Index: sys/dev/ofw/ofw_fdt.c =================================================================== --- sys/dev/ofw/ofw_fdt.c +++ sys/dev/ofw/ofw_fdt.c @@ -79,6 +79,8 @@ 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_interpret(ofw_t, const char *, int, cell_t *); +static int ofw_fdt_model(ofw_t, char *, size_t); +static int ofw_fdt_compatible(ofw_t, char *, size_t); static ofw_method_t ofw_fdt_methods[] = { OFWMETHOD(ofw_init, ofw_fdt_init), @@ -95,6 +97,8 @@ 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), + OFWMETHOD(ofw_compatible, ofw_fdt_compatible), { 0, 0 } }; @@ -105,6 +109,11 @@ }; OFW_DEF(ofw_fdt); +#define FDT_MODEL_LEN 80 +static char model[FDT_MODEL_LEN]; +#define FDT_COMPAT_LEN 80 +static char compatible[FDT_COMPAT_LEN]; + static void *fdtp = NULL; static int @@ -125,6 +134,15 @@ SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_fdt), OID_AUTO, "dtb", CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, sysctl_handle_dtb, "", "Device Tree Blob"); + + if (*model != '\0') + SYSCTL_ADD_STRING(NULL, SYSCTL_STATIC_CHILDREN(_hw_fdt), + OID_AUTO, "model", CTLFLAG_RD, + model, FDT_MODEL_LEN, "Model as given by manufacturer"); + if (*compatible != '\0') + SYSCTL_ADD_STRING(NULL, SYSCTL_STATIC_CHILDREN(_hw_fdt), + OID_AUTO, "compatible", CTLFLAG_RD, + compatible, FDT_COMPAT_LEN, "Compatibility string as given by manufacturer"); } SYSINIT(dtb_oid, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_fdt_oid, NULL); @@ -132,12 +150,27 @@ ofw_fdt_init(ofw_t ofw, void *data) { int err; + phandle_t root; /* Check FDT blob integrity */ if ((err = fdt_check_header(data)) != 0) return (err); fdtp = data; + + bzero(model, FDT_MODEL_LEN); + if ((root = ofw_fdt_finddevice(NULL, "/")) != -1) { + if (ofw_fdt_getproplen(NULL, root, "model") > 0) + ofw_fdt_getprop(NULL, root, "model", model, + FDT_MODEL_LEN); + } + + bzero(compatible, FDT_COMPAT_LEN); + if ((root = ofw_fdt_finddevice(NULL, "/")) != -1) { + if (ofw_fdt_getproplen(NULL, root, "compatible") > 0) + ofw_fdt_getprop(NULL, root, "compatible", compatible, + FDT_COMPAT_LEN); + } return (0); } @@ -274,7 +307,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 +328,6 @@ if (prop == NULL) return (-1); - bcopy(prop, buf, min(len, buflen)); return (len); @@ -407,25 +438,35 @@ return (-1); } +/* Find the model string from the fdt */ +static int +ofw_fdt_model(ofw_t ofw, char *buf, size_t buflen) +{ + + if (buf != NULL) + strlcpy (buf, model, buflen); + return (0); +} + +/* Find the compatible string from the fdt */ +static int +ofw_fdt_compatible(ofw_t ofw, char *buf, size_t buflen) +{ + + if (buf != NULL) + strlcpy(buf, compatible, buflen); + return (0); +} + #if defined(FDT_MARVELL) static int ofw_fdt_fixup(ofw_t ofw) { -#define FDT_MODEL_LEN 80 - char model[FDT_MODEL_LEN]; phandle_t root; - ssize_t len; int i; - if ((root = ofw_fdt_finddevice(ofw, "/")) == -1) - return (ENODEV); - - 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); + 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,30 @@ 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; +}; + +/** + * @brief return compatible string + * + * @param _compatible Buffer for compatible + * @param _size Size of buffer + */ +METHOD int compatible { + ofw_t _ofw; + char *_compatible; + 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,8 @@ /* User interface functions */ int OF_interpret(const char *cmd, int nreturns, ...); +int OF_model(char *buf, size_t len); +int OF_compatible(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 @@ -846,3 +846,26 @@ for (;;) /* just in case */ ; } + +/* 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)); +} + +/* Return compatible from fdt. */ +int +OF_compatible(char *buf, size_t len) +{ + + if (ofw_def_impl == NULL) + return (0); + + return(OFW_COMPATIBLE(ofw_obj, buf, len)); +} + 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,30 @@ __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); }