diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-06-04 15:13:43 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-06-04 15:13:43 +0300 |
| commit | 3dbd8c34176312b0bd3aba2309d284ac83181411 (patch) | |
| tree | 9bf6216f2c120a388308457444738d0c55002bd2 /common/debug.c | |
| parent | 52e5c94314fa8e10efded82db85d181ed32f00bd (diff) | |
| download | kmi-3dbd8c34176312b0bd3aba2309d284ac83181411.tar.gz kmi-3dbd8c34176312b0bd3aba2309d284ac83181411.zip | |
visionfive2 boots
+ Make 8250 serial driver more generic
+ Still TODO: write a tutorial on how to boot on the visionfive2
Diffstat (limited to 'common/debug.c')
| -rw-r--r-- | common/debug.c | 133 |
1 files changed, 65 insertions, 68 deletions
diff --git a/common/debug.c b/common/debug.c index 346934a..f3cacdf 100644 --- a/common/debug.c +++ b/common/debug.c @@ -20,18 +20,21 @@ /** Debug context structure. */ struct dbg_info { - /** Address of serial device in memory. */ - pm_t dbg_ptr; - + /** Address of serial device in virtual memory. Always access registers + * through this address rather than \p addr. */ + pm_t base; + /** Shift count between registers of serial device. */ + size_t shift; /** Type of serial device. */ enum serial_dev dev; + /** Physical address of serial device. */ + pm_t addr; }; /** Static debugging information. */ static struct dbg_info dbg_info = (struct dbg_info){ 0 }; /* forward declarations. */ -static void __setup_dbg(pm_t pt, enum serial_dev dev); static struct dbg_info __dbg_from_fdt(const void *fdt); void init_dbg(const void *fdt) @@ -41,51 +44,41 @@ void init_dbg(const void *fdt) void setup_dmap_dbg() { - __setup_dbg(dbg_info.dbg_ptr, dbg_info.dev); + /* noop with the new 8250 driver, though might still be useful in the + * future if I add in some other kind of simple uart */ } void setup_io_dbg(struct vmem *b) { - vm_t io_ptr = map_io_dbg(b); - __setup_dbg(io_ptr, dbg_info.dev); + dbg_info.base = map_io_dbg(b); } vm_t map_io_dbg(struct vmem *b) { - return setup_kernel_io(b, dbg_info.dbg_ptr); + return setup_kernel_io(b, dbg_info.addr); } +/** 8250 data register index. */ +#define UART_8250_DATA 0 +/** 8250 irq register idex. */ +#define UART_8250_IRQ 1 +/** 8250 ird_id register index. */ +#define UART_8250_IRQ_ID 2 +/** 8250 lcr register index. */ +#define UART_8250_LCR 3 +/** 8250 mcr register index. */ +#define UART_8250_MCR 4 +/** 8250 lsr register index. */ +#define UART_8250_LSR 5 +/** 8250 msr register index. */ +#define UART_8250_MSR 6 +/** 8250 scr register index. */ +#define UART_8250_SCR 7 + /* if there arises a need for more supported serial drivers, I should probably * try to implement some kind of basic driver subsystem, but this is good enough * for now. */ -/** 8250 and compatible serial drivers. */ -struct __packed uart_8250 { - /** Receiver buffer/transmitter holding register. */ - uint8_t data; - - /** Interrupt enable register. */ - uint8_t irq; - - /** Interrupt identity/FIFO control register. */ - uint8_t irq_id; - - /** Line control register. */ - uint8_t lcr; - - /** Modem control register. */ - uint8_t mcr; - - /** Line status register. */ - uint8_t lsr; - - /** Modem status register. */ - uint8_t msr; - - /** Scratch register. */ - uint8_t scr; -}; - /** Line status data ready. */ #define LSR_DR (1 << 0) @@ -111,17 +104,11 @@ struct __packed uart_8250 { #define LSR_ERR (1 << 7) /** - * Address of generic 8250 port. If other serial drivers are added, this should - * maybe be made a void *. No support for quirks at the moment. - */ -static struct uart_8250 *port = 0; - -/** - * Serial transmitter empty. + * 8250 transmitter empty. * * @return \c 0 if not empty, non-zero otherwise. */ -static int __serial_tx_empty() +static int __8250_tx_empty() { /** * @todo visionfive2 loops on lsr indefinitely, why? @@ -129,23 +116,43 @@ static int __serial_tx_empty() * meaning the registers are spaced apart more in memory than my naive * struct. * */ - return port->lsr & LSR_THRE; + volatile uint8_t *lsr = (uint8_t *)dbg_info.base + + (UART_8250_LSR << dbg_info.shift); + return (*lsr) & LSR_THRE; } /** - * Put character out onto serial lines. + * Put character out onto 8250 serial lines. * * @param c Character to output. */ -static void __putchar(char c) +static void __8250_putchar(char c) { - if (!port) + if (!dbg_info.base) return; - while (__serial_tx_empty() == 0) + while (__8250_tx_empty() == 0) ; - port->data = c; + volatile uint8_t *data = (uint8_t *)dbg_info.base + + (UART_8250_DATA << dbg_info.shift); + *data = c; +} + +/** + * Put one character out on the serial lines. + * Automatically handles newlines. + * + * @param c Character to put. + */ +static void __putchar(char c) +{ + if (c == '\n') + __putchar('\r'); + + switch (dbg_info.dev) { + case UART_8250: __8250_putchar(c); return; + } } /** @@ -200,28 +207,18 @@ static struct dbg_info __dbg_from_fdt(const void *fdt) /* get serial device address */ struct cell_info ci = get_reginfo(fdt, stdout); void *reg_ptr = (void *)fdt_getprop(fdt, stdout_offset, "reg", NULL); - pm_t dbg_ptr = (pm_t)fdt_load_int_ptr(ci.addr_cells, reg_ptr); - return (struct dbg_info){ dbg_ptr, dev }; -} - -/** - * Set static port. - * - * @param pt Address of memory mapped serial device. - * @param dev Chosen device. - */ -void __setup_dbg(vm_t pt, enum serial_dev dev) -{ - switch (dev) { - case UART_8250: - port = (struct uart_8250 *)pt; - break; - } + /* get serial device offset if present */ + size_t shift = 0; + void *shift_ptr = (void *)fdt_getprop(fdt, stdout_offset, "reg-shift", + NULL); + if (shift_ptr) + shift = (size_t)fdt_load_int32_ptr(shift_ptr); - /* in the future possibly configure the serial connection, though the - * defaults (set by U-boot) seem to work alright */ + /* while in direct map, base == addr, and this changes only when we jump + * into virtually mapped io */ + return (struct dbg_info){ dbg_ptr, shift, dev, dbg_ptr }; } /** Printf formatting left align flag. */ |
