aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Kimmitt <jonathan@kimmitt.uk>2019-11-06 17:43:09 +0000
committerAndrew Waterman <andrew@sifive.com>2019-11-06 09:43:09 -0800
commit14e87d2dd250b0efb5e9fb19ab279ccf1ccbdbd7 (patch)
tree981f33c25b55b354fdfe01f9977951e9fd0faee4
parentb1bdf5bb995ada25f4855279e90ac2c54c7162fa (diff)
downloadriscv-pk-14e87d2dd250b0efb5e9fb19ab279ccf1ccbdbd7.zip
riscv-pk-14e87d2dd250b0efb5e9fb19ab279ccf1ccbdbd7.tar.gz
riscv-pk-14e87d2dd250b0efb5e9fb19ab279ccf1ccbdbd7.tar.bz2
Support a subset of 16750 functionality, and improve baud rate selection (#182)
-rw-r--r--machine/uart16550.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/machine/uart16550.c b/machine/uart16550.c
index 44685eb..f4fbbee 100644
--- a/machine/uart16550.c
+++ b/machine/uart16550.c
@@ -25,7 +25,10 @@ static uint32_t uart16550_clock = 1843200; // a "common" base clock
#define UART_REG_STATUS_RX 0x01
#define UART_REG_STATUS_TX 0x20
+// We cannot use the word DEFAULT for a parameter that cannot be overridden due to -Werror
+#ifndef UART_DEFAULT_BAUD
#define UART_DEFAULT_BAUD 38400
+#endif
void uart16550_putchar(uint8_t ch)
{
@@ -47,18 +50,21 @@ struct uart16550_scan
uint32_t reg_offset;
uint32_t reg_shift;
uint32_t clock_freq;
+ uint32_t baud;
};
static void uart16550_open(const struct fdt_scan_node *node, void *extra)
{
struct uart16550_scan *scan = (struct uart16550_scan *)extra;
memset(scan, 0, sizeof(*scan));
+ scan->baud = UART_DEFAULT_BAUD;
}
static void uart16550_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct uart16550_scan *scan = (struct uart16550_scan *)extra;
- if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, "ns16550a") != -1) {
+ // For the purposes of the boot loader, the 16750 is a superset of what 16550a provides
+ if (!strcmp(prop->name, "compatible") && ((fdt_string_list_index(prop, "ns16550a") != -1) || (fdt_string_list_index(prop, "ns16750") != -1))) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
@@ -66,6 +72,9 @@ static void uart16550_prop(const struct fdt_scan_prop *prop, void *extra)
scan->reg_shift = fdt_get_value(prop, 0);
} else if (!strcmp(prop->name, "reg-offset")) {
scan->reg_offset = fdt_get_value(prop, 0);
+ } else if (!strcmp(prop->name, "current-speed")) {
+ // This is the property that Linux uses
+ scan->baud = fdt_get_value(prop, 0);
} else if (!strcmp(prop->name, "clock-frequency")) {
scan->clock_freq = fdt_get_value(prop, 0);
}
@@ -81,8 +90,11 @@ static void uart16550_done(const struct fdt_scan_node *node, void *extra)
uart16550_clock = scan->clock_freq;
// if device tree doesn't supply a clock, fallback to default clock of 1843200
- uint32_t divisor = uart16550_clock / (16 * UART_DEFAULT_BAUD);
- assert (divisor < 0x10000u);
+ // Check for divide by zero
+ uint32_t divisor = uart16550_clock / (16 * (scan->baud ? scan->baud : UART_DEFAULT_BAUD));
+ // If the divisor is out of range, don't assert, set the rate back to the default
+ if (divisor >= 0x10000u)
+ divisor = uart16550_clock / (16 * UART_DEFAULT_BAUD);
uart16550 = (void*)((uintptr_t)scan->reg + scan->reg_offset);
uart16550_reg_shift = scan->reg_shift;