Index: sys/dev/uart/uart_dev_mu.c =================================================================== --- sys/dev/uart/uart_dev_mu.c +++ sys/dev/uart/uart_dev_mu.c @@ -140,6 +140,7 @@ static void uart_mu_putc(struct uart_bas *bas, int); static int uart_mu_rxready(struct uart_bas *bas); static int uart_mu_getc(struct uart_bas *bas, struct mtx *); +static int cpu_clock(void); static struct uart_ops uart_mu_ops = { .probe = uart_mu_probe, @@ -157,12 +158,6 @@ return (0); } -/* - * According to the docs, the cpu clock is locked to 250Mhz when - * the micro-uart is used - */ -#define CPU_CLOCK 250000000 - static void uart_mu_param(struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) @@ -188,15 +183,11 @@ line |= LCR_WLEN8; break; } - __uart_setreg(bas, AUX_MU_LCR_REG, line); /* See 2.2.1 BCM2835-ARM-Peripherals baudrate */ if (baudrate != 0) { - baud = CPU_CLOCK / (8 * baudrate); - /* XXX - * baud = cpu_clock() / (8 * baudrate); - */ + baud = cpu_clock() / (8 * baudrate); __uart_setreg(bas, AUX_MU_BAUD_REG, ((uint32_t)(baud & 0xFFFF))); } @@ -252,7 +243,7 @@ */ struct uart_mu_softc { struct uart_softc bas; - uint16_t aux_ier; /* Interrupt mask */ + uint16_t aux_ier; /* Interrupt mask */ }; static int uart_mu_bus_attach(struct uart_softc *); @@ -518,4 +509,40 @@ __uart_setreg(bas, AUX_MU_CNTL_REG, CNTL_RXENAB|CNTL_TXENAB); __uart_setreg(bas, AUX_MU_IER_REG, psc->aux_ier); uart_unlock(sc->sc_hwmtx); +} + +/* + * From www.raspberrypi.org/documentation/configuration/uart.md + * + * "The baud rate of the mini UART is linked to the core frequency of + * the VPU on the VC4 GPU. This means that, as the VPU frequency governor + * varies the core frequency, the baud rate of the mini UART also changes" + * + * Since this is rather unusable for a uart the core frequency is locked + * if this uart is enabled in the config. Unfortantely it is locked + * to 250Mhz on Rpi2 and Rpi3 but 500Mhz on Rpi4 so this driver needs + * to determine which is needed. This is one approach, another approach + * might be to query bcm2835_cpufreq.c directly. + */ + +#define RPI2_AND_3_CORE_CLOCK 250000000 +#define RPI4_CORE_CLOCK 500000000 + +static int +cpu_clock(void) +{ + char compat[255]; + ssize_t compatlen; + char *curstr; + phandle_t root; + + root = OF_peer(0); + if (root == 0) + return (RPI2_AND_3_CORE_CLOCK); + compatlen = OF_getprop(root, "compatible", compat, sizeof(compat)); + for (curstr = compat; curstr < compat + compatlen; curstr++) { + if (strncmp(curstr, "4-model", 7) == 0) + return (RPI4_CORE_CLOCK); + } + return (RPI2_AND_3_CORE_CLOCK); }