From 67ae5d3d46ae87857216dfdee6180e5d7c2ddd27 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 15 Mar 2022 21:03:20 -0600 Subject: dm: Add docs to explain how to enable DM_SERIAL for a board This is an attempt to cover the common cases found when enabling driver model for serial on a new board. Signed-off-by: Simon Glass Reviewed-by: Fabio Estevam Signed-off-by: Heinrich Schuchardt --- doc/develop/driver-model/serial-howto.rst | 153 +++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 1 deletion(-) diff --git a/doc/develop/driver-model/serial-howto.rst b/doc/develop/driver-model/serial-howto.rst index 1469131..8af79a9 100644 --- a/doc/develop/driver-model/serial-howto.rst +++ b/doc/develop/driver-model/serial-howto.rst @@ -34,7 +34,7 @@ In terms of patches a conversion series typically has these patches: - convert at least one existing board to use driver model serial - (if no boards remain that don't use driver model) remove the old code -This may be a good time to move your board to use device tree also. Mostly +This may be a good time to move your board to use the device tree too. Mostly this involves these steps: - define CONFIG_OF_CONTROL and CONFIG_OF_SEPARATE @@ -44,3 +44,154 @@ this involves these steps: - build and get u-boot-dtb.bin so you can test it - Your drivers can now use device tree - For device tree in SPL, define CONFIG_SPL_OF_CONTROL + + +Converting boards to CONFIG_DM_SERIAL +------------------------------------- + +If your SoC has a serial driver that uses driver model (has U_BOOT_DRIVER() in +it), then you may still find that your board has not been converted. To convert +your board, enable the option and see if you can get it working. + +Firstly you will have a lot more success if you have a method of debugging your +board, such as a JTAG connection. Failing that the debug UART is useful, +although since you are trying to get the UART driver running, it will interfere +with your efforts eventually. + +Secondly, while the UART is a relatively simple peripheral, it may need quite a +few pieces to be up and running before it will work, such as the correct pin +muxing, clocks, power domains and possibly even GPIOs, if an external +transceiver is used. Look at other boards that use the same SoC, for clues as to +what is needed. + +Thirdly, when added tags, put them in a xxx-u-boot.dtsi file, where xxx is your +board name, or SoC name. There may already be a file for your SoC which contains +what you need. U-Boot automatically includes these files: see :ref:`dttweaks`. + +Here are some things you might need to consider: + +1. The serial driver itself needs to be present before relocation, so that the + U-Boot banner appears. Make sure it has a u-boot,pre-reloc tag in the device + tree, so that the serial driver is bound when U-Boot starts. + + For example, on iMX8:: + + lpuart3: serial@5a090000 { + compatible = "fsl,imx8qm-lpuart"; + ... + }; + + put this in your xxx-u-boot.dtsi file:: + + &lpuart3 { + u-boot,dm-pre-proper; + }; + +2. If your serial port requires a particular pinmux configuration, you may need + a pinctrl driver. This needs to have a u-boot,pre-reloc tag also. Take care + that any subnodes have the same tag, if they are needed to make the correct + pinctrl available. + + For example, on RK3288, the UART2 uses uart2_xfer:: + + uart2: serial@ff690000 { + ... + pinctrl-0 = <&uart2_xfer>; + }; + + which is defined as follows:: + + pinctrl: pinctrl { + compatible = "rockchip,rk3228-pinctrl"; + + uart2: uart2 { + uart2_xfer: uart2-xfer { + rockchip,pins = <1 RK_PC2 RK_FUNC_2 &pcfg_pull_up>, + <1 RK_PC3 RK_FUNC_2 &pcfg_pull_none>; + }; + ... + }; + + This means you must make the uart2-xfer node available as well as all its + parents, so put this in your xxx-u-boot.dtsi file:: + + &pinctrl { + u-boot,dm-pre-reloc; + }; + + &uart2 { + u-boot,dm-pre-reloc; + }; + + &uart2_xfer { + u-boot,dm-pre-reloc; + }; + +3. The same applies to power domains. For example, if a particular power domain + must be enabled for the serial port to work, you need to ensure it is + available before relocation: + + For example, on iMX8, put this in your xxx-u-boot.dtsi file:: + + &pd_dma { + u-boot,dm-pre-proper; + }; + + &pd_dma_lpuart3 { + u-boot,dm-pre-proper; + }; + +4. The same applies to clocks, in the same way. Make sure that when your driver + requests a clock, typically with clk_get_by_index(), it is available. + + +Generally a failure to find a required device will cause an error which you can +catch, if you have the debug UART working. U-Boot outputs serial data to the +debug UART until the point where the real serial driver takes over. This point +is marked by gd->flags having the GD_FLG_SERIAL_READY flag set. This change +happens in serial_init() in serial-uclass.c so until that point the debug UART +is used. You can see the relevant code in putc() +, for example:: + + /* if we don't have a console yet, use the debug UART */ + if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY)) { + printch(c); + return; + } + ... carries on to use the console / serial driver + +Note that in device_probe() the call to pinctrl_select_state() silently fails +if the pinctrl driver fails. You can add a temporary check there if needed. + +Why do we have all these tags? The problem is that before relocation we don't +want to bind all the drivers since memory is limited and the CPU may be running +at a slow speed. So many boards will fail to boot without this optimisation, or +may take a long time to start up (e.g. hundreds of milliseconds). The tags tell +U-Boot which drivers to bind. + +The good news is that this problem is normally solved by the SoC, so that any +boards that use it will work as normal. But in some cases there are multiple +UARTs or multiple pinmux options, which means that each board may need to do +some customisation. + +Serial in SPL +------------- + +A similar process is needed in SPL, but in this case the u-boot,dm-spl or +u-boot,dm-tpl tags are used. Add these in the same way as above, to ensure that +the SPL device tree contains the required nodes (see spl/u-boot-spl.dtb for +what it actually contains). + +Removing old code +----------------- + +In some cases there may be initialisation code that is no-longer needed when +driver model is used, such as setting up the pin muxing, or enabling a clock. +Be sure to remove this. + +Example patch +------------- + +See this serial_patch_ for iMX7. + +.. _serial_patch: https://patchwork.ozlabs.org/project/uboot/patch/20220314232406.1945308-1-festevam@gmail.com/ -- cgit v1.1 From 56bc239db201e00e9885223cf03333b5d369e1be Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 2 Apr 2022 07:16:56 +0200 Subject: doc: correct bootefi.rst * add link to booti man-page * correct link description for efidebug command * correct punctuation Signed-off-by: Heinrich Schuchardt --- doc/usage/cmd/bootefi.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst index 282f22a..31279fc 100644 --- a/doc/usage/cmd/bootefi.rst +++ b/doc/usage/cmd/bootefi.rst @@ -24,7 +24,7 @@ The *bootefi* command is used to launch a UEFI binary which can be either of * UEFI run-time services driver An operating system requires a hardware description which can either be -presented as ACPI table (CONFIG\_GENERATE\_ACPI\_TABLE=y) or as device-tree +presented as ACPI table (CONFIG\_GENERATE\_ACPI\_TABLE=y) or as device-tree. The load address of the device-tree may be provided as parameter *fdt\_addr*. If this address is not specified, the bootefi command will try to fall back in sequence to: @@ -123,6 +123,7 @@ Configuration ------------- To use the *bootefi* command you must specify CONFIG\_CMD\_BOOTEFI=y. +The *bootefi bootmgr* sub-command requries CMD\_BOOTEFI\_BOOTMGR=y. The *bootefi hello* sub-command requries CMD\_BOOTEFI\_HELLO=y. The *bootefi selftest* sub-command depends on CMD\_BOOTEFI\_SELFTEST=y. @@ -130,6 +131,6 @@ See also -------- * *bootm* for launching UEFI binaries packed in FIT images -* *booti*, *bootm*, *bootz* for launching a Linux kernel without using the - UEFI sub-system -* *efidebug* for setting UEFI boot variables +* :doc:`booti`, *bootm*, *bootz* for launching a Linux kernel without + using the UEFI sub-system +* *efidebug* for setting UEFI boot variables and boot options -- cgit v1.1 From 16736c2312bff2a35707c411c3dba91de86751a9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 5 Apr 2022 16:14:27 +0200 Subject: doc: debug UART for RISC-V QEMU virt machine Provide settings for enabling the debug UART of the virt machine on RISC-V QEMU. Signed-off-by: Heinrich Schuchardt --- doc/board/emulation/qemu-riscv.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/board/emulation/qemu-riscv.rst b/doc/board/emulation/qemu-riscv.rst index ae99881..782f372 100644 --- a/doc/board/emulation/qemu-riscv.rst +++ b/doc/board/emulation/qemu-riscv.rst @@ -132,3 +132,13 @@ An attached disk can be emulated in RISC-V virt machine by adding:: -device ide-hd,drive=mydisk,bus=ahci.0 You will have to run 'scsi scan' to use it. + +Debug UART +---------- + +The following settings provide a debug UART for the virt machine:: + + CONFIG_DEBUG_UART=y + CONFIG_DEBUG_UART_NS16550=y + CONFIG_DEBUG_UART_BASE=0x10000000 + CONFIG_DEBUG_UART_CLOCK=3686400 -- cgit v1.1 From 2f5c9ad3f4ae9128dff35e8c704f629a5c42518e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 6 Apr 2022 11:35:46 +0200 Subject: doc: distro: Update list of all support boot types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add HOST, UBIFS. Signed-off-by: Pali Rohár Reviewed-by: Heinrich Schuchardt --- doc/develop/distro.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/develop/distro.rst b/doc/develop/distro.rst index c522be6..0113a3d 100644 --- a/doc/develop/distro.rst +++ b/doc/develop/distro.rst @@ -295,7 +295,8 @@ Each entry in the macro defines a single boot device (e.g. a specific eMMC device or SD card) or type of boot device (e.g. USB disk). The parameters to the func macro (passed in by the internal implementation of the header) are: -- Upper-case disk type (MMC, SATA, SCSI, IDE, USB, DHCP, PXE, VIRTIO). +- Upper-case disk type (DHCP, HOST, IDE, MMC, NVME, PXE, SATA, SCSI, UBIFS, USB, + VIRTIO). - Lower-case disk type (same options as above). - ID of the specific disk (MMC only) or ignored for other types. -- cgit v1.1 From f2288a26ab6d7d23bf4e57a61e051d0e0cfdf8dd Mon Sep 17 00:00:00 2001 From: Tom Saeger Date: Tue, 22 Mar 2022 15:21:10 -0600 Subject: efi_loader: optional persistence of variables Since be66b89da306 ("efi_loader: configuration of variables store") the choice of EFI_VARIABLE_FILE_STORE or EFI_MM_COMM_TEE is mutually-exclusive, however efi_var_to_file also allows for "neither". Provide an additional Kconfig option. Signed-off-by: Tom Saeger Reviewed-by: Heinrich Schuchardt --- lib/efi_loader/Kconfig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 28657f5..759cd2a 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -62,11 +62,18 @@ config EFI_MM_COMM_TEE variable related operations to that. The application will verify, authenticate and store the variables on an RPMB. +config EFI_VARIABLE_NO_STORE + bool "Don't persist non-volatile UEFI variables" + help + If you choose this option, non-volatile variables cannot be persisted. + You could still provide non-volatile variables via + EFI_VARIABLES_PRESEED. + endchoice config EFI_VARIABLES_PRESEED bool "Initial values for UEFI variables" - depends on EFI_VARIABLE_FILE_STORE + depends on !EFI_MM_COMM_TEE help Include a file with the initial values for non-volatile UEFI variables into the U-Boot binary. If this configuration option is set, changes -- cgit v1.1 From 4cd1fca3611b40d84d38dec9f562ecfd287e2844 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Mon, 21 Mar 2022 22:37:35 +0900 Subject: cmd: efidebug: Disable 'capsule disk-update' when CONFIG_EFI_CAPSULE_ON_DISK=n Disable 'capsule disk-update' option for the efidebug command when CONFIC_EFI_CAPSULE_ON_DISK is disabled, because this option is available only when the EFI capsule update on disk is enabled. Signed-off-by: Masami Hiramatsu Suggested-by: Heinrich Schuchardt --- cmd/efidebug.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 3cc6f2b..df928ce 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -84,6 +84,7 @@ static int do_efi_capsule_update(struct cmd_tbl *cmdtp, int flag, return CMD_RET_SUCCESS; } +#ifdef CONFIG_EFI_CAPSULE_ON_DISK static int do_efi_capsule_on_disk_update(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) { @@ -93,6 +94,7 @@ static int do_efi_capsule_on_disk_update(struct cmd_tbl *cmdtp, int flag, return ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE; } +#endif /** * do_efi_capsule_show() - show capsule information @@ -303,8 +305,10 @@ static struct cmd_tbl cmd_efidebug_capsule_sub[] = { U_BOOT_CMD_MKENT(esrt, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_esrt, "", ""), #endif +#ifdef CONFIG_EFI_CAPSULE_ON_DISK U_BOOT_CMD_MKENT(disk-update, 0, 0, do_efi_capsule_on_disk_update, "", ""), +#endif U_BOOT_CMD_MKENT(result, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_res, "", ""), }; -- cgit v1.1 From 39bdf115805b9fd2bbfc8ed3c0d85224042ac776 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Mon, 21 Mar 2022 22:37:45 +0900 Subject: efi_loader: Make efi_load_capsule_drivers() available even if EFI_CAPSULE_ON_DISK=n Make efi_load_capsule_drivers() available even if EFI_CAPSULE_ON_DISK is disabled because the caller (efi_init_obj_list()) expects it only relays on EFI_HAVE_CAPSULE_SUPPORT. Suggested-by: Heinrich Schuchardt Signed-off-by: Masami Hiramatsu --- lib/efi_loader/efi_capsule.c | 60 ++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index f004401..66abc30 100644 --- a/lib/efi_loader/efi_capsule.c +++ b/lib/efi_loader/efi_capsule.c @@ -619,6 +619,36 @@ out: return EFI_EXIT(ret); } +/** + * efi_load_capsule_drivers - initialize capsule drivers + * + * Generic FMP drivers backed by DFU + * + * Return: status code + */ +efi_status_t __weak efi_load_capsule_drivers(void) +{ + __maybe_unused efi_handle_t handle; + efi_status_t ret = EFI_SUCCESS; + + if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_FIT)) { + handle = NULL; + ret = EFI_CALL(efi_install_multiple_protocol_interfaces( + &handle, &efi_guid_firmware_management_protocol, + &efi_fmp_fit, NULL)); + } + + if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_RAW)) { + handle = NULL; + ret = EFI_CALL(efi_install_multiple_protocol_interfaces( + &handle, + &efi_guid_firmware_management_protocol, + &efi_fmp_raw, NULL)); + } + + return ret; +} + #ifdef CONFIG_EFI_CAPSULE_ON_DISK /** * get_dp_device - retrieve a device path from boot variable @@ -1015,36 +1045,6 @@ static void efi_capsule_scan_done(void) } /** - * efi_load_capsule_drivers - initialize capsule drivers - * - * Generic FMP drivers backed by DFU - * - * Return: status code - */ -efi_status_t __weak efi_load_capsule_drivers(void) -{ - __maybe_unused efi_handle_t handle; - efi_status_t ret = EFI_SUCCESS; - - if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_FIT)) { - handle = NULL; - ret = EFI_CALL(efi_install_multiple_protocol_interfaces( - &handle, &efi_guid_firmware_management_protocol, - &efi_fmp_fit, NULL)); - } - - if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_RAW)) { - handle = NULL; - ret = EFI_CALL(efi_install_multiple_protocol_interfaces( - &handle, - &efi_guid_firmware_management_protocol, - &efi_fmp_raw, NULL)); - } - - return ret; -} - -/** * check_run_capsules() - check whether capsule update should run * * The spec says OsIndications must be set in order to run the capsule update -- cgit v1.1 From 7660cfee0fb7827535b8d7152613728ad399b9df Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Mon, 21 Mar 2022 22:37:56 +0900 Subject: efi_loader: Use sysreset instead of reset command Use sysreset_walk_halt() directly from reset-after-capsule-on-disk feature to reboot (cold reset) machine instead of using reset command interface, since this is not a command. Note that this will make CONFIG_EFI_CAPSULE_ON_DISK depending on the CONFIG_SYSRESET. Signed-off-by: Masami Hiramatsu Reviewed-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- lib/efi_loader/Kconfig | 1 + lib/efi_loader/efi_capsule.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 759cd2a..559b95a 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -136,6 +136,7 @@ config EFI_RUNTIME_UPDATE_CAPSULE config EFI_CAPSULE_ON_DISK bool "Enable capsule-on-disk support" + depends on SYSRESET select EFI_HAVE_CAPSULE_SUPPORT help Select this option if you want to use capsule-on-disk feature, diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index 66abc30..a107f28 100644 --- a/lib/efi_loader/efi_capsule.c +++ b/lib/efi_loader/efi_capsule.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1157,9 +1158,9 @@ efi_status_t efi_launch_capsules(void) * UEFI spec requires to reset system after complete processing capsule * update on the storage. */ - log_info("Reboot after firmware update"); + log_info("Reboot after firmware update.\n"); /* Cold reset is required for loading the new firmware. */ - do_reset(NULL, 0, 0, NULL); + sysreset_walk_halt(SYSRESET_COLD); hang(); /* not reach here */ -- cgit v1.1 From ae518bd88002400e2ea251f1ffe51fbde2d02fca Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 8 Mar 2022 20:36:39 +0900 Subject: scsi: call device_probe() after scanning Every time a scsi bus/port is scanned and a new block device is detected, we want to call device_probe() as it will give us a chance to run additional post-processings for some purposes. In particular, support for creating partitions on a device will be added. Signed-off-by: AKASHI Takahiro Reviewed-by: Simon Glass --- drivers/scsi/scsi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index d7b3301..78d729d 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -595,6 +595,11 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose) ata_swap_buf_le16((u16 *)&bdesc->revision, sizeof(bd.revision) / 2); } + ret = blk_probe_or_unbind(bdev); + if (ret < 0) + /* TODO: undo create */ + return ret; + if (verbose) { printf(" Device %d: ", bdesc->devnum); dev_print(bdesc); -- cgit v1.1 From 8c9812a5d557c4eacf164147d7380b3af1b222ec Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 8 Mar 2022 20:36:40 +0900 Subject: usb: storage: call device_probe() after scanning Every time a usb bus/port is scanned and a new device is detected, we want to call device_probe() as it will give us a chance to run additional post-processings for some purposes. In particular, support for creating partitions on a device will be added. Signed-off-by: AKASHI Takahiro Reviewed-by: Simon Glass --- common/usb_storage.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/usb_storage.c b/common/usb_storage.c index c9e2d73..291728f 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -239,6 +239,10 @@ static int usb_stor_probe_device(struct usb_device *udev) if (ret) return ret; } + + ret = blk_probe_or_unbind(dev); + if (ret) + return ret; } #else /* We don't have space to even probe if we hit the maximum */ -- cgit v1.1 From c822c1a50bd7573c57ba70a2b52590a7954960fc Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 8 Mar 2022 20:36:41 +0900 Subject: mmc: call device_probe() after scanning Every time a mmc bus/port is scanned and a new device is detected, we want to call device_probe() as it will give us a chance to run additional post-processings for some purposes. In particular, support for creating partitions on a device will be added. Signed-off-by: AKASHI Takahiro Reviewed-by: Jaehoon Chung --- drivers/mmc/mmc-uclass.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index b80e838..57da788 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -467,6 +467,18 @@ static int mmc_blk_probe(struct udevice *dev) return ret; } + ret = device_probe(dev); + if (ret) { + debug("Probing %s failed (err=%d)\n", dev->name, ret); + + if (CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)) + mmc_deinit(mmc); + + return ret; + } + return 0; } -- cgit v1.1 From df1ed8b2a8bac37c35ed0e349d704ba1e3bf76ee Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 8 Mar 2022 20:36:42 +0900 Subject: nvme: call device_probe() after scanning Every time a nvme bus/port is scanned and a new device is detected, we want to call device_probe() as it will give us a chance to run additional post-processings for some purposes. In particular, support for creating partitions on a device will be added. Signed-off-by: AKASHI Takahiro Reviewed-by: Simon Glass --- drivers/nvme/nvme.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index 1d56517..a305305 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -884,6 +884,10 @@ int nvme_init(struct udevice *udev) -1, 512, 0, &ns_udev); if (ret) goto free_id; + + ret = blk_probe_or_unbind(ns_udev); + if (ret) + goto free_id; } free(id); -- cgit v1.1 From c662edd6de9002176f62c05c6fe71bd5b4e84c4c Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 8 Mar 2022 20:36:43 +0900 Subject: sata: call device_probe() after scanning Every time a sata bus/port is scanned and a new device is detected, we want to call device_probe() as it will give us a chance to run additional post-processings for some purposes. In particular, support for creating partitions on a device will be added. Signed-off-by: AKASHI Takahiro Reviewed-by: Simon Glass --- drivers/ata/dwc_ahsata.c | 5 +++++ drivers/ata/fsl_sata.c | 11 +++++++++++ drivers/ata/sata_mv.c | 5 +++++ drivers/ata/sata_sil.c | 12 ++++++++++++ 4 files changed, 33 insertions(+) diff --git a/drivers/ata/dwc_ahsata.c b/drivers/ata/dwc_ahsata.c index 6d42548..d9fd850 100644 --- a/drivers/ata/dwc_ahsata.c +++ b/drivers/ata/dwc_ahsata.c @@ -1026,6 +1026,11 @@ int dwc_ahsata_scan(struct udevice *dev) return ret; } + ret = blk_probe_or_unbind(dev); + if (ret < 0) + /* TODO: undo create */ + return ret; + return 0; } diff --git a/drivers/ata/fsl_sata.c b/drivers/ata/fsl_sata.c index e44db0a..d1bab93 100644 --- a/drivers/ata/fsl_sata.c +++ b/drivers/ata/fsl_sata.c @@ -982,6 +982,17 @@ static int fsl_ata_probe(struct udevice *dev) failed_number++; continue; } + + ret = device_probe(dev); + if (ret < 0) { + debug("Probing %s failed (%d)\n", dev->name, ret); + ret = fsl_unbind_device(blk); + if (ret) + return ret; + + failed_number++; + continue; + } } if (failed_number == nr_ports) diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 003222d..a187796 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1099,6 +1099,11 @@ static int sata_mv_probe(struct udevice *dev) continue; } + ret = blk_probe_or_unbind(dev); + if (ret < 0) + /* TODO: undo create */ + continue; + /* If we got here, the current SATA port was probed * successfully, so set the probe status to successful. */ diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index a4f0dae..b213eba 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -753,6 +753,18 @@ static int sil_pci_probe(struct udevice *dev) failed_number++; continue; } + + ret = device_probe(dev); + if (ret < 0) { + debug("Probing %s failed (%d)\n", dev->name, ret); + ret = sil_unbind_device(blk); + device_unbind(dev); + if (ret) + return ret; + + failed_number++; + continue; + } } if (failed_number == sata_info.maxport) -- cgit v1.1 From 4c73b0344230129ec7493cf425922791e6132a30 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 8 Mar 2022 20:36:44 +0900 Subject: block: ide: call device_probe() after scanning Every time an ide bus/port is scanned and a new device is detected, we want to call device_probe() as it will give us a chance to run additional post-processings for some purposes. In particular, support for creating partitions on a device will be added. Signed-off-by: AKASHI Takahiro Reviewed-by: Simon Glass --- drivers/block/ide.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 63c4cfd..e8518ff 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -1123,6 +1123,10 @@ static int ide_probe(struct udevice *udev) blksz, size, &blk_dev); if (ret) return ret; + + ret = blk_probe_or_unbind(blk_dev); + if (ret) + return ret; } } -- cgit v1.1 From 75a9d7504180f01abb3f63ee894476f457c6dbb5 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 8 Mar 2022 20:36:45 +0900 Subject: virtio: call device_probe() in scanning virtio_init() enumerates all the peripherals that are to be materialised with udevices(UCLASS_VIRIO) and creates particular device instances (UCLASS_BlK or whatever else) as children. On the other hand, device_probe() won't be invoked against those resultant udevices unlike other ordinary device drivers do in the driver model. This is particularly inconvenient when we want to add "event notification" callback so that we will be able to automatically create all efi_disk objects in a later patch. With this patch applied, "virtio scan" will work in a similar way to "scsi rescan", "usb start" or others in term of 'probe' semantics. I didn't add this change to virtio_init() itself because this function may be called in board_init_r() (indirectly in board_late_init()) before UEFI subsustem is initialized. Signed-off-by: AKASHI Takahiro Reviewed-by: Simon Glass --- cmd/virtio.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/cmd/virtio.c b/cmd/virtio.c index 3dace53..ea3ed2e 100644 --- a/cmd/virtio.c +++ b/cmd/virtio.c @@ -17,8 +17,25 @@ static int do_virtio(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { if (argc == 2 && !strcmp(argv[1], "scan")) { - /* make sure all virtio devices are enumerated */ - virtio_init(); + /* + * make sure all virtio devices are enumerated. + * Do the same as virtio_init(), but also call + * device_probe() for children (i.e. virtio devices) + */ + struct udevice *bus, *child; + int ret; + + ret = uclass_first_device(UCLASS_VIRTIO, &bus); + if (ret) + return CMD_RET_FAILURE; + + while (bus) { + device_foreach_child_probe(child, bus) + ; + ret = uclass_next_device(&bus); + if (ret) + break; + } return CMD_RET_SUCCESS; } -- cgit v1.1 From 6b7a6210fde96bb95c8168af4ebf4eb83401df9e Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 8 Mar 2022 20:36:46 +0900 Subject: dm: add tag support With dm-tag feature, any U-Boot subsystem is allowed to associate arbitrary number of data with a particular udevice. This can been see as expanding "struct udevice" without modifying the definition. As a first user, UEFI subsystem makes use of tags to associate an efi_disk object with a block device. Signed-off-by: AKASHI Takahiro Reviewed-by: Simon Glass --- drivers/core/Makefile | 2 +- drivers/core/root.c | 2 + drivers/core/tag.c | 139 ++++++++++++++++++++++++++++++++++++++ include/asm-generic/global_data.h | 4 ++ include/dm/tag.h | 110 ++++++++++++++++++++++++++++++ 5 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 drivers/core/tag.c create mode 100644 include/dm/tag.h diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 5edd4e4..3742e75 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -2,7 +2,7 @@ # # Copyright (c) 2013 Google, Inc -obj-y += device.o fdtaddr.o lists.o root.o uclass.o util.o +obj-y += device.o fdtaddr.o lists.o root.o uclass.o util.o tag.o obj-$(CONFIG_$(SPL_TPL_)ACPIGEN) += acpi.o obj-$(CONFIG_DEVRES) += devres.o obj-$(CONFIG_$(SPL_)DM_DEVICE_REMOVE) += device-remove.o diff --git a/drivers/core/root.c b/drivers/core/root.c index 8efb425..86b3884 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -199,6 +199,8 @@ int dm_init(bool of_live) return ret; } + INIT_LIST_HEAD((struct list_head *)&gd->dmtag_list); + return 0; } diff --git a/drivers/core/tag.c b/drivers/core/tag.c new file mode 100644 index 0000000..6829bcd --- /dev/null +++ b/drivers/core/tag.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 Linaro Limited + * Author: AKASHI Takahiro + */ + +#include +#include +#include +#include +#include +#include + +struct udevice; + +DECLARE_GLOBAL_DATA_PTR; + +int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr) +{ + struct dmtag_node *node; + + if (!dev || tag >= DM_TAG_COUNT) + return -EINVAL; + + list_for_each_entry(node, &gd->dmtag_list, sibling) { + if (node->dev == dev && node->tag == tag) + return -EEXIST; + } + + node = calloc(sizeof(*node), 1); + if (!node) + return -ENOSPC; + + node->dev = dev; + node->tag = tag; + node->ptr = ptr; + list_add_tail(&node->sibling, (struct list_head *)&gd->dmtag_list); + + return 0; +} + +int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val) +{ + struct dmtag_node *node; + + if (!dev || tag >= DM_TAG_COUNT) + return -EINVAL; + + list_for_each_entry(node, &gd->dmtag_list, sibling) { + if (node->dev == dev && node->tag == tag) + return -EEXIST; + } + + node = calloc(sizeof(*node), 1); + if (!node) + return -ENOSPC; + + node->dev = dev; + node->tag = tag; + node->val = val; + list_add_tail(&node->sibling, (struct list_head *)&gd->dmtag_list); + + return 0; +} + +int dev_tag_get_ptr(struct udevice *dev, enum dm_tag_t tag, void **ptrp) +{ + struct dmtag_node *node; + + if (!dev || tag >= DM_TAG_COUNT) + return -EINVAL; + + list_for_each_entry(node, &gd->dmtag_list, sibling) { + if (node->dev == dev && node->tag == tag) { + *ptrp = node->ptr; + return 0; + } + } + + return -ENOENT; +} + +int dev_tag_get_val(struct udevice *dev, enum dm_tag_t tag, ulong *valp) +{ + struct dmtag_node *node; + + if (!dev || tag >= DM_TAG_COUNT) + return -EINVAL; + + list_for_each_entry(node, &gd->dmtag_list, sibling) { + if (node->dev == dev && node->tag == tag) { + *valp = node->val; + return 0; + } + } + + return -ENOENT; +} + +int dev_tag_del(struct udevice *dev, enum dm_tag_t tag) +{ + struct dmtag_node *node, *tmp; + + if (!dev || tag >= DM_TAG_COUNT) + return -EINVAL; + + list_for_each_entry_safe(node, tmp, &gd->dmtag_list, sibling) { + if (node->dev == dev && node->tag == tag) { + list_del(&node->sibling); + free(node); + + return 0; + } + } + + return -ENOENT; +} + +int dev_tag_del_all(struct udevice *dev) +{ + struct dmtag_node *node, *tmp; + bool found = false; + + if (!dev) + return -EINVAL; + + list_for_each_entry_safe(node, tmp, &gd->dmtag_list, sibling) { + if (node->dev == dev) { + list_del(&node->sibling); + free(node); + found = true; + } + } + + if (found) + return 0; + + return -ENOENT; +} diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index beb8bb9..805a6fd 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -474,6 +474,10 @@ struct global_data { */ struct event_state event_state; #endif + /** + * @dmtag_list: List of DM tags + */ + struct list_head dmtag_list; }; #ifndef DO_DEPS_ONLY static_assert(sizeof(struct global_data) == GD_SIZE); diff --git a/include/dm/tag.h b/include/dm/tag.h new file mode 100644 index 0000000..54fc31e --- /dev/null +++ b/include/dm/tag.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2021 Linaro Limited + * Author: AKASHI Takahiro + */ + +#ifndef _DM_TAG_H +#define _DM_TAG_H + +#include +#include + +struct udevice; + +enum dm_tag_t { + /* EFI_LOADER */ + DM_TAG_EFI = 0, + + DM_TAG_COUNT, +}; + +/** + * dmtag_node + * + * @sibling: List of dm-tag nodes + * @dev: Associated udevice + * @tag: Tag type + * @ptr: Pointer as a value + * @val: Value + */ +struct dmtag_node { + struct list_head sibling; + struct udevice *dev; + enum dm_tag_t tag; + union { + void *ptr; + ulong val; + }; +}; + +/** + * dev_tag_set_ptr() - set a tag's value as a pointer + * @dev: Device to operate + * @tag: Tag type + * @ptr: Pointer to set + * + * Set the value, @ptr, as of @tag associated with the device, @dev + * + * Return: 0 on success, -ve on error + */ +int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr); + +/** + * dev_tag_set_val() set a tag's value as an integer + * @dev: Device to operate + * @tag: Tag type + * @val: Value to set + * + * Set the value, @val, as of @tag associated with the device, @dev + * + * Return: on success, -ve on error + */ +int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val); + +/** + * dev_tag_get_ptr() - get a tag's value as a pointer + * @dev: Device to operate + * @tag: Tag type + * @ptrp: Pointer to tag's value (pointer) + * + * Get a tag's value as a pointer + * + * Return: on success, -ve on error + */ +int dev_tag_get_ptr(struct udevice *dev, enum dm_tag_t tag, void **ptrp); + +/** + * dev_tag_get_val() - get a tag's value as an integer + * @dev: Device to operate + * @tag: Tag type + * @valp: Pointer to tag's value (ulong) + * + * Get a tag's value as an integer + * + * Return: 0 on success, -ve on error + */ +int dev_tag_get_val(struct udevice *dev, enum dm_tag_t tag, ulong *valp); + +/** + * dev_tag_del() - delete a tag + * @dev: Device to operate + * @tag: Tag type + * + * Delete a tag of @tag associated with the device, @dev + * + * Return: 0 on success, -ve on error + */ +int dev_tag_del(struct udevice *dev, enum dm_tag_t tag); + +/** + * dev_tag_del_all() - delete all tags + * @dev: Device to operate + * + * Delete all the tags associated with the device, @dev + * + * Return: 0 on success, -ve on error + */ +int dev_tag_del_all(struct udevice *dev); + +#endif /* _DM_TAG_H */ -- cgit v1.1