From d8062e950367fab0f219a889e8f2fbfade90108c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 May 2023 16:54:56 -0600 Subject: input: Flush the keyboard buffer before resetting it If U-Boot is not the first-stage bootloader the keyboard may already be set up. Make sure to flush any data before trying to reset it. This avoids a long timeout / hang. Add some comments and a log category while we are here. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/input/i8042.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/input/i8042.c b/drivers/input/i8042.c index 3563dc98838..e6070ca0152 100644 --- a/drivers/input/i8042.c +++ b/drivers/input/i8042.c @@ -6,6 +6,8 @@ /* i8042.c - Intel 8042 keyboard driver routines */ +#define LOG_CATEGORY UCLASS_KEYBOARD + #include #include #include @@ -54,6 +56,14 @@ static unsigned char ext_key_map[] = { 0x00 /* map end */ }; +/** + * kbd_input_empty() - Wait until the keyboard is ready for a command + * + * Checks the IBF flag (input buffer full), waiting for it to indicate that + * any previous command has been processed. + * + * Return: true if ready, false if it timed out + */ static int kbd_input_empty(void) { int kbd_timeout = KBD_TIMEOUT * 1000; @@ -64,6 +74,12 @@ static int kbd_input_empty(void) return kbd_timeout != -1; } +/** + * kbd_output_full() - Wait until the keyboard has data available + * + * Checks the OBF flag (output buffer full), waiting for it to indicate that + * a response to a previous command is available + */ static int kbd_output_full(void) { int kbd_timeout = KBD_TIMEOUT * 1000; @@ -127,6 +143,9 @@ static int kbd_reset(int quirk) { int config; + if (!kbd_input_empty()) + goto err; + /* controller self test */ if (kbd_cmd_read(CMD_SELF_TEST) != KBC_TEST_OK) goto err; -- cgit v1.2.3 From 0992a90daa80a17f9e7e33a56fd3f9660ee84c97 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 May 2023 16:54:57 -0600 Subject: acpi: Create a new Kconfig for ACPI We have several Kconfig options for ACPI, but all relate to specific functions, such as generating tables and AML code. Add a new option which controls including basic ACPI library code, including the lib/acpi directory. This will allow us to add functions which are available even if table generation is not supported. Adjust the command to avoid a build error when ACPIGEN is not enabled. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/core/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 0f755aa702e..f0d848f45d8 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -448,6 +448,7 @@ config OFNODE_MULTI_TREE_MAX config ACPIGEN bool "Support ACPI table generation in driver model" + depends on ACPI default y if SANDBOX || (GENERATE_ACPI_TABLE && !QEMU) select LIB_UUID help -- cgit v1.2.3 From b29dbf98baa35441ad01957bb2317cb4f70f390f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 May 2023 16:55:00 -0600 Subject: x86: Allow locating the UART from ACPI tables When coreboot does not pass a UART in its sysinfo struct, there is no easy way to find it out. Since coreboot does not actually init the serial device when serial is disabled, it is not possible to make it add this information to the sysinfo table. Add a way to obtain this information from the DBG2 ACPI table, which is normally set up by coreboot. For now this only supports a memory-mapped 16550-style UART. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/serial/Kconfig | 10 ++++ drivers/serial/serial_coreboot.c | 114 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 116 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 7faf6784442..f4767c838f9 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -669,6 +669,16 @@ config COREBOOT_SERIAL a serial console on any platform without needing to change the device tree, etc. +config COREBOOT_SERIAL_FROM_DBG2 + bool "Obtain UART from ACPI tables" + depends on COREBOOT_SERIAL + default y if !SPL + help + Select this to try to find a DBG2 record in the ACPI tables, in the + event that coreboot does not provide information about the UART in the + normal sysinfo tables. This provides a useful fallback when serial + is not enabled in coreboot. + config CORTINA_UART bool "Cortina UART support" depends on DM_SERIAL diff --git a/drivers/serial/serial_coreboot.c b/drivers/serial/serial_coreboot.c index de09c8681f5..23066e4d054 100644 --- a/drivers/serial/serial_coreboot.c +++ b/drivers/serial/serial_coreboot.c @@ -5,25 +5,123 @@ * Copyright 2019 Google LLC */ +#define LOG_CATGEGORY UCLASS_SERIAL + #include #include +#include #include #include +#include #include +DECLARE_GLOBAL_DATA_PTR; + +static int read_dbg2(struct ns16550_plat *plat) +{ + struct acpi_table_header *tab; + struct acpi_dbg2_header *hdr; + struct acpi_dbg2_device *dbg; + struct acpi_gen_regaddr *addr; + u32 *addr_size; + + log_debug("Looking for DBG2 in ACPI tables\n"); + if (!gd->acpi_start) { + log_debug("No ACPI tables\n"); + return -ENOENT; + } + + tab = acpi_find_table("DBG2"); + if (!tab) { + log_debug("No DBG2 table\n"); + return -ENOENT; + } + hdr = container_of(tab, struct acpi_dbg2_header, header); + + /* We only use the first device, but check that there is at least one */ + if (!hdr->devices_count) { + log_debug("No devices\n"); + return -ENOENT; + } + if (hdr->devices_offset >= tab->length) { + log_debug("Invalid offset\n"); + return -EINVAL; + } + dbg = (void *)hdr + hdr->devices_offset; + if (dbg->revision) { + log_debug("Invalid revision %d\n", dbg->revision); + return -EINVAL; + } + if (!dbg->address_count) { + log_debug("No addresses\n"); + return -EINVAL; + } + if (dbg->port_type != ACPI_DBG2_SERIAL_PORT) { + log_debug("Not a serial port\n"); + return -EPROTOTYPE; + } + if (dbg->port_subtype != ACPI_DBG2_16550_COMPATIBLE) { + log_debug("Incompatible serial port\n"); + return -EPROTOTYPE; + } + if (dbg->base_address_offset >= dbg->length || + dbg->address_size_offset >= dbg->length) { + log_debug("Invalid base address/size offsets %d, %d\n", + dbg->base_address_offset, dbg->address_size_offset); + return -EINVAL; + } + addr_size = (void *)dbg + dbg->address_size_offset; + if (!*addr_size) { + log_debug("Zero address size\n"); + return -EINVAL; + } + addr = (void *)dbg + dbg->base_address_offset; + if (addr->space_id != ACPI_ADDRESS_SPACE_MEMORY) { + log_debug("Incompatible space %d\n", addr->space_id); + return -EPROTOTYPE; + } + + plat->base = addr->addrl; + + /* ACPI_ACCESS_SIZE_DWORD_ACCESS is 3; we want 2 */ + plat->reg_shift = addr->access_size - 1; + plat->reg_width = 4; /* coreboot sets bit_width to 0 */ + plat->clock = 1843200; + plat->fcr = UART_FCR_DEFVAL; + plat->flags = 0; + log_debug("Collected UART from ACPI DBG2 table\n"); + + return 0; +} + static int coreboot_of_to_plat(struct udevice *dev) { struct ns16550_plat *plat = dev_get_plat(dev); struct cb_serial *cb_info = lib_sysinfo.serial; + int ret = -ENOENT; - plat->base = cb_info->baseaddr; - plat->reg_shift = cb_info->regwidth == 4 ? 2 : 0; - plat->reg_width = cb_info->regwidth; - plat->clock = cb_info->input_hertz; - plat->fcr = UART_FCR_DEFVAL; - plat->flags = 0; - if (cb_info->type == CB_SERIAL_TYPE_IO_MAPPED) - plat->flags |= NS16550_FLAG_IO; + if (cb_info) { + plat->base = cb_info->baseaddr; + plat->reg_shift = cb_info->regwidth == 4 ? 2 : 0; + plat->reg_width = cb_info->regwidth; + plat->clock = cb_info->input_hertz; + plat->fcr = UART_FCR_DEFVAL; + plat->flags = 0; + if (cb_info->type == CB_SERIAL_TYPE_IO_MAPPED) + plat->flags |= NS16550_FLAG_IO; + ret = 0; + } else if (IS_ENABLED(CONFIG_COREBOOT_SERIAL_FROM_DBG2)) { + ret = read_dbg2(plat); + } + + if (ret) { + /* + * Returning an error will cause U-Boot to complain that + * there is no UART, which may panic. So stay silent and + * pray that the video console will work. + */ + log_debug("Cannot detect UART\n"); + } return 0; } -- cgit v1.2.3 From dd0f7bcf3b29a0b6095622b7dd83279b0a3dbfe4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 May 2023 16:55:01 -0600 Subject: pci: coreboot: Don't read regions when booting When U-Boot is the second-stage bootloader, PCI is already set up. We cannot read the regions from the device tree. There is no point anyway, since PCI devices have already been allocated according to the regions and it is not safe for U-Boot to make any changes. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Fixes: f2ebaaa9f38d ("pci: Handle failed calloc in decode_regions()") Tested-by: Christian Gmeiner Tested-by: Bin Meng --- drivers/pci/pci-uclass.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 9343cfc62a9..8d27e40338c 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -973,6 +973,10 @@ static int decode_regions(struct pci_controller *hose, ofnode parent_node, int len; int i; + /* handle booting from coreboot, etc. */ + if (!ll_boot_init()) + return 0; + prop = ofnode_get_property(node, "ranges", &len); if (!prop) { debug("%s: Cannot decode regions\n", __func__); -- cgit v1.2.3 From 38534712cd4c4d8acdf760ee87ba219f82d738c9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 May 2023 16:55:07 -0600 Subject: nvme: Enable PCI bus mastering U-Boot sets up devices ready for use, but coreboot does not. Enable this so that NVMe works OK from coreboot. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/nvme/nvme_pci.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/nvme/nvme_pci.c b/drivers/nvme/nvme_pci.c index 36bf9c5ffb7..5bb43d299fc 100644 --- a/drivers/nvme/nvme_pci.c +++ b/drivers/nvme/nvme_pci.c @@ -6,6 +6,7 @@ #include #include +#include #include #include "nvme.h" @@ -30,6 +31,10 @@ static int nvme_probe(struct udevice *udev) ndev->instance = trailing_strtol(udev->name); ndev->bar = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, PCI_REGION_MEM); + + /* Turn on bus-mastering */ + dm_pci_clrset_config16(udev, PCI_COMMAND, 0, PCI_COMMAND_MASTER); + return nvme_init(udev); } -- cgit v1.2.3 From 55171aedda88d12666e2a1bbc661dea1bec65337 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 May 2023 16:50:45 -0600 Subject: dm: Emit the arch_cpu_init_dm() even only before relocation The original function was only called once, before relocation. The new one is called again after relocation. This was not the intent of the original call. Fix this by renaming and updating the calling logic. With this, chromebook_link64 makes it through SPL. Fixes: 7fe32b3442f0 ("event: Convert arch_cpu_init_dm() to use events") Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/core/root.c | 4 ++-- drivers/cpu/microblaze_cpu.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/core/root.c b/drivers/core/root.c index c4fb48548bb..6775fb0b657 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -436,8 +436,8 @@ int dm_init_and_scan(bool pre_reloc_only) return ret; } } - if (CONFIG_IS_ENABLED(DM_EVENT)) { - ret = event_notify_null(EVT_DM_POST_INIT); + if (CONFIG_IS_ENABLED(DM_EVENT) && !(gd->flags & GD_FLG_RELOC)) { + ret = event_notify_null(EVT_DM_POST_INIT_F); if (ret) return log_msg_ret("ev", ret); } diff --git a/drivers/cpu/microblaze_cpu.c b/drivers/cpu/microblaze_cpu.c index b9d07928223..c97a89fbd5c 100644 --- a/drivers/cpu/microblaze_cpu.c +++ b/drivers/cpu/microblaze_cpu.c @@ -29,7 +29,7 @@ static int microblaze_cpu_probe_all(void *ctx, struct event *event) return 0; } -EVENT_SPY(EVT_DM_POST_INIT, microblaze_cpu_probe_all); +EVENT_SPY(EVT_DM_POST_INIT_F, microblaze_cpu_probe_all); static void microblaze_set_cpuinfo_pvr(struct microblaze_cpuinfo *ci) { -- cgit v1.2.3 From 28afcb1e7f7d1b899514cbdb58fb658ee0b5c5a3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 May 2023 16:50:47 -0600 Subject: sf: Guard against zero erasesize With tiny SPI flash the erasesize is 0 which can cause a divide-by-zero error. Check for this and return a proper error instead. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/mtd/spi/sf_probe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index e192f97efdc..de6516f1065 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -189,7 +189,8 @@ static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) struct mtd_info *mtd = &flash->mtd; struct erase_info instr; - if (offset % mtd->erasesize || len % mtd->erasesize) { + if (!mtd->erasesize || + (offset % mtd->erasesize || len % mtd->erasesize)) { debug("SF: Erase offset/length not multiple of erase size\n"); return -EINVAL; } -- cgit v1.2.3 From dafbfe83e04c17d304129b709ec6305acd616aac Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 May 2023 16:50:48 -0600 Subject: sf: Rename spi-nor-tiny functions The 'tiny' SPI nor functions have the same name as their big brothers, which can be confusing. Use different names so it is clear which version is in the image. Signed-off-by: Simon Glass Acked-by: Vignesh Raghavendra Reviewed-by: Bin Meng --- drivers/mtd/spi/spi-nor-tiny.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index 68152ce3b4b..7aa24e129f9 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -361,7 +361,7 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor) * Erase an address range on the nor chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. */ -static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) +static int spi_nor_erase_tiny(struct mtd_info *mtd, struct erase_info *instr) { return -ENOTSUPP; } @@ -390,8 +390,8 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) return ERR_PTR(-EMEDIUMTYPE); } -static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static int spi_nor_read_tiny(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) { struct spi_nor *nor = mtd_to_spi_nor(mtd); int ret; @@ -426,8 +426,8 @@ read_err: * FLASH_PAGESIZE chunks. The address range may be any size provided * it is within the physical boundaries. */ -static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static int spi_nor_write_tiny(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { return -ENOTSUPP; } @@ -741,9 +741,9 @@ int spi_nor_scan(struct spi_nor *nor) mtd->writesize = 1; mtd->flags = MTD_CAP_NORFLASH; mtd->size = info->sector_size * info->n_sectors; - mtd->_erase = spi_nor_erase; - mtd->_read = spi_nor_read; - mtd->_write = spi_nor_write; + mtd->_erase = spi_nor_erase_tiny; + mtd->_read = spi_nor_read_tiny; + mtd->_write = spi_nor_write_tiny; nor->size = mtd->size; -- cgit v1.2.3 From 6624392d3bb633fe91b7cc4b75b6eec28f637f72 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 9 May 2023 18:13:47 +0800 Subject: x86: sysreset: Set up LPC only after relocation Probing LPC can cause PCI enumeration to take place, which significantly increases pre-relocation memory usage. Also, LPC is somtimes enabled directly by SPL. Adjust the logic to probe the LPC only after relocation. This allows chromebook_link64 to start up without a much larger CONFIG_SYS_MALLOC_F_LEN value. Signed-off-by: Simon Glass Signed-off-by: Bin Meng Reviewed-by: Bin Meng --- drivers/sysreset/sysreset_x86.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/sysreset/sysreset_x86.c b/drivers/sysreset/sysreset_x86.c index 8042f3994fe..4936fdb76c7 100644 --- a/drivers/sysreset/sysreset_x86.c +++ b/drivers/sysreset/sysreset_x86.c @@ -129,8 +129,13 @@ static int x86_sysreset_probe(struct udevice *dev) { struct x86_sysreset_plat *plat = dev_get_plat(dev); - /* Locate the PCH if there is one. It isn't essential */ - uclass_first_device(UCLASS_PCH, &plat->pch); + /* + * Locate the PCH if there is one. It isn't essential. Avoid this before + * relocation as we shouldn't need reset then and it needs a lot of + * memory for PCI enumeration. + */ + if (gd->flags & GD_FLG_RELOC) + uclass_first_device(UCLASS_PCH, &plat->pch); return 0; } -- cgit v1.2.3