Browse Source

Support a subset of 16750 functionality, and improve baud rate selection

pull/182/head
Jonathan Richard Robert Kimmitt 7 years ago
parent
commit
4f7e99bb70
  1. 18
      machine/uart16550.c

18
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;

Loading…
Cancel
Save