Index: sys/dev/ofw/ofw_fdt.c =================================================================== --- sys/dev/ofw/ofw_fdt.c +++ sys/dev/ofw/ofw_fdt.c @@ -78,6 +78,8 @@ static phandle_t ofw_fdt_finddevice(ofw_t, const char *); static ssize_t ofw_fdt_instance_to_path(ofw_t, ihandle_t, char *, size_t); static ssize_t ofw_fdt_package_to_path(ofw_t, phandle_t, char *, size_t); +static int ofw_fdt_model(ofw_t, char *, size_t); +static phandle_t ofw_fdt_find_model(ofw_t ofw, phandle_t); static int ofw_fdt_interpret(ofw_t, const char *, int, cell_t *); static ofw_method_t ofw_fdt_methods[] = { @@ -95,6 +97,7 @@ OFWMETHOD(ofw_instance_to_path, ofw_fdt_instance_to_path), OFWMETHOD(ofw_package_to_path, ofw_fdt_package_to_path), OFWMETHOD(ofw_interpret, ofw_fdt_interpret), + OFWMETHOD(ofw_model, ofw_fdt_model), { 0, 0 } }; @@ -105,6 +108,9 @@ }; OFW_DEF(ofw_fdt); +#define FDT_MODEL_LEN 80 +static char model[FDT_MODEL_LEN]; + static void *fdtp = NULL; static int @@ -128,6 +134,16 @@ } SYSINIT(dtb_oid, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_fdt_oid, NULL); +static void +sysctl_register_model_oid(void *arg) +{ + /* XXX hw.model is already taken */ + SYSCTL_ADD_STRING(NULL, SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "manufacturer", + CTLFLAG_RD | CTLFLAG_MPSAFE, model, + 0, "Model as given by manufacturer"); +} +SYSINIT(model_oid, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_model_oid, NULL); + static int ofw_fdt_init(ofw_t ofw, void *data) { @@ -274,7 +290,6 @@ return (-1); prop = fdt_getprop(fdtp, offset, propname, &len); - if (prop == NULL && strcmp(propname, "name") == 0) { /* Emulate the 'name' property */ name = fdt_get_name(fdtp, offset, &len); @@ -296,7 +311,6 @@ if (prop == NULL) return (-1); - bcopy(prop, buf, min(len, buflen)); return (len); @@ -407,25 +421,44 @@ return (-1); } -#if defined(FDT_MARVELL) +/* Return the fdt model name. */ static int -ofw_fdt_fixup(ofw_t ofw) +ofw_fdt_model(ofw_t ofw, char *buf, size_t len) { -#define FDT_MODEL_LEN 80 - char model[FDT_MODEL_LEN]; - phandle_t root; + + ofw_fdt_find_model(ofw, 0); + strncpy (buf, model, len); + return (-1); +} + +/* Find the model string from the fdt */ +static phandle_t +ofw_fdt_find_model(ofw_t ofw, phandle_t root) +{ ssize_t len; - int i; + bzero(model, FDT_MODEL_LEN); if ((root = ofw_fdt_finddevice(ofw, "/")) == -1) - return (ENODEV); - + return (-1); if ((len = ofw_fdt_getproplen(ofw, root, "model")) <= 0) return (0); - - bzero(model, FDT_MODEL_LEN); if (ofw_fdt_getprop(ofw, root, "model", model, FDT_MODEL_LEN) <= 0) return (0); + return (root); +} + +#if defined(FDT_MARVELL) +static int +ofw_fdt_fixup(ofw_t ofw) +{ + phandle_t root; + int i; + + root = ofw_fdt_find_model(ofw_t ofw, root); + if (root < 0) + return (ENODEV); + if (*model == '\0') + return (ENOENT); /* * Search fixup table and call handler if appropriate. Index: sys/dev/ofw/ofw_if.m =================================================================== --- sys/dev/ofw/ofw_if.m +++ sys/dev/ofw/ofw_if.m @@ -247,6 +247,18 @@ cell_t *_returns; }; +/** + * @brief return model name + * + * @param _model Buffer for model + * @param _size Size of buffer + */ +METHOD int model { + ofw_t _ofw; + char *_model; + size_t _size; +}; + # Device I/O Functions (optional) /** Index: sys/dev/ofw/openfirm.h =================================================================== --- sys/dev/ofw/openfirm.h +++ sys/dev/ofw/openfirm.h @@ -174,6 +174,7 @@ /* User interface functions */ int OF_interpret(const char *cmd, int nreturns, ...); +int OF_model(char *buf, size_t len); /* * Decode the Nth register property of the given device node and create a bus Index: sys/dev/ofw/openfirm.c =================================================================== --- sys/dev/ofw/openfirm.c +++ sys/dev/ofw/openfirm.c @@ -292,6 +292,17 @@ return (OFW_TEST(ofw_obj, name)); } +/* Return model from fdt. */ +int +OF_model(char *buf, size_t len) +{ + + if (ofw_def_impl == NULL) + return (0); + + return(OFW_MODEL(ofw_obj, buf, len)); +} + int OF_interpret(const char *cmd, int nreturns, ...) { Index: sys/dev/uart/uart_dev_mu.c =================================================================== --- sys/dev/uart/uart_dev_mu.c +++ sys/dev/uart/uart_dev_mu.c @@ -140,7 +140,11 @@ 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); +#define RPI2_AND_3_CORE_CLOCK 250000000 +#define RPI4_CORE_CLOCK 500000000 + static struct uart_ops uart_mu_ops = { .probe = uart_mu_probe, .init = uart_mu_init, @@ -157,12 +161,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) @@ -193,10 +191,7 @@ /* 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))); } @@ -518,4 +513,31 @@ __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. + */ + + +static int +cpu_clock(void) +{ + char model[40]; + + OF_model(model, sizeof(model)); + + if (strncmp(model, "Raspberry Pi 4", 14) == 0) + return (RPI4_CORE_CLOCK); + return (RPI2_AND_3_CORE_CLOCK); }