[PATCH 2/2] ARM: meson: add support for Libre Computer aml-s905d3-cc
Add support for the Libre Computer aml-s905d3-cc "Solitude" board: https://libre.computer/products/aml-s905d3-cc/ The Solitude board has a Credit Card form factor, similar to the the previous "Le Potato" card, but with the Amlogic A311D SoC, MIPI DSI and CSI connectors. PoE header and a single USB2 Type-C connector replacing the microUSB one for power and USB 2.0. The board has an embedded SPI NOR flash, and EFI Capsule support is added. The GUID is dynamically generated for the board, to get it: => efidebug capsule esrt ESRT: fw_resource_count=1 ESRT: fw_resource_count_max=1 ESRT: fw_resource_version=1 [entry 0]== ESRT: fw_class=4302C3CB-2502-5EFE-87E0-894A8A322893 ESRT: fw_type=unknown ESRT: fw_version=0 ESRT: lowest_supported_fw_version=0 ESRT: capsule_flags=0 ESRT: last_attempt_version=0 ESRT: last_attempt_status=success On the host (with the aml_encrypt_g12a result binary): $ eficapsule --guid 4302C3CB-2502-5EFE-87E0-894A8A322893 -i 1 u-boot.bin u-boot.cap On the board (from USB disk containing u-boot.cap at root): => load usb 0:1 $kernel_addr_r u-boot.cap => efidebug capsule update $kernel_addr_r The binary will then be flashed on the SPI. Signed-off-by: Neil Armstrong --- .../dts/meson-sm1-s905d3-libretech-cc-u-boot.dtsi | 15 +++ board/libre-computer/aml-s905d3-cc/MAINTAINERS | 7 ++ board/libre-computer/aml-s905d3-cc/Makefile| 6 ++ board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c | 44 + configs/aml-s905d3-cc_defconfig| 108 + doc/board/amlogic/aml-s905d3-cc.rst| 46 + doc/board/amlogic/index.rst| 1 + 7 files changed, 227 insertions(+) diff --git a/arch/arm/dts/meson-sm1-s905d3-libretech-cc-u-boot.dtsi b/arch/arm/dts/meson-sm1-s905d3-libretech-cc-u-boot.dtsi new file mode 100644 index 000..1c4f019120f --- /dev/null +++ b/arch/arm/dts/meson-sm1-s905d3-libretech-cc-u-boot.dtsi @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Neil Armstrong + */ + +#include "meson-g12-common-u-boot.dtsi" + +&sd_emmc_c { + pinctrl-0 = <&emmc_ctrl_pins>, <&emmc_data_4b_pins>, <&emmc_ds_pins>; + bus-width = <4>; +}; + +&spifc { + status = "okay"; +}; diff --git a/board/libre-computer/aml-s905d3-cc/MAINTAINERS b/board/libre-computer/aml-s905d3-cc/MAINTAINERS new file mode 100644 index 000..4b75c815c07 --- /dev/null +++ b/board/libre-computer/aml-s905d3-cc/MAINTAINERS @@ -0,0 +1,7 @@ +LIBRE-COMPUTER AML-S905D3-CC +M: Neil Armstrong +S: Maintained +L: u-boot-amlo...@groups.io +F: board/amlogic/aml-s905d3-cc/ +F: configs/aml-s905d3-cc_defconfig +F: doc/board/amlogic/aml-s905d3-cc.rst diff --git a/board/libre-computer/aml-s905d3-cc/Makefile b/board/libre-computer/aml-s905d3-cc/Makefile new file mode 100644 index 000..7d2c41e6436 --- /dev/null +++ b/board/libre-computer/aml-s905d3-cc/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2016 BayLibre, SAS +# Author: Neil Armstrong + +obj-y := aml-s905d3-cc.o diff --git a/board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c b/board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c new file mode 100644 index 000..f641db5a494 --- /dev/null +++ b/board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include +#include + +struct efi_fw_image fw_images[] = { + { + .fw_name = u"AML_S905D3_CC_BOOT", + .image_index = 1, + }, +}; + +struct efi_capsule_update_info update_info = { + .dfu_string = "sf 0:0=u-boot-bin raw 0 0x1", + .num_images = ARRAY_SIZE(fw_images), + .images = fw_images, +}; + + +#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO) +void set_dfu_alt_info(char *interface, char *devstr) +{ + if (strcmp(interface, "ram") == 0) + env_set("dfu_alt_info", "fitimage ram 0x0808 0x400"); + else if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) + env_set("dfu_alt_info", update_info.dfu_string); +} +#endif + +int misc_init_r(void) +{ + meson_generate_serial_ethaddr(); + + return 0; +} diff --git a/configs/aml-s905d3-cc_defconfig b/configs/aml-s905d3-cc_defconfig new file mode 100644 index 000..a6e5d584c0a --- /dev/null +++ b/configs/aml-s905d3-cc_defconfig @@ -0,0 +1,108 @@ +CONFIG_ARM=y +CONFIG_SYS_VENDOR="libre-computer" +CONFIG_SYS_BOARD="aml-s905d3-cc" +CONFIG_ARCH_MESON=y +CONFIG_TEXT_BASE=0x0100 +CONFIG_NR_DRAM
[PATCH 1/2] ARM: meson: add support for Libre Computer aml-a311d-cc
Add support for the Libre Computer aml-a311d-cc "Alta" board: https://libre.computer/products/aml-a311d-cc/ The Alta board has a Credit Card form factor, similar to the the prvevious "Le Potato" card, but with the Amlogic A311D SoC, MIPI DSI and CSI connectors. PoE header and a single USB2 Type-C connector replacing the microUSB one for power and USB 2.0. The board has an embedded SPI NOR flash, and EFI Capsule support is added. The GUID is dynamically generated for the board, to get it: => efidebug capsule esrt ESRT: fw_resource_count=1 ESRT: fw_resource_count_max=1 ESRT: fw_resource_version=1 [entry 0]== ESRT: fw_class=17E07D9D-4D91-53F4-8780-1D91F279C1A5 ESRT: fw_type=unknown ESRT: fw_version=0 ESRT: lowest_supported_fw_version=0 ESRT: capsule_flags=0 ESRT: last_attempt_version=0 ESRT: last_attempt_status=success On the host (with the aml_encrypt_g12a result binary): $ eficapsule --guid 17E07D9D-4D91-53F4-8780-1D91F279C1A5 -i 1 u-boot.bin u-boot.cap On the board (from USB disk containing u-boot.cap at root): => load usb 0:1 $kernel_addr_r u-boot.cap => efidebug capsule update $kernel_addr_r The binary will then be flashed on the SPI. Signed-off-by: Neil Armstrong --- .../dts/meson-g12b-a311d-libretech-cc-u-boot.dtsi | 15 +++ board/libre-computer/aml-a311d-cc/MAINTAINERS | 7 ++ board/libre-computer/aml-a311d-cc/Makefile | 6 ++ board/libre-computer/aml-a311d-cc/aml-a311d-cc.c | 44 + configs/aml-a311d-cc_defconfig | 108 + doc/board/amlogic/aml-a311d-cc.rst | 46 + doc/board/amlogic/index.rst| 1 + 7 files changed, 227 insertions(+) diff --git a/arch/arm/dts/meson-g12b-a311d-libretech-cc-u-boot.dtsi b/arch/arm/dts/meson-g12b-a311d-libretech-cc-u-boot.dtsi new file mode 100644 index 000..cbada739042 --- /dev/null +++ b/arch/arm/dts/meson-g12b-a311d-libretech-cc-u-boot.dtsi @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Neil Armstrong + */ + +#include "meson-g12-common-u-boot.dtsi" + +&sd_emmc_c { + pinctrl-0 = <&emmc_ctrl_pins>, <&emmc_data_4b_pins>; + bus-width = <4>; +}; + +&spifc { + status = "okay"; +}; diff --git a/board/libre-computer/aml-a311d-cc/MAINTAINERS b/board/libre-computer/aml-a311d-cc/MAINTAINERS new file mode 100644 index 000..b4b77acd23b --- /dev/null +++ b/board/libre-computer/aml-a311d-cc/MAINTAINERS @@ -0,0 +1,7 @@ +LIBRE-COMPUTER AML-A311D-CC +M: Neil Armstrong +S: Maintained +L: u-boot-amlo...@groups.io +F: board/amlogic/aml-a311d-cc/ +F: configs/aml-a311d-cc_defconfig +F: doc/board/amlogic/aml-a311d-cc.rst diff --git a/board/libre-computer/aml-a311d-cc/Makefile b/board/libre-computer/aml-a311d-cc/Makefile new file mode 100644 index 000..461955def3a --- /dev/null +++ b/board/libre-computer/aml-a311d-cc/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2016 BayLibre, SAS +# Author: Neil Armstrong + +obj-y := aml-a311d-cc.o diff --git a/board/libre-computer/aml-a311d-cc/aml-a311d-cc.c b/board/libre-computer/aml-a311d-cc/aml-a311d-cc.c new file mode 100644 index 000..e45cfd5d8a3 --- /dev/null +++ b/board/libre-computer/aml-a311d-cc/aml-a311d-cc.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include +#include + +struct efi_fw_image fw_images[] = { + { + .fw_name = u"AML_A311D_CC_BOOT", + .image_index = 1, + }, +}; + +struct efi_capsule_update_info update_info = { + .dfu_string = "sf 0:0=u-boot-bin raw 0 0x1", + .num_images = ARRAY_SIZE(fw_images), + .images = fw_images, +}; + + +#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO) +void set_dfu_alt_info(char *interface, char *devstr) +{ + if (strcmp(interface, "ram") == 0) + env_set("dfu_alt_info", "fitimage ram 0x0808 0x400"); + else if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) + env_set("dfu_alt_info", update_info.dfu_string); +} +#endif + +int misc_init_r(void) +{ + meson_generate_serial_ethaddr(); + + return 0; +} diff --git a/configs/aml-a311d-cc_defconfig b/configs/aml-a311d-cc_defconfig new file mode 100644 index 000..c8e22200419 --- /dev/null +++ b/configs/aml-a311d-cc_defconfig @@ -0,0 +1,108 @@ +CONFIG_ARM=y +CONFIG_SYS_VENDOR="libre-computer" +CONFIG_SYS_BOARD="aml-a311d-cc" +CONFIG_ARCH_MESON=y +CONFIG_TEXT_BASE=0x0100 +CONFIG_NR_DRAM_BANKS=1 +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_
[PATCH 0/2] board: libre-computer: Add support for Libre Computer aml-a311d-cc & aml-s905d3-cc boards
Add support for the Libre Computer aml-a311d-cc "Alta" & aml-s905d3-cc "Solitude" boards: https://libre.computer/products/aml-a311d-cc/ https://libre.computer/products/aml-s905d3-cc/ The Alta & Solitude boards have a Credit Card form factor, similar to the the previous "Le Potato" card, but with the Amlogic A311D or S903D3 SoCS, MIPI DSI and CSI connectors. PoE header and a single USB2 Type-C connector replacing the microUSB one for power and USB 2.0. The boards have an embedded SPI NOR flash, and EFI Capsule support is added. Signed-off-by: Neil Armstrong --- Neil Armstrong (2): ARM: meson: add support for Libre Computer aml-a311d-cc ARM: meson: add support for Libre Computer aml-s905d3-cc .../dts/meson-g12b-a311d-libretech-cc-u-boot.dtsi | 15 +++ .../dts/meson-sm1-s905d3-libretech-cc-u-boot.dtsi | 15 +++ board/libre-computer/aml-a311d-cc/MAINTAINERS | 7 ++ board/libre-computer/aml-a311d-cc/Makefile | 6 ++ board/libre-computer/aml-a311d-cc/aml-a311d-cc.c | 44 + board/libre-computer/aml-s905d3-cc/MAINTAINERS | 7 ++ board/libre-computer/aml-s905d3-cc/Makefile| 6 ++ board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c | 44 + configs/aml-a311d-cc_defconfig | 108 + configs/aml-s905d3-cc_defconfig| 108 + doc/board/amlogic/aml-a311d-cc.rst | 46 + doc/board/amlogic/aml-s905d3-cc.rst| 46 + doc/board/amlogic/index.rst| 2 + 13 files changed, 454 insertions(+) --- base-commit: 13fd7a17858e5f2555a1d68e4afa75fceda0dac0 change-id: 20240920-u-boot-topic-libre-computer-solitude-alta-c3b22cbd16df Best regards, -- Neil Armstrong
Re: [PATCH v2 09/13] ufs: Sync possible UFS Quirks with Linux UFS driver
On 20/09/2024 10:00, neil.armstr...@linaro.org wrote: From: Bhupesh Sharma Sync u-boot UFS driver to add all possible UFS Quirks as supported by Linux UFS driver as well. Synced with include/ufs/ufshcd.h from Linux v6.11 release Signed-off-by: Bhupesh Sharma Tested-by: Venkatesh Yadav Abbarapu --- drivers/ufs/ufs.h | 193 +- 1 file changed, 162 insertions(+), 31 deletions(-) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 555f8a6857d..a1006b80e88 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -712,38 +712,169 @@ struct ufs_hba { u32 version; u32 intr_mask; u32 quirks; -/* - * If UFS host controller is having issue in processing LCC (Line - * Control Command) coming from device then enable this quirk. - * When this quirk is enabled, host controller driver should disable - * the LCC transmission on UFS device (by clearing TX_LCC_ENABLE - * attribute of device to 0). - */ -#define UFSHCD_QUIRK_BROKEN_LCCBIT(0) - -/* - * This quirk needs to be enabled if the host controller has - * 64-bit addressing supported capability but it doesn't work. - */ -#define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS BIT(1) - -/* - * This quirk needs to be enabled if the host controller has - * auto-hibernate capability but it's FASTAUTO only. - */ -#define UFSHCD_QUIRK_HIBERN_FASTAUTO BIT(2) - -/* - * This quirk needs to be enabled if the host controller has - * 64-bit addressing supported capability but it doesn't work. - */ -#define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS 0x2 -/* - * This quirk needs to be enabled if the host controller has - * auto-hibernate capability but it's FASTAUTO only. - */ -#define UFSHCD_QUIRK_HIBERN_FASTAUTO 0x4 +enum ufshcd_quirks { + /* Interrupt aggregation support is broken */ + UFSHCD_QUIRK_BROKEN_INTR_AGGR = 1 << 0, + + /* +* delay before each dme command is required as the unipro +* layer has shown instabilities +*/ + UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS = 1 << 1, + + /* +* If UFS host controller is having issue in processing LCC (Line +* Control Command) coming from device then enable this quirk. +* When this quirk is enabled, host controller driver should disable +* the LCC transmission on UFS device (by clearing TX_LCC_ENABLE +* attribute of device to 0). +*/ + UFSHCD_QUIRK_BROKEN_LCC = 1 << 2, + + /* +* The attribute PA_RXHSUNTERMCAP specifies whether or not the +* inbound Link supports unterminated line in HS mode. Setting this +* attribute to 1 fixes moving to HS gear. +*/ + UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP= 1 << 3, + + /* +* This quirk needs to be enabled if the host controller only allows +* accessing the peer dme attributes in AUTO mode (FAST AUTO or +* SLOW AUTO). +*/ + UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE = 1 << 4, + + /* +* This quirk needs to be enabled if the host controller doesn't +* advertise the correct version in UFS_VER register. If this quirk +* is enabled, standard UFS host driver will call the vendor specific +* ops (get_ufs_hci_version) to get the correct version. +*/ + UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION = 1 << 5, + + /* +* Clear handling for transfer/task request list is just opposite. +*/ + UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR= 1 << 6, + + /* +* This quirk needs to be enabled if host controller doesn't allow +* that the interrupt aggregation timer and counter are reset by s/w. +*/ + UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR = 1 << 7, + + /* +* This quirks needs to be enabled if host controller cannot be +* enabled via HCE register. +*/ + UFSHCI_QUIRK_BROKEN_HCE = 1 << 8, + + /* +* This quirk needs to be enabled if the host controller regards +* resolution of the values of PRDTO and PRDTL in UTRD as byte. +*/ + UFSHCD_QUIRK_PRDT_BYTE_GRAN = 1 << 9, + + /* +* This quirk needs to be enabled if the host controller reports +* OCS FATAL ERROR with device error through sense data +*/ + UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR = 1 << 10, + + /* +* This quirk needs to be enabled if the host controller has +* auto-hibernate capability but it doesn't work. +*/ + UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8= 1 << 11, + + /* +* This quirk needs to disable manual flush for write booster +*/ + UFSHC
[PATCH v2 13/13] MAINTAINERS: Add myself to the list of UFS maintainers
Adding myself to continue Bhupesh's work to enhance and fix UFS support in U-Boot, especially for Qualcomm SoCs, and help review patches and maintain the UFS subsystem. Reviewed-by: Neha Malcom Francis Tested-by: Venkatesh Yadav Abbarapu Signed-off-by: Neil Armstrong --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7ab39d91a55..14809c057c9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1707,6 +1707,7 @@ T:git https://source.denx.de/u-boot/custodians/u-boot-ubi.git F: drivers/mtd/ubi/ UFS +M: Neil Armstrong M: Bhupesh Sharma M: Neha Malcom Francis S: Maintained -- 2.34.1
[PATCH v2 10/13] ufs: Add missing memory barriers
From: Bhupesh Sharma Add missing wmb() and mb() barriers in the u-boot UFS core framework driver to allow registers updates to happen before follow-up read operations. This makes the barrier placement similar to the Linux UFS driver, synced from the Linux v6.9 release. Starting from the v6.10 release, the barriers were replaced with a register read-back in [1], this will ported to u-boot in a second time. [1] https://lore.kernel.org/all/20240329-ufs-reset-ensure-effect-before-delay-v5-0-181252004...@redhat.com/ Signed-off-by: Bhupesh Sharma Tested-by: Venkatesh Yadav Abbarapu --- drivers/ufs/ufs.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 565a6af1404..5d4e5424358 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -432,6 +432,12 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba) ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utmrdl), REG_UTP_TASK_REQ_LIST_BASE_H); + /* +* Make sure base address and interrupt setup are updated before +* enabling the run/stop registers below. +*/ + wmb(); + /* * UCRDY, UTMRLDY and UTRLRDY bits must be 1 */ @@ -861,6 +867,9 @@ static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); + /* Make sure doorbell reg is updated before reading interrupt status */ + wmb(); + start = get_timer(0); do { intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); @@ -1994,6 +2003,8 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) REG_INTERRUPT_STATUS); ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE); + mb(); + err = ufshcd_hba_enable(hba); if (err) { dev_err(hba->dev, "Host controller enable failed\n"); -- 2.34.1
[PATCH v2 12/13] ufs: core: remove link_startup_again logic
The link_startup_again logic was added in Linux to handle device that were set in LinkDown state, which should not be the case since U-boot doesn't set LinkDown state are init, and Linux sets the device active in ufshcd_init() for the first link startup. ufshcd_set_ufs_dev_active(hba) is called at ufshcd_init() right before scheduling an ufshcd_async_scan that will call ufshcd_device_init() then ufshcd_link_startup(). The comment in probe says: /* * We are assuming that device wasn't put in sleep/power-down * state exclusively during the boot stage before kernel. * This assumption helps avoid doing link startup twice during * ufshcd_probe_hba(). */ we can assume the same from U-Boot. While it worked to far, it breaks link startup for Qualcomm Controllers v5, let's just remove the logic. Tested-by: Venkatesh Yadav Abbarapu Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 8 1 file changed, 8 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index d2df5c26f76..e34e4586224 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -462,9 +462,7 @@ static int ufshcd_link_startup(struct ufs_hba *hba) { int ret; int retries = DME_LINKSTARTUP_RETRIES; - bool link_startup_again = true; -link_startup: do { ufshcd_ops_link_startup_notify(hba, PRE_CHANGE); @@ -490,12 +488,6 @@ link_startup: /* failed to get the link up... retire */ goto out; - if (link_startup_again) { - link_startup_again = false; - retries = DME_LINKSTARTUP_RETRIES; - goto link_startup; - } - /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */ ufshcd_init_pwr_info(hba); -- 2.34.1
[PATCH v2 11/13] ufs: Fix debug message in 'ufs_start'
From: Bhupesh Sharma Minor typo fix and rewording of printf message inside 'ufs_start' which announces the availability of the UFS device. Signed-off-by: Bhupesh Sharma Tested-by: Venkatesh Yadav Abbarapu --- drivers/ufs/ufs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 5d4e5424358..d2df5c26f76 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -1925,7 +1925,7 @@ int ufs_start(struct ufs_hba *hba) return ret; } - printf("Device at %s up at:", hba->dev->name); + debug("UFS Device %s is up!\n", hba->dev->name); ufshcd_print_pwr_info(hba); } -- 2.34.1
[PATCH v2 09/13] ufs: Sync possible UFS Quirks with Linux UFS driver
From: Bhupesh Sharma Sync u-boot UFS driver to add all possible UFS Quirks as supported by Linux UFS driver as well. Synced with include/ufs/ufshcd.h from Linux v6.11 release Signed-off-by: Bhupesh Sharma Tested-by: Venkatesh Yadav Abbarapu --- drivers/ufs/ufs.h | 193 +- 1 file changed, 162 insertions(+), 31 deletions(-) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 555f8a6857d..a1006b80e88 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -712,38 +712,169 @@ struct ufs_hba { u32 version; u32 intr_mask; u32 quirks; -/* - * If UFS host controller is having issue in processing LCC (Line - * Control Command) coming from device then enable this quirk. - * When this quirk is enabled, host controller driver should disable - * the LCC transmission on UFS device (by clearing TX_LCC_ENABLE - * attribute of device to 0). - */ -#define UFSHCD_QUIRK_BROKEN_LCCBIT(0) - -/* - * This quirk needs to be enabled if the host controller has - * 64-bit addressing supported capability but it doesn't work. - */ -#define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS BIT(1) - -/* - * This quirk needs to be enabled if the host controller has - * auto-hibernate capability but it's FASTAUTO only. - */ -#define UFSHCD_QUIRK_HIBERN_FASTAUTO BIT(2) - -/* - * This quirk needs to be enabled if the host controller has - * 64-bit addressing supported capability but it doesn't work. - */ -#define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS 0x2 -/* - * This quirk needs to be enabled if the host controller has - * auto-hibernate capability but it's FASTAUTO only. - */ -#define UFSHCD_QUIRK_HIBERN_FASTAUTO 0x4 +enum ufshcd_quirks { + /* Interrupt aggregation support is broken */ + UFSHCD_QUIRK_BROKEN_INTR_AGGR = 1 << 0, + + /* +* delay before each dme command is required as the unipro +* layer has shown instabilities +*/ + UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS = 1 << 1, + + /* +* If UFS host controller is having issue in processing LCC (Line +* Control Command) coming from device then enable this quirk. +* When this quirk is enabled, host controller driver should disable +* the LCC transmission on UFS device (by clearing TX_LCC_ENABLE +* attribute of device to 0). +*/ + UFSHCD_QUIRK_BROKEN_LCC = 1 << 2, + + /* +* The attribute PA_RXHSUNTERMCAP specifies whether or not the +* inbound Link supports unterminated line in HS mode. Setting this +* attribute to 1 fixes moving to HS gear. +*/ + UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP= 1 << 3, + + /* +* This quirk needs to be enabled if the host controller only allows +* accessing the peer dme attributes in AUTO mode (FAST AUTO or +* SLOW AUTO). +*/ + UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE = 1 << 4, + + /* +* This quirk needs to be enabled if the host controller doesn't +* advertise the correct version in UFS_VER register. If this quirk +* is enabled, standard UFS host driver will call the vendor specific +* ops (get_ufs_hci_version) to get the correct version. +*/ + UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION = 1 << 5, + + /* +* Clear handling for transfer/task request list is just opposite. +*/ + UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR= 1 << 6, + + /* +* This quirk needs to be enabled if host controller doesn't allow +* that the interrupt aggregation timer and counter are reset by s/w. +*/ + UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR = 1 << 7, + + /* +* This quirks needs to be enabled if host controller cannot be +* enabled via HCE register. +*/ + UFSHCI_QUIRK_BROKEN_HCE = 1 << 8, + + /* +* This quirk needs to be enabled if the host controller regards +* resolution of the values of PRDTO and PRDTL in UTRD as byte. +*/ + UFSHCD_QUIRK_PRDT_BYTE_GRAN = 1 << 9, + + /* +* This quirk needs to be enabled if the host controller reports +* OCS FATAL ERROR with device error through sense data +*/ + UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR = 1 << 10, + + /* +* This quirk needs to be enabled if the host controller has +* auto-hibernate capability but it doesn't work. +*/ + UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8= 1 << 11, + + /* +* This quirk needs to disable manual flush for write booster +*/ + UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL = 1 << 12, + +
[PATCH v2 03/13] ufs: split flush and invalidate to only invalidate when required
There is no need to flush and invalidate all data updated by the driver, mainly because on ARM platforms flush also invalidates the cachelines. Split the function in two and add the appropriate cacheline invalidates after the UFS DMA operation finishes to make sure we read from memory. Flushing then invalidating cacheline unaligned data causes data corruption issues on Qualcomm platforms, and is largely unnecessary anyway, so let's cleanup the cache operations. Reviewed-by: Neha Malcom Francis Tested-by: Venkatesh Yadav Abbarapu Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 45 ++--- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 3d9a7d7ee12..5845fd694d3 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -696,17 +696,28 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) } /** - * ufshcd_cache_flush_and_invalidate - Flush and invalidate cache + * ufshcd_cache_flush - Flush cache * - * Flush and invalidate cache in aligned address..address+size range. - * The invalidation is in place to avoid stale data in cache. + * Flush cache in aligned address..address+size range. */ -static void ufshcd_cache_flush_and_invalidate(void *addr, unsigned long size) +static void ufshcd_cache_flush(void *addr, unsigned long size) { uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); flush_dcache_range(start_addr, end_addr); +} + +/** + * ufshcd_cache_invalidate - Invalidate cache + * + * Invalidate cache in aligned address..address+size range. + */ +static void ufshcd_cache_invalidate(void *addr, unsigned long size) +{ + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); + invalidate_dcache_range(start_addr, end_addr); } @@ -754,7 +765,7 @@ static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, req_desc->prd_table_length = 0; - ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc)); + ufshcd_cache_flush(req_desc, sizeof(*req_desc)); } static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, @@ -785,13 +796,13 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, /* Copy the Descriptor */ if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) { memcpy(ucd_req_ptr + 1, query->descriptor, len); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr)); } else { - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); } memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) @@ -809,8 +820,8 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } /** @@ -877,6 +888,8 @@ static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) */ static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) { + ufshcd_cache_invalidate(ucd_rsp_ptr, sizeof(*ucd_rsp_ptr)); + return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24; } @@ -888,6 +901,8 @@ static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba) { struct utp_transfer_req_desc *req_desc = hba->utrdl; + ufshcd_cache_invalidate(req_desc, sizeof(*req_desc)); + return le32_to_cpu(req_desc->header.dword_2) & MASK_OCS; } @@ -1437,8 +1452,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba, memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len); memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry, @@ -1461,7 +1476,7
[PATCH v2 08/13] ufs: Clear UECPA once due to LINERESET has happened during LINK_STARTUP
From: Bhupesh Sharma Clear UECPA once in u-boot UFS driver due to LINERESET has happened during LINK_STARTUP. This makes the u-boot ufs driver behavior related to UECPA similar to Linux UFS driver. Ported from Linux kernel commit: 2355b66ed20c ("scsi: ufs: Handle LINERESET indication in err handler") Signed-off-by: Bhupesh Sharma Tested-by: Venkatesh Yadav Abbarapu --- drivers/ufs/ufs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index d99dcdef7d0..565a6af1404 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -504,6 +504,8 @@ link_startup: if (ret) goto out; + /* Clear UECPA once due to LINERESET has happened during LINK_STARTUP */ + ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); ret = ufshcd_make_hba_operational(hba); out: if (ret) -- 2.34.1
[PATCH v2 05/13] ufs: Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS
From: Marek Vasut Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS for host controllers which do not support 64-bit addressing. Ported from Linux kernel commit 6554400d6f66 ("scsi: ufs: core: Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS") with ufs_scsi_buffer_aligned() based on U-Boot generic bounce buffer. Signed-off-by: Marek Vasut Tested-by: Venkatesh Yadav Abbarapu --- drivers/ufs/ufs.h | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 43042c294bb..c92f47d82b5 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -732,6 +732,12 @@ struct ufs_hba { */ #define UFSHCD_QUIRK_HIBERN_FASTAUTO BIT(2) +/* + * This quirk needs to be enabled if the host controller has + * 64-bit addressing supported capability but it doesn't work. + */ +#define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS 0x2 + /* Virtual memory reference */ struct utp_transfer_cmd_desc *ucdl; struct utp_transfer_req_desc *utrdl; -- 2.34.1
[PATCH v2 07/13] ufs/ufs.h: Add definition of 'ufshcd_rmwl()'
From: Bhupesh Sharma Add definition of 'ufshcd_rmwl()' helper function which would be later used by Qualcomm UFS driver to read-modify-write registers. Ported from Linux kernel commits: e785060ea3a1 ("ufs: definitions for phy interface") cff91daf52d3 ("scsi: ufs: Fix kernel-doc syntax in ufshcd.h") Signed-off-by: Bhupesh Sharma Tested-by: Venkatesh Yadav Abbarapu --- drivers/ufs/ufs.h | 18 ++ 1 file changed, 18 insertions(+) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index b55c4a9e996..555f8a6857d 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -3,6 +3,7 @@ #define __UFS_H #include +#include #include "unipro.h" struct udevice; @@ -933,6 +934,23 @@ enum { #define ufshcd_readl(hba, reg) \ readl((hba)->mmio_base + (reg)) +/** + * ufshcd_rmwl - perform read/modify/write for a controller register + * @hba: per adapter instance + * @mask: mask to apply on read value + * @val: actual value to write + * @reg: register address + */ +static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg) +{ + u32 tmp; + + tmp = ufshcd_readl(hba, reg); + tmp &= ~mask; + tmp |= (val & mask); + ufshcd_writel(hba, tmp, reg); +} + /* UTRLRSR - UTP Transfer Request Run-Stop Register 60h */ #define UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT 0x1 -- 2.34.1
[PATCH v2 06/13] ufs: Add UFSHCD_QUIRK_HIBERN_FASTAUTO
From: Marek Vasut Add UFSHCD_QUIRK_HIBERN_FASTAUTO quirk for host controllers which supports auto-hibernate the capability but only FASTAUTO mode. Ported from Linux kernel commit 2f11bbc2c7f3 ("scsi: ufs: core: Add UFSHCD_QUIRK_HIBERN_FASTAUTO") Signed-off-by: Marek Vasut Tested-by: Venkatesh Yadav Abbarapu --- drivers/ufs/ufs.h | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index c92f47d82b5..b55c4a9e996 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -738,6 +738,12 @@ struct ufs_hba { */ #define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS 0x2 +/* + * This quirk needs to be enabled if the host controller has + * auto-hibernate capability but it's FASTAUTO only. + */ +#define UFSHCD_QUIRK_HIBERN_FASTAUTO 0x4 + /* Virtual memory reference */ struct utp_transfer_cmd_desc *ucdl; struct utp_transfer_req_desc *utrdl; -- 2.34.1
[PATCH v2 02/13] ufs: fix dcache flush and invalidate range calculation
The current calculation will omit doing a flush/invalidate on the last cacheline if the base address is not aligned with DMA_MINALIGN. This causes commands failures and write corruptions on Qualcomm platforms. Reviewed-by: Neha Malcom Francis Tested-by: Venkatesh Yadav Abbarapu Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 16 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index e005cc90608..3d9a7d7ee12 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -703,11 +703,11 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) */ static void ufshcd_cache_flush_and_invalidate(void *addr, unsigned long size) { - uintptr_t aaddr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); - unsigned long asize = ALIGN(size, ARCH_DMA_MINALIGN); + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); - flush_dcache_range(aaddr, aaddr + asize); - invalidate_dcache_range(aaddr, aaddr + asize); + flush_dcache_range(start_addr, end_addr); + invalidate_dcache_range(start_addr, end_addr); } /** @@ -1466,13 +1466,13 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) } if (pccb->dma_dir == DMA_TO_DEVICE) { /* Write to device */ - flush_dcache_range(aaddr, aaddr + - ALIGN(datalen, ARCH_DMA_MINALIGN)); + flush_dcache_range(aaddr, + ALIGN((uintptr_t)pccb->pdata + datalen, ARCH_DMA_MINALIGN)); } /* In any case, invalidate cache to avoid stale data in it. */ - invalidate_dcache_range(aaddr, aaddr + - ALIGN(datalen, ARCH_DMA_MINALIGN)); + invalidate_dcache_range(aaddr, + ALIGN((uintptr_t)pccb->pdata + datalen, ARCH_DMA_MINALIGN)); table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY); buf = pccb->pdata; -- 2.34.1
[PATCH v2 04/13] ufs: use dcache helpers for scsi_cmd data and only invalidate if necessary
Now we have proper flush and invalidate helpers, we can use them directly to operate on the scsi_cmd data. Likewise, we do not need to flush then invalidate, just flush _or_ invalidate depending on the data direction. Reviewed-by: Neha Malcom Francis Tested-by: Venkatesh Yadav Abbarapu Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 14 -- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 5845fd694d3..d99dcdef7d0 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -1468,7 +1468,6 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) { struct utp_transfer_req_desc *req_desc = hba->utrdl; struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr; - uintptr_t aaddr = (uintptr_t)(pccb->pdata) & ~(ARCH_DMA_MINALIGN - 1); ulong datalen = pccb->datalen; int table_length; u8 *buf; @@ -1480,15 +1479,6 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) return; } - if (pccb->dma_dir == DMA_TO_DEVICE) { /* Write to device */ - flush_dcache_range(aaddr, - ALIGN((uintptr_t)pccb->pdata + datalen, ARCH_DMA_MINALIGN)); - } - - /* In any case, invalidate cache to avoid stale data in it. */ - invalidate_dcache_range(aaddr, - ALIGN((uintptr_t)pccb->pdata + datalen, ARCH_DMA_MINALIGN)); - table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY); buf = pccb->pdata; i = table_length; @@ -1517,8 +1507,12 @@ static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb) ufshcd_prepare_utp_scsi_cmd_upiu(hba, pccb, upiu_flags); prepare_prdt_table(hba, pccb); + ufshcd_cache_flush(pccb->pdata, pccb->datalen); + ufshcd_send_command(hba, TASK_TAG); + ufshcd_cache_invalidate(pccb->pdata, pccb->datalen); + ocs = ufshcd_get_tr_ocs(hba); switch (ocs) { case OCS_SUCCESS: -- 2.34.1
[PATCH v2 01/13] ufs: allocate descriptors with size aligned with DMA_MINALIGN
Align the allocation size with DMA_MINALIGN to make sure we do not flush/invalidate data from following allocations. Reviewed-by: Neha Malcom Francis Tested-by: Venkatesh Yadav Abbarapu Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index be64bf971f1..e005cc90608 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -633,7 +633,9 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) /* Allocate one Transfer Request Descriptor * Should be aligned to 1k boundary. */ - hba->utrdl = memalign(1024, sizeof(struct utp_transfer_req_desc)); + hba->utrdl = memalign(1024, + ALIGN(sizeof(struct utp_transfer_req_desc), + ARCH_DMA_MINALIGN)); if (!hba->utrdl) { dev_err(hba->dev, "Transfer Descriptor memory allocation failed\n"); return -ENOMEM; @@ -642,7 +644,9 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) /* Allocate one Command Descriptor * Should be aligned to 1k boundary. */ - hba->ucdl = memalign(1024, sizeof(struct utp_transfer_cmd_desc)); + hba->ucdl = memalign(1024, +ALIGN(sizeof(struct utp_transfer_cmd_desc), + ARCH_DMA_MINALIGN)); if (!hba->ucdl) { dev_err(hba->dev, "Command descriptor memory allocation failed\n"); return -ENOMEM; -- 2.34.1
[PATCH v2 00/13] ufs: enhancements to support Qualcomm UFS controllers
This serie regroups all the fixes and base enhancements required to support the Qualcomm UFS controllers in U-Boot. This syncs headers & defines from Linux, and includes 2 set of fixes that were sent separately: - ufs: core: remove link_startup_again logic - ufs: properly fix cache operations Without those 2 sets, UFS cannot initialize on Qualcomm controlers since v5, and a numerous of Cache issues makes any UFS controller fail to initialize. Since UFS core hasn't changed for a while, and since UFS is core technology for the Qualcomm SoCs, I volunteer maintaininig the UFS subsystem if Bhupesh & Neha Malcom Francis are ok with that. It has been reported to show regressions on: - TI K3 platforms (j721s2, j721e, j7200, j784s4) [1] - AMD platform (amd_versal2_virt_defconfig) [2] [1] https://lore.kernel.org/all/38f599a8-7094-4a04-8ff6-96fc8b9d1...@ti.com/ [2] https://lore.kernel.org/all/sa1pr12mb869713ca620f99077b75ef0e98...@sa1pr12mb8697.namprd12.prod.outlook.com/ Signed-off-by: Neil Armstrong --- Changes in v2: - Added review and tested-by tags - Updated patch 12 message with more explanations - Synced patch 9 again with Linux 6.11 - Updated patches 7, 8, 9 and 10 with informations about the origins of the changes - Link to v1: https://lore.kernel.org/r/20240910-topic-ufs-enhancements-v1-0-3ee0bffac...@linaro.org --- Bhupesh Sharma (5): ufs/ufs.h: Add definition of 'ufshcd_rmwl()' ufs: Clear UECPA once due to LINERESET has happened during LINK_STARTUP ufs: Sync possible UFS Quirks with Linux UFS driver ufs: Add missing memory barriers ufs: Fix debug message in 'ufs_start' Marek Vasut (2): ufs: Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS ufs: Add UFSHCD_QUIRK_HIBERN_FASTAUTO Neil Armstrong (6): ufs: allocate descriptors with size aligned with DMA_MINALIGN ufs: fix dcache flush and invalidate range calculation ufs: split flush and invalidate to only invalidate when required ufs: use dcache helpers for scsi_cmd data and only invalidate if necessary ufs: core: remove link_startup_again logic MAINTAINERS: Add myself to the list of UFS maintainers MAINTAINERS | 1 + drivers/ufs/ufs.c | 98 --- drivers/ufs/ufs.h | 199 -- 3 files changed, 239 insertions(+), 59 deletions(-) --- base-commit: 24961c0e0444d3ed534ffc6a173e6ea636ca116b change-id: 20240910-topic-ufs-enhancements-fe8ef9ce39d8 Best regards, -- Neil Armstrong
Re: [PATCH v2 1/3] ufs: add support for DesignWare Controller
LKDIV_DIV_125); + } else { /* POST_CHANGE */ + err = ufshcd_dwc_link_is_up(hba); + if (err) { + dev_err(hba->dev, "Link is not up\n"); + return err; + } + + err = ufshcd_dwc_connection_setup(hba); + if (err) + dev_err(hba->dev, "Connection setup failed (%d)\n", + err); + } + + return err; +} diff --git a/drivers/ufs/ufshcd-dwc.h b/drivers/ufs/ufshcd-dwc.h new file mode 100644 index 00..d997045d3c --- /dev/null +++ b/drivers/ufs/ufshcd-dwc.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * UFS Host driver for Synopsys Designware Core + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + * Authors: Joao Pinto + */ + +#ifndef _UFSHCD_DWC_H +#define _UFSHCD_DWC_H + +struct ufshcd_dme_attr_val { + u32 attr_sel; + u32 mib_val; + u8 peer; +}; + +int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status); +int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba, +const struct ufshcd_dme_attr_val *v, int n); +#endif /* End of Header */ diff --git a/drivers/ufs/ufshci-dwc.h b/drivers/ufs/ufshci-dwc.h new file mode 100644 index 00..9e24c230c6 --- /dev/null +++ b/drivers/ufs/ufshci-dwc.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * UFS Host driver for Synopsys Designware Core + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + * Authors: Joao Pinto + */ + +#ifndef _UFSHCI_DWC_H +#define _UFSHCI_DWC_H + +/* DWC HC UFSHCI specific Registers */ +enum dwc_specific_registers { + DWC_UFS_REG_HCLKDIV = 0xFC, +}; + +/* Clock Divider Values: Hex equivalent of frequency in MHz */ +enum clk_div_values { + DWC_UFS_REG_HCLKDIV_DIV_62_5= 0x3e, + DWC_UFS_REG_HCLKDIV_DIV_125 = 0x7d, + DWC_UFS_REG_HCLKDIV_DIV_200 = 0xc8, +}; + +/* Selector Index */ +enum selector_index { + SELIND_LN0_TX = 0x00, + SELIND_LN1_TX = 0x01, + SELIND_LN0_RX = 0x04, + SELIND_LN1_RX = 0x05, +}; +#endif Reviewed-by: Neil Armstrong
Re: [PATCH 2/3] ufs: ufs-amd-versal2: Add support for AMD UFS controller
|= SRAM_CSR_BYPASS_MASK; + } else { + dev_err(hba->dev, "Invalid phy-mode %d.\n", priv->phy_mode); + return -EINVAL; + } + + ret = versal2_pm_ufs_sram_csr_sel(priv->pd_dev_id, + PM_UFS_SRAM_CSR_WRITE, &sram_csr); + if (ret) + return ret; + + /* De Assert RST_UFS Reset for UFS block in PMX_IOU */ + ret = reset_deassert(priv->rstc); + if (ret) + dev_err(hba->dev, "ufshc reset deassert failed, err = %d\n", ret); + + break; + case POST_CHANGE: + ret = ufs_versal2_phy_init(hba); + if (ret) + dev_err(hba->dev, "Phy init failed (%d)\n", ret); + + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int ufs_versal2_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + struct ufs_versal2_priv *priv = dev_get_priv(hba->dev); + int ret = 0; + + switch (status) { + case PRE_CHANGE: + if (priv->host_clk) { + u32 core_clk_div = priv->host_clk / TIMEOUT_MICROSEC; + + ufshcd_writel(hba, core_clk_div, DWC_UFS_REG_HCLKDIV); + } + break; + case POST_CHANGE: + ret = ufshcd_dwc_link_startup_notify(hba, status); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static struct ufs_hba_ops ufs_versal2_hba_ops = { + .init = ufs_versal2_init, + .link_startup_notify = ufs_versal2_link_startup_notify, + .hce_enable_notify = ufs_versal2_hce_enable_notify, +}; + +static int ufs_versal2_probe(struct udevice *dev) +{ + int ret; + + /* Perform generic probe */ + ret = ufshcd_probe(dev, &ufs_versal2_hba_ops); + if (ret) + dev_err(dev, "ufshcd_probe() failed %d\n", ret); + + return ret; +} + +static int ufs_versal2_bind(struct udevice *dev) +{ + struct udevice *scsi_dev; + + return ufs_scsi_bind(dev, &scsi_dev); +} + +static const struct udevice_id ufs_versal2_ids[] = { + { + .compatible = "amd,versal2-ufs", + }, + {}, +}; + +U_BOOT_DRIVER(ufs_versal2_pltfm) = { + .name = "ufs-versal2-pltfm", + .id = UCLASS_UFS, + .of_match = ufs_versal2_ids, + .probe = ufs_versal2_probe, + .bind = ufs_versal2_bind, +}; diff --git a/drivers/ufs/ufshcd-dwc.h b/drivers/ufs/ufshcd-dwc.h index d997045d3c..fc1bcca8cc 100644 --- a/drivers/ufs/ufshcd-dwc.h +++ b/drivers/ufs/ufshcd-dwc.h @@ -10,6 +10,52 @@ #ifndef _UFSHCD_DWC_H #define _UFSHCD_DWC_H +/* PHY modes */ +#define UFSHCD_DWC_PHY_MODE_ROM0 + +/* RMMI Attributes */ +#define CBREFCLKCTRL2 0x8132 +#define CBCRCTRL 0x811F +#define CBC10DIRECTCONF2 0x810E +#define CBCREGADDRLSB 0x8116 +#define CBCREGADDRMSB 0x8117 +#define CBCREGWRLSB0x8118 +#define CBCREGWRMSB0x8119 +#define CBCREGRDLSB0x811A +#define CBCREGRDMSB0x811B +#define CBCREGRDWRSEL 0x811C + +#define CBREFREFCLK_GATE_OVR_ENBIT(7) + +/* M-PHY Attributes */ +#define MTX_FSM_STATE 0x41 +#define MRX_FSM_STATE 0xC1 + +/* M-PHY registers */ +#define FAST_FLAGS(n) (0x401C + ((n) * 0x100)) +#define RX_AFE_ATT_IDAC(n) (0x4000 + ((n) * 0x100)) +#define RX_AFE_CTLE_IDAC(n)(0x4001 + ((n) * 0x100)) +#define FW_CALIB_CCFG(n) (0x404D + ((n) * 0x100)) + +/* Tx/Rx FSM state */ +enum rx_fsm_state { + RX_STATE_DISABLED = 0, + RX_STATE_HIBERN8 = 1, + RX_STATE_SLEEP = 2, + RX_STATE_STALL = 3, + RX_STATE_LSBURST = 4, + RX_STATE_HSBURST = 5, +}; + +enum tx_fsm_state { + TX_STATE_DISABLED = 0, + TX_STATE_HIBERN8 = 1, + TX_STATE_SLEEP = 2, + TX_STATE_STALL = 3, + TX_STATE_LSBURST = 4, + TX_STATE_HSBURST = 5, +}; + struct ufshcd_dme_attr_val { u32 attr_sel; u32 mib_val; diff --git a/drivers/ufs/unipro.h b/drivers/ufs/unipro.h index b30b17fa5a..2f5726d4d3 100644 --- a/drivers/ufs/unipro.h +++ b/drivers/ufs/unipro.h @@ -148,6 +148,7 @@ #define VS_MPHYCFGUPDT0xD085 #define VS_DEBUGOMC 0xD09E #define VS_POWERSTATE 0xD083 +#define VS_MPHYDISABLE 0xD0C1 #define PA_GRANULARITY_MIN_VAL 1 #define PA_GRANULARITY_MAX_VAL6 Looks fine! Reviewed-by: Neil Armstrong Neil
Re: [PATCH 1/3] ufs: add support for DesignWare Controller
Hi, On 19/09/2024 11:17, Venkatesh Yadav Abbarapu wrote: This patch has the goal to add support for DesignWare UFS Controller specific operations. This is based on linux kernel commit: "drivers/scsi/ufs/ufshcd-dwc.c: ufs: add support for DesignWare Controller" (sha1: 4b9ffb5a353bdee49f1f477ffe2b95ab3f9cbc0c) It is ported from linux kernel 6.11-rc1. Signed-off-by: Venkatesh Yadav Abbarapu --- drivers/ufs/ufs.h| 11 +++ drivers/ufs/ufshcd-dwc.c | 141 +++ drivers/ufs/ufshcd-dwc.h | 23 +++ drivers/ufs/ufshci-dwc.h | 32 + 4 files changed, 207 insertions(+) create mode 100644 drivers/ufs/ufshcd-dwc.c create mode 100644 drivers/ufs/ufshcd-dwc.h create mode 100644 drivers/ufs/ufshci-dwc.h diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index e8a1441156..83837d5817 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -850,6 +850,7 @@ struct ufs_hba { struct ufs_pwr_mode_info max_pwr_info; struct ufs_dev_cmd dev_cmd; + enum uic_link_state uic_link_state; Will this be really used ? }; static inline int ufshcd_ops_init(struct ufs_hba *hba) @@ -878,6 +879,14 @@ static inline int ufshcd_ops_link_startup_notify(struct ufs_hba *hba, return 0; } +static inline int ufshcd_vops_phy_initialization(struct ufs_hba *hba) +{ + if (hba->ops && hba->ops->phy_initialization) + return hba->ops->phy_initialization(hba); + + return 0; +} There's no users of hba->ops->phy_initialization, and the patch 2 doesn't even add an user, so I think you can also drop this + /* Controller UFSHCI version */ enum { UFSHCI_VERSION_10 = 0x0001, /* 1.0 */ @@ -1022,6 +1031,8 @@ enum { writel((val), (hba)->mmio_base + (reg)) #define ufshcd_readl(hba, reg) \ readl((hba)->mmio_base + (reg)) +#define ufshcd_set_link_active(hba) ((hba)->uic_link_state = \ + UIC_LINK_ACTIVE_STATE) Same here, you set as active, but there's no users of uic_link_state I think you can drop this /** * ufshcd_rmwl - perform read/modify/write for a controller register diff --git a/drivers/ufs/ufshcd-dwc.c b/drivers/ufs/ufshcd-dwc.c new file mode 100644 index 00..db51a3b807 --- /dev/null +++ b/drivers/ufs/ufshcd-dwc.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * UFS Host driver for Synopsys Designware Core + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ufs.h" +#include "ufshci-dwc.h" +#include "ufshcd-dwc.h" + +int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba, +const struct ufshcd_dme_attr_val *v, int n) +{ + int ret = 0; + int attr_node = 0; + + for (attr_node = 0; attr_node < n; attr_node++) { + ret = ufshcd_dme_set_attr(hba, v[attr_node].attr_sel, + ATTR_SET_NOR, v[attr_node].mib_val, v[attr_node].peer); + if (ret) + return ret; + } + + return 0; +} + +/** + * ufshcd_dwc_program_clk_div() - program clock divider. + * @hba: Private Structure pointer + * @divider_val: clock divider value to be programmed + * + */ +static void ufshcd_dwc_program_clk_div(struct ufs_hba *hba, u32 divider_val) +{ + ufshcd_writel(hba, divider_val, DWC_UFS_REG_HCLKDIV); +} + +/** + * ufshcd_dwc_link_is_up() - check if link is up. + * @hba: private structure pointer + * + * Return: 0 on success, non-zero value on failure. + */ +static int ufshcd_dwc_link_is_up(struct ufs_hba *hba) +{ + int dme_result = 0; + + ufshcd_dme_get(hba, UIC_ARG_MIB(VS_POWERSTATE), &dme_result); + + if (dme_result == UFSHCD_LINK_IS_UP) { + ufshcd_set_link_active(hba); You can drop this, we don't track and use the link state + return 0; + } + + return 1; +} + +/** + * ufshcd_dwc_connection_setup() - configure unipro attributes. + * @hba: pointer to drivers private data + * + * This function configures both the local side (host) and the peer side + * (device) unipro attributes to establish the connection to application/ + * cport. + * This function is not required if the hardware is properly configured to + * have this connection setup on reset. But invoking this function does no + * harm and should be fine even working with any ufs device. + * + * Return: 0 on success non-zero value on failure. + */ +static int ufshcd_dwc_connection_setup(struct ufs_hba *hba) +{ + static const struct ufshcd_dme_attr_val setup_attrs[] = { + { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_LOCAL }, + { UIC_ARG_MIB(N_DEVICEID), 0, DME_LOCAL }, + { UIC_ARG_MIB(N_DEVICEID_VALID), 0, DME_LOCAL }, + { UIC_ARG_MIB(T_PEERDEVICEID), 1, DME_LOCAL }, + { UIC_ARG_MIB(
Re: [PATCH 00/13] ufs: enhancements to support Qualcomm UFS controllers
On 19/09/2024 10:56, Neha Malcom Francis wrote: Hi Neil On 18/09/24 13:36, Neil Armstrong wrote: Hi Marek, Manorit, Tom, Michal, On 10/09/2024 11:20, Neil Armstrong wrote: This serie regroups all the fixes and base enhancements required to support the Qualcomm UFS controllers in U-Boot. This syncs headers & defines from Linux, and includes 2 set of fixes that were sent separately: - ufs: core: remove link_startup_again logic - ufs: properly fix cache operations Without those 2 sets, UFS cannot initialize on Qualcomm controlers since v5, and a numerous of Cache issues makes any UFS controller fail to initialize. Since UFS core hasn't changed for a while, and since UFS is core technology for the Qualcomm SoCs, I volunteer maintaininig the UFS subsystem if Bhupesh & Neha Malcom Francis are ok with that. Could you run this serie on the r8a779f0_spider, j721s2_evm_a72, j721e_evm_a72, j7200_evm_a72, amd_versal2_virt and qemu-riscv and check for possible regressions ? For the K3 platforms (j721s2, j721e, j7200, j784s4) I have already done a sanity test with this series on j784s4 with no regressions seen, so should be fine. Ack, thanks for the report! Neil It seems the only user of UFS_PCI is qemu-riscv, is there other users ? Thanks, Neil Signed-off-by: Neil Armstrong --- Bhupesh Sharma (5): ufs/ufs.h: Add definition of 'ufshcd_rmwl()' ufs: Clear UECPA once due to LINERESET has happened during LINK_STARTUP ufs: Sync possible UFS Quirks with Linux UFS driver ufs: Add missing memory barriers ufs: Fix debug message in 'ufs_start' Marek Vasut (2): ufs: Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS ufs: Add UFSHCD_QUIRK_HIBERN_FASTAUTO Neil Armstrong (6): ufs: allocate descriptors with size aligned with DMA_MINALIGN ufs: fix dcache flush and invalidate range calculation ufs: split flush and invalidate to only invalidate when required ufs: use dcache helpers for scsi_cmd data and only invalidate if necessary ufs: core: remove link_startup_again logic MAINTAINERS: Add myself to the list of UFS maintainers MAINTAINERS | 1 + drivers/ufs/ufs.c | 98 -- drivers/ufs/ufs.h | 157 +++--- 3 files changed, 197 insertions(+), 59 deletions(-) --- base-commit: ca55cf8104c0dd78aae45fa66dd8400ef1b3d0ac change-id: 20240910-topic-ufs-enhancements-fe8ef9ce39d8 Best regards,
Re: [PATCH 00/13] ufs: enhancements to support Qualcomm UFS controllers
On 18/09/2024 12:47, Michal Simek wrote: On 9/18/24 12:40, neil.armstr...@linaro.org wrote: Hi, On 18/09/2024 11:03, Michal Simek wrote: Hi Neil, On 9/18/24 10:06, Neil Armstrong wrote: Hi Marek, Manorit, Tom, Michal, On 10/09/2024 11:20, Neil Armstrong wrote: This serie regroups all the fixes and base enhancements required to support the Qualcomm UFS controllers in U-Boot. This syncs headers & defines from Linux, and includes 2 set of fixes that were sent separately: - ufs: core: remove link_startup_again logic - ufs: properly fix cache operations Without those 2 sets, UFS cannot initialize on Qualcomm controlers since v5, and a numerous of Cache issues makes any UFS controller fail to initialize. Since UFS core hasn't changed for a while, and since UFS is core technology for the Qualcomm SoCs, I volunteer maintaininig the UFS subsystem if Bhupesh & Neha Malcom Francis are ok with that. Could you run this serie on the r8a779f0_spider, j721s2_evm_a72, j721e_evm_a72, j7200_evm_a72, amd_versal2_virt and qemu-riscv and check for possible regressions ? It seems the only user of UFS_PCI is qemu-riscv, is there other users ? Good timing. We are close to send some updates to UFS which we require to get DWC version to work inside U-Boot. How far are that core changes from Linux? I see 9/13 is sync with Linux but when this is done you should also say which Linux version was used for sync. I think we are still quite far from Linux, we just took the basic required bits and pieces to at least make the Qcom UFS controller driver build work, but Linux driver is overly complicated with power management code we do not really need in U-Boot, so it's quite hard to sync honestly. But the plan is to align as much as possible once we get the basic Qcom UFS mainline. That's understandable. But even when you say sync with Linux for some headers, etc it is good to say that it is sync with 6.11 for example. Oh yes exact, I forgot to add this info, I planned to... I'll fix this in a v2. Thanks, Neil Thanks, Michal
Re: [PATCH 00/13] ufs: enhancements to support Qualcomm UFS controllers
Hi, On 18/09/2024 11:03, Michal Simek wrote: Hi Neil, On 9/18/24 10:06, Neil Armstrong wrote: Hi Marek, Manorit, Tom, Michal, On 10/09/2024 11:20, Neil Armstrong wrote: This serie regroups all the fixes and base enhancements required to support the Qualcomm UFS controllers in U-Boot. This syncs headers & defines from Linux, and includes 2 set of fixes that were sent separately: - ufs: core: remove link_startup_again logic - ufs: properly fix cache operations Without those 2 sets, UFS cannot initialize on Qualcomm controlers since v5, and a numerous of Cache issues makes any UFS controller fail to initialize. Since UFS core hasn't changed for a while, and since UFS is core technology for the Qualcomm SoCs, I volunteer maintaininig the UFS subsystem if Bhupesh & Neha Malcom Francis are ok with that. Could you run this serie on the r8a779f0_spider, j721s2_evm_a72, j721e_evm_a72, j7200_evm_a72, amd_versal2_virt and qemu-riscv and check for possible regressions ? It seems the only user of UFS_PCI is qemu-riscv, is there other users ? Good timing. We are close to send some updates to UFS which we require to get DWC version to work inside U-Boot. How far are that core changes from Linux? I see 9/13 is sync with Linux but when this is done you should also say which Linux version was used for sync. I think we are still quite far from Linux, we just took the basic required bits and pieces to at least make the Qcom UFS controller driver build work, but Linux driver is overly complicated with power management code we do not really need in U-Boot, so it's quite hard to sync honestly. But the plan is to align as much as possible once we get the basic Qcom UFS mainline. I see that there are definitely some kernel-doc issues Also s/U-boot/U-Boot/g Ack, will check Venkatesh: Can you please look at this patch series and validate it on our platform? Also make sense to send our changes to make sure that they won't break others. Thanks, Michal Thanks, Neil
Re: [PATCH 00/13] ufs: enhancements to support Qualcomm UFS controllers
Hi Marek, Manorit, Tom, Michal, On 10/09/2024 11:20, Neil Armstrong wrote: This serie regroups all the fixes and base enhancements required to support the Qualcomm UFS controllers in U-Boot. This syncs headers & defines from Linux, and includes 2 set of fixes that were sent separately: - ufs: core: remove link_startup_again logic - ufs: properly fix cache operations Without those 2 sets, UFS cannot initialize on Qualcomm controlers since v5, and a numerous of Cache issues makes any UFS controller fail to initialize. Since UFS core hasn't changed for a while, and since UFS is core technology for the Qualcomm SoCs, I volunteer maintaininig the UFS subsystem if Bhupesh & Neha Malcom Francis are ok with that. Could you run this serie on the r8a779f0_spider, j721s2_evm_a72, j721e_evm_a72, j7200_evm_a72, amd_versal2_virt and qemu-riscv and check for possible regressions ? It seems the only user of UFS_PCI is qemu-riscv, is there other users ? Thanks, Neil Signed-off-by: Neil Armstrong --- Bhupesh Sharma (5): ufs/ufs.h: Add definition of 'ufshcd_rmwl()' ufs: Clear UECPA once due to LINERESET has happened during LINK_STARTUP ufs: Sync possible UFS Quirks with Linux UFS driver ufs: Add missing memory barriers ufs: Fix debug message in 'ufs_start' Marek Vasut (2): ufs: Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS ufs: Add UFSHCD_QUIRK_HIBERN_FASTAUTO Neil Armstrong (6): ufs: allocate descriptors with size aligned with DMA_MINALIGN ufs: fix dcache flush and invalidate range calculation ufs: split flush and invalidate to only invalidate when required ufs: use dcache helpers for scsi_cmd data and only invalidate if necessary ufs: core: remove link_startup_again logic MAINTAINERS: Add myself to the list of UFS maintainers MAINTAINERS | 1 + drivers/ufs/ufs.c | 98 -- drivers/ufs/ufs.h | 157 +++--- 3 files changed, 197 insertions(+), 59 deletions(-) --- base-commit: ca55cf8104c0dd78aae45fa66dd8400ef1b3d0ac change-id: 20240910-topic-ufs-enhancements-fe8ef9ce39d8 Best regards,
[PATCH v2 2/2] board: libre-computer: aml-s805x-cc: Enable capsule updates
Since the aml-s805-cc works well using EFI, and now the capsule updates backend has been merged, let's enable the missing configs and add the required structures to support it. The GUID is dynamically generated for the board, to get it: => efidebug capsule esrt ESRT: fw_resource_count=1 ESRT: fw_resource_count_max=1 ESRT: fw_resource_version=1 [entry 0]== ESRT: fw_class=B8079027-9B2C-57D4-86AA-CC782ADA598C ESRT: fw_type=unknown ESRT: fw_version=0 ESRT: lowest_supported_fw_version=0 ESRT: capsule_flags=0 ESRT: last_attempt_version=0 ESRT: last_attempt_status=success On the host (with the aml_encrypt_gxl result binary): $ eficapsule --guid B8079027-9B2C-57D4-86AA-CC782ADA598C -i 1 u-boot.bin u-boot.cap On the board (from USB disk containing u-boot.cap at root): => load usb 0:1 $kernel_addr_r u-boot.cap => efidebug capsule update $kernel_addr_r The binary will then be flashed on the SPI. Reviewed-by: Ilias Apalodimas Signed-off-by: Neil Armstrong --- board/libre-computer/aml-s805x-ac/aml-s805x-ac.c | 24 configs/libretech-ac_defconfig | 6 ++ 2 files changed, 30 insertions(+) diff --git a/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c index ae9834c0bf8..94cf5b4361f 100644 --- a/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c +++ b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,29 @@ #define EFUSE_MAC_OFFSET 52 #define EFUSE_MAC_SIZE 6 +struct efi_fw_image fw_images[] = { + { + .fw_name = u"AML_S805X_AC_BOOT", + .image_index = 1, + }, +}; + +struct efi_capsule_update_info update_info = { + .dfu_string = "sf 0:0=u-boot-bin raw 0 0x1", + .num_images = ARRAY_SIZE(fw_images), + .images = fw_images, +}; + +#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO) +void set_dfu_alt_info(char *interface, char *devstr) +{ + if (strcmp(interface, "ram") == 0) + env_set("dfu_alt_info", "fitimage ram 0x0808 0x400"); + else if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) + env_set("dfu_alt_info", update_info.dfu_string); +} +#endif + int misc_init_r(void) { u8 mac_addr[EFUSE_MAC_SIZE + 1]; diff --git a/configs/libretech-ac_defconfig b/configs/libretech-ac_defconfig index 11d9795e05d..7763a14f203 100644 --- a/configs/libretech-ac_defconfig +++ b/configs/libretech-ac_defconfig @@ -35,6 +35,7 @@ CONFIG_SYS_MAXARGS=32 # CONFIG_CMD_IMI is not set CONFIG_CMD_ADC=y CONFIG_CMD_DFU=y +CONFIG_CMD_NVEDIT_EFI=y CONFIG_CMD_GPIO=y # CONFIG_CMD_LOADS is not set CONFIG_CMD_MMC=y @@ -42,6 +43,7 @@ CONFIG_CMD_SF_TEST=y CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_EFIDEBUG=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_REGULATOR=y CONFIG_OF_CONTROL=y @@ -49,6 +51,8 @@ CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_SARADC_MESON=y CONFIG_DFU_RAM=y +CONFIG_DFU_SF=y +CONFIG_SET_DFU_ALT_INFO=y CONFIG_MMC_MESON_GX=y CONFIG_MTD=y CONFIG_DM_MTD=y @@ -98,3 +102,5 @@ CONFIG_VIDEO_BMP_RLE8=y CONFIG_BMP_16BPP=y CONFIG_BMP_24BPP=y CONFIG_BMP_32BPP=y +CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y -- 2.34.1
[PATCH v2 1/2] board: libretech-ac: move board support into dedicated directory
The libretech-ac aka aml-s805x-ac supports mainline U-boot from a dedicated SPI flash, move the board support into a dedicated vendor/board subdirectory in order to support vendor specific customization. It also aligns with the vendor downstream changes. Signed-off-by: Neil Armstrong --- board/amlogic/p212/MAINTAINERS | 2 - board/libre-computer/aml-s805x-ac/MAINTAINERS| 8 board/libre-computer/aml-s805x-ac/Makefile | 6 +++ board/libre-computer/aml-s805x-ac/aml-s805x-ac.c | 47 configs/libretech-ac_defconfig | 2 + 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/board/amlogic/p212/MAINTAINERS b/board/amlogic/p212/MAINTAINERS index b2e3205fdf0..e73a4e52c1f 100644 --- a/board/amlogic/p212/MAINTAINERS +++ b/board/amlogic/p212/MAINTAINERS @@ -5,11 +5,9 @@ L: u-boot-amlo...@groups.io F: board/amlogic/p212/ F: include/configs/p212.h F: configs/khadas-vim_defconfig -F: configs/libretech-ac_defconfig F: configs/libretech-cc_defconfig F: configs/libretech-cc_v2_defconfig F: configs/p212_defconfig F: doc/board/amlogic/p212.rst -F: doc/board/amlogic/libretech-ac.rst F: doc/board/amlogic/libretech-cc.rst F: doc/board/amlogic/khadas-vim.rst diff --git a/board/libre-computer/aml-s805x-ac/MAINTAINERS b/board/libre-computer/aml-s805x-ac/MAINTAINERS new file mode 100644 index 000..7cbc08aeb6c --- /dev/null +++ b/board/libre-computer/aml-s805x-ac/MAINTAINERS @@ -0,0 +1,8 @@ +LIBRE-COMPUTER AML-S805X-AC +M: Neil Armstrong +S: Maintained +L: u-boot-amlo...@groups.io +F: board/amlogic/aml-s805x-ac/ +F: include/configs/libretech-ac.h +F: configs/libretech-ac_defconfig +F: doc/board/amlogic/libretech-ac.rst diff --git a/board/libre-computer/aml-s805x-ac/Makefile b/board/libre-computer/aml-s805x-ac/Makefile new file mode 100644 index 000..b4367ea522b --- /dev/null +++ b/board/libre-computer/aml-s805x-ac/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2016 BayLibre, SAS +# Author: Neil Armstrong + +obj-y := aml-s805x-ac.o diff --git a/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c new file mode 100644 index 000..ae9834c0bf8 --- /dev/null +++ b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EFUSE_SN_OFFSET20 +#define EFUSE_SN_SIZE 16 +#define EFUSE_MAC_OFFSET 52 +#define EFUSE_MAC_SIZE 6 + +int misc_init_r(void) +{ + u8 mac_addr[EFUSE_MAC_SIZE + 1]; + char serial[EFUSE_SN_SIZE + 1]; + ssize_t len; + + if (!eth_env_get_enetaddr("ethaddr", mac_addr)) { + len = meson_sm_read_efuse(EFUSE_MAC_OFFSET, + mac_addr, EFUSE_MAC_SIZE); + mac_addr[len] = '\0'; + if (len == EFUSE_MAC_SIZE && is_valid_ethaddr(mac_addr)) + eth_env_set_enetaddr("ethaddr", mac_addr); + else + meson_generate_serial_ethaddr(); + } + + if (!env_get("serial#")) { + len = meson_sm_read_efuse(EFUSE_SN_OFFSET, serial, + EFUSE_SN_SIZE); + serial[len] = '\0'; + if (len == EFUSE_SN_SIZE) + env_set("serial#", serial); + } + + return 0; +} diff --git a/configs/libretech-ac_defconfig b/configs/libretech-ac_defconfig index 6ad04570022..11d9795e05d 100644 --- a/configs/libretech-ac_defconfig +++ b/configs/libretech-ac_defconfig @@ -1,5 +1,7 @@ CONFIG_ARM=y CONFIG_SYS_CONFIG_NAME="libretech-ac" +CONFIG_SYS_VENDOR="libre-computer" +CONFIG_SYS_BOARD="aml-s805x-ac" CONFIG_ARCH_MESON=y CONFIG_TEXT_BASE=0x0100 CONFIG_NR_DRAM_BANKS=1 -- 2.34.1
[PATCH v2 0/2] ARM: meson: libretech-ac: add support for EFI Capsules Update
The necessary changes were made in U-Boot to easily support EFI Capsules Update and be compliant with Arm SystemReady IR. Let's add support for the libretech-ac/AML-S805X-CC since it's an easy well-supported target having a dedicated SPI Flash to store U-Boot. Signed-off-by: Neil Armstrong --- Changes in v2: - Add set_dfu_alt_info() + CONFIG_SET_DFU_ALT_INFO to support both RAM and SF DFU backend - Fix typo in cover letter and commit message - Link to v1: https://lore.kernel.org/r/20240916-u-boot-topic-dynamic-uuid-v1-0-7e4f48542...@linaro.org --- Neil Armstrong (2): board: libretech-ac: move board support into dedicated directory board: libre-computer: aml-s805x-cc: Enable capsule updates board/amlogic/p212/MAINTAINERS | 2 - board/libre-computer/aml-s805x-ac/MAINTAINERS| 8 +++ board/libre-computer/aml-s805x-ac/Makefile | 6 ++ board/libre-computer/aml-s805x-ac/aml-s805x-ac.c | 71 configs/libretech-ac_defconfig | 8 +++ 5 files changed, 93 insertions(+), 2 deletions(-) --- base-commit: df84c019c46e6833cc79385bdb23efba4882c09d change-id: 20240916-u-boot-topic-dynamic-uuid-a871c25236a4 Best regards, -- Neil Armstrong
[PATCH] dfu: sf: rely on DT for spi speed and mode
Align with cmd_sf, and try to rely on DT for spi speed and mode, and still fallback on spi_flash_probe() if it fails. With the current scheme, spi_flash_probe() will be called with CONFIG_SF_DEFAULT_SPEED and CONFIG_SF_DEFAULT_MODE with are set to 0 by default on DT platforms using DM_SPI_FLASH. Like cmd_sf, keep the option to specify the speed and mode from the dfu_alt_mode string, but rely on DT properties if not specified. Using CONFIG_SF_DEFAULT_SPEED and CONFIG_SF_DEFAULT_MODE makes the SPIFC controller on Amlogic Meson G12B & SM1 hardware fail and is unable to recover until a system reboot. Signed-off-by: Neil Armstrong --- drivers/dfu/dfu_sf.c | 22 ++ 1 file changed, 22 insertions(+) diff --git a/drivers/dfu/dfu_sf.c b/drivers/dfu/dfu_sf.c index 7c1c0f9e2dc..b5d875be5ea 100644 --- a/drivers/dfu/dfu_sf.c +++ b/drivers/dfu/dfu_sf.c @@ -123,6 +123,9 @@ static struct spi_flash *parse_dev(char *devstr) unsigned int mode = CONFIG_SF_DEFAULT_MODE; char *s, *endp; struct spi_flash *dev; +#if CONFIG_IS_ENABLED(DM_SPI_FLASH) + bool use_dt = true; +#endif s = strsep(&devstr, ":"); if (!s || !*s || (bus = simple_strtoul(s, &endp, 0), *endp)) { @@ -143,6 +146,9 @@ static struct spi_flash *parse_dev(char *devstr) printf("Invalid SPI speed %s\n", s); return NULL; } +#if CONFIG_IS_ENABLED(DM_SPI_FLASH) + use_dt = false; +#endif } s = strsep(&devstr, ":"); @@ -152,9 +158,25 @@ static struct spi_flash *parse_dev(char *devstr) printf("Invalid SPI mode %s\n", s); return NULL; } +#if CONFIG_IS_ENABLED(DM_SPI_FLASH) + use_dt = false; +#endif } +#if CONFIG_IS_ENABLED(DM_SPI_FLASH) + if (use_dt) { + struct udevice *new; + + if (!spi_flash_probe_bus_cs(bus, cs, &new)) + dev = dev_get_uclass_priv(new); + else + dev = NULL; + } else { + dev = spi_flash_probe(bus, cs, speed, mode); + } +#else dev = spi_flash_probe(bus, cs, speed, mode); +#endif if (!dev) { printf("Failed to create SPI flash at %u:%u:%u:%u\n", bus, cs, speed, mode); --- base-commit: 19dbc09405d3503ce3efef3c2e4b4f0f1a03372d change-id: 20240917-uboot-topic-dfu-sf-dt-8ae62e5c7d79 Best regards, -- Neil Armstrong
Re: [PATCH 0/2] ARM: meson: libretech-ac: add suppor for EFI Capsules Update
On 16/09/2024 18:29, Tom Rini wrote: On Mon, Sep 16, 2024 at 11:41:47AM +0200, Neil Armstrong wrote: The necessary changes were made in U-Boot to easily support EFI Capsules Update and be compliant with Arm SystemReady SR. To be clear, "SR" or "IR" ? I assume you meant IR here. Indeed IR, I'll fix in v2, I need to send a v2 because I need to add set_dfu_alt_info() to keep support for the ram backed dfu I used when booting from USB. Thanks, Neil
[PATCH 1/2] board: libretech-ac: move board support into dedicated directory
The libretech-ac aka aml-s805x-ac supports mainline U-boot from a dedicated SPI flash, move the board support into a dedicated vendor/board subdirectory in order to support vendor specific customization. It also aligns with the vendor downstream changes. Signed-off-by: Neil Armstrong --- board/amlogic/p212/MAINTAINERS | 2 - board/libre-computer/aml-s805x-ac/MAINTAINERS| 8 board/libre-computer/aml-s805x-ac/Makefile | 6 +++ board/libre-computer/aml-s805x-ac/aml-s805x-ac.c | 47 configs/libretech-ac_defconfig | 2 + 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/board/amlogic/p212/MAINTAINERS b/board/amlogic/p212/MAINTAINERS index b2e3205fdf0..e73a4e52c1f 100644 --- a/board/amlogic/p212/MAINTAINERS +++ b/board/amlogic/p212/MAINTAINERS @@ -5,11 +5,9 @@ L: u-boot-amlo...@groups.io F: board/amlogic/p212/ F: include/configs/p212.h F: configs/khadas-vim_defconfig -F: configs/libretech-ac_defconfig F: configs/libretech-cc_defconfig F: configs/libretech-cc_v2_defconfig F: configs/p212_defconfig F: doc/board/amlogic/p212.rst -F: doc/board/amlogic/libretech-ac.rst F: doc/board/amlogic/libretech-cc.rst F: doc/board/amlogic/khadas-vim.rst diff --git a/board/libre-computer/aml-s805x-ac/MAINTAINERS b/board/libre-computer/aml-s805x-ac/MAINTAINERS new file mode 100644 index 000..7cbc08aeb6c --- /dev/null +++ b/board/libre-computer/aml-s805x-ac/MAINTAINERS @@ -0,0 +1,8 @@ +LIBRE-COMPUTER AML-S805X-AC +M: Neil Armstrong +S: Maintained +L: u-boot-amlo...@groups.io +F: board/amlogic/aml-s805x-ac/ +F: include/configs/libretech-ac.h +F: configs/libretech-ac_defconfig +F: doc/board/amlogic/libretech-ac.rst diff --git a/board/libre-computer/aml-s805x-ac/Makefile b/board/libre-computer/aml-s805x-ac/Makefile new file mode 100644 index 000..b4367ea522b --- /dev/null +++ b/board/libre-computer/aml-s805x-ac/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2016 BayLibre, SAS +# Author: Neil Armstrong + +obj-y := aml-s805x-ac.o diff --git a/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c new file mode 100644 index 000..ae9834c0bf8 --- /dev/null +++ b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EFUSE_SN_OFFSET20 +#define EFUSE_SN_SIZE 16 +#define EFUSE_MAC_OFFSET 52 +#define EFUSE_MAC_SIZE 6 + +int misc_init_r(void) +{ + u8 mac_addr[EFUSE_MAC_SIZE + 1]; + char serial[EFUSE_SN_SIZE + 1]; + ssize_t len; + + if (!eth_env_get_enetaddr("ethaddr", mac_addr)) { + len = meson_sm_read_efuse(EFUSE_MAC_OFFSET, + mac_addr, EFUSE_MAC_SIZE); + mac_addr[len] = '\0'; + if (len == EFUSE_MAC_SIZE && is_valid_ethaddr(mac_addr)) + eth_env_set_enetaddr("ethaddr", mac_addr); + else + meson_generate_serial_ethaddr(); + } + + if (!env_get("serial#")) { + len = meson_sm_read_efuse(EFUSE_SN_OFFSET, serial, + EFUSE_SN_SIZE); + serial[len] = '\0'; + if (len == EFUSE_SN_SIZE) + env_set("serial#", serial); + } + + return 0; +} diff --git a/configs/libretech-ac_defconfig b/configs/libretech-ac_defconfig index 6ad04570022..11d9795e05d 100644 --- a/configs/libretech-ac_defconfig +++ b/configs/libretech-ac_defconfig @@ -1,5 +1,7 @@ CONFIG_ARM=y CONFIG_SYS_CONFIG_NAME="libretech-ac" +CONFIG_SYS_VENDOR="libre-computer" +CONFIG_SYS_BOARD="aml-s805x-ac" CONFIG_ARCH_MESON=y CONFIG_TEXT_BASE=0x0100 CONFIG_NR_DRAM_BANKS=1 -- 2.34.1
[PATCH 2/2] board: libre-computer: aml-s805-cc: Enable capsule updates
Since the aml-s805-cc works well using EFI, and now the capsule updates backend has been merged, let's enable the missing configs and add the required structures to support it. The GUID is dynamically generated for the board, to get it: => efidebug capsule esrt ESRT: fw_resource_count=1 ESRT: fw_resource_count_max=1 ESRT: fw_resource_version=1 [entry 0]== ESRT: fw_class=B8079027-9B2C-57D4-86AA-CC782ADA598C ESRT: fw_type=unknown ESRT: fw_version=0 ESRT: lowest_supported_fw_version=0 ESRT: capsule_flags=0 ESRT: last_attempt_version=0 ESRT: last_attempt_status=success On the host (with the aml_encrypt_gxl result binary): $ eficapsule --guid B8079027-9B2C-57D4-86AA-CC782ADA598C -i 1 u-boot.bin u-boot.cap On the board (from USB disk containing u-boot.cap at root): => load usb 0:1 $kernel_addr_r u-boot.cap => efidebug capsule update $kernel_addr_r The binary will then be flashed on the SPI. Signed-off-by: Neil Armstrong --- board/libre-computer/aml-s805x-ac/aml-s805x-ac.c | 14 ++ configs/libretech-ac_defconfig | 5 + 2 files changed, 19 insertions(+) diff --git a/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c index ae9834c0bf8..ba14df54967 100644 --- a/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c +++ b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,19 @@ #define EFUSE_MAC_OFFSET 52 #define EFUSE_MAC_SIZE 6 +struct efi_fw_image fw_images[] = { + { + .fw_name = u"AML_S805X_AC_BOOT", + .image_index = 1, + }, +}; + +struct efi_capsule_update_info update_info = { + .dfu_string = "sf 0:0=u-boot-bin raw 0 0x1", + .num_images = ARRAY_SIZE(fw_images), + .images = fw_images, +}; + int misc_init_r(void) { u8 mac_addr[EFUSE_MAC_SIZE + 1]; diff --git a/configs/libretech-ac_defconfig b/configs/libretech-ac_defconfig index 11d9795e05d..f146a495654 100644 --- a/configs/libretech-ac_defconfig +++ b/configs/libretech-ac_defconfig @@ -35,6 +35,7 @@ CONFIG_SYS_MAXARGS=32 # CONFIG_CMD_IMI is not set CONFIG_CMD_ADC=y CONFIG_CMD_DFU=y +CONFIG_CMD_NVEDIT_EFI=y CONFIG_CMD_GPIO=y # CONFIG_CMD_LOADS is not set CONFIG_CMD_MMC=y @@ -42,6 +43,7 @@ CONFIG_CMD_SF_TEST=y CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_EFIDEBUG=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_REGULATOR=y CONFIG_OF_CONTROL=y @@ -49,6 +51,7 @@ CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_SARADC_MESON=y CONFIG_DFU_RAM=y +CONFIG_DFU_SF=y CONFIG_MMC_MESON_GX=y CONFIG_MTD=y CONFIG_DM_MTD=y @@ -98,3 +101,5 @@ CONFIG_VIDEO_BMP_RLE8=y CONFIG_BMP_16BPP=y CONFIG_BMP_24BPP=y CONFIG_BMP_32BPP=y +CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y -- 2.34.1
[PATCH 0/2] ARM: meson: libretech-ac: add suppor for EFI Capsules Update
The necessary changes were made in U-Boot to easily support EFI Capsules Update and be compliant with Arm SystemReady SR. Let's add support for the libretech-ac/AML-S805X-CC since it's an easy well-supported target having a dedicated SPI Flash to store U-Boot. Signed-off-by: Neil Armstrong --- Neil Armstrong (2): board: libretech-ac: move board support into dedicated directory board: libre-computer: aml-s805-cc: Enable capsule updates board/amlogic/p212/MAINTAINERS | 2 - board/libre-computer/aml-s805x-ac/MAINTAINERS| 8 board/libre-computer/aml-s805x-ac/Makefile | 6 +++ board/libre-computer/aml-s805x-ac/aml-s805x-ac.c | 61 configs/libretech-ac_defconfig | 7 +++ 5 files changed, 82 insertions(+), 2 deletions(-) --- base-commit: df84c019c46e6833cc79385bdb23efba4882c09d change-id: 20240916-u-boot-topic-dynamic-uuid-a871c25236a4 Best regards, -- Neil Armstrong
Re: Assistance Required: U-Boot Access Issues on Amlogic A113X SoC
Hi Mike, On 06/09/2024 19:00, Mike wrote: Dear U-Boot Community, I am working on a project involving the Amlogic A113X SoC and have encountered an issue with U-Boot during the boot process over UART. While I am able to connect via UART and observe the boot log, the system does not allow any interaction or command input. It seems that the manufacturer may have restricted this access, potentially violating the GNU GPL license. It surely does, it's quite common in embedded, they do not want you to change the software running on the device even if the License allows you to. Here are the details: - *SoC:* Amlogic A113X Good news, this device is very well supported on the mainline U-boot branch ;-) => https://linux-meson.com/u-boot.html => https://docs.u-boot.org/en/latest/board/amlogic/index.html Neil - *Bootloader:* U-Boot 2015.01 (Jan 13 2023 - 10:30:19) - *Issue:* The device does not respond to input during the boot process over UART (no response to Ctrl+C, Enter, etc.) - *UART Log:* AXG:BL1:d1dbf2:a4926f;FEAT:F0DC31BC:2000;POC:F;EMMC:800;NAND:0;READ:0;0.0;0.0;CHK:0; sdio debug board detected TE: 139689 BL2 Built : 10:38:43, Apr 14 2020. axg gf27ed33 - jenkins@walle02-sh set vcck to 1100 mv set vddee to 950 mv Board ID = 3 CPU clk: 1200MHz DDR low power enabled DDR3 chl: Rank0 16bit @ 912MHz bist_test rank: 0 1c 07 32 26 10 3c 1e 06 36 27 10 3f 00 00 00 00 00 00 00 00 00 00 00 00 772 - PASS Rank0: 256MB(auto)-2T-13 AddrBus test pass! NAND init Load FIP HDR from NAND, src: 0xc000, des: 0x0170, size: 0x4000, part: 0 Load BL3x from NAND, src: 0x0001, des: 0x01704000, size: 0x000b7c00, part: 0 NOTICE: BL31: v1.3(release):3edeb02 NOTICE: BL31: Built : 16:43:54, Apr 14 2020 NOTICE: BL31: AXG secure boot! NOTICE: BL31: BL33 decompress pass OPS=0x43 [Image: axg_v1.1.3494-9ec8345 2020-04-17 18:16:39 jenkins@walle02-sh] 25 0c 43 00 c3 ac bf b3 9f 7a e1 5b 3a 07 57 99 bl30:axg ver: 9 mode: 0 bl30:axg thermal0 [0.015883 Inits done] secure task start! high task start! low task start! ERROR: Error initializing runtime service opteed_fast U-Boot 2015.01 (Jan 13 2023 - 10:30:19) DRAM: 256 MiB Relocation Offset is: 0eeb mmu cfg end: 0x2000 mmu cfg end: 0x2000 register usb cfg[0][1] = 0ff6e198 aml_i2c_init_port init regs for 2 NAND: get_sys_clk_rate_mtd() 292, clock setting 200! bus cycle0: 6,timing: 7 NAND device id: 98 da 90 15 76 16 NAND device: Manufacturer ID: 0x98, Chip ID: 0x98 (Toshiba A revision NAND 2Gib TC58NVG1S3HBAI4 ) get_sys_clk_rate_mtd() 292, clock setting 200! m3_nand_adjust_timing() sys_clk_rate 200, bus_c 6, bus_t 7 oob_fill_cnt =32 oob_size =64, bch_bytes =14 ecc mode:6 ecc_page_num=2 eep_need_oobsize=16 plane_num=1 writesize=0x800 ecc.size=0x200 bch_mode=1 oob avail size 6 Creating 1 MTD partitions on "A revision NAND 2Gib TC58NVG1S3HBAI4 ": 0x-0x0020 : "bootloader" A revision NAND 2Gib TC58NVG1S3HBAI4 initialized ok get_sys_clk_rate_mtd() 292, clock setting 200! bus cycle0: 6,timing: 7 NAND device id: 98 da 90 15 76 16 NAND device: Manufacturer ID: 0x98, Chip ID: 0x98 (Toshiba A revision NAND 2Gib TC58NVG1S3HBAI4 ) get_sys_clk_rate_mtd() 292, clock setting 200! m3_nand_adjust_timing() sys_clk_rate 200, bus_c 6, bus_t 7 oob_fill_cnt =32 oob_size =64, bch_bytes =14 ecc mode:6 ecc_page_num=2 eep_need_oobsize=16 PLANE change! plane_num=1 writesize=0x800 ecc.size=0x200 bch_mode=1 aml_nand_init :oobmul=1,oobfree.length=8, - oob_size=64 oob avail size 8 nbbt=20 nenv=24 nkey=32 ndtb=40 nddr=44 bbt_start=20 env_start=24 key_start=32 dtb_start=40 ddr_start=44 nbbt: info size=0x800 max_scan_blk=24, start_blk=20 nbbt : phy_blk_addr=20, ec=0, phy_page_addr=0, timestamp=1 nbbt free list: blockN=21, ec=-1, dirty_flag=0 blockN=22, ec=-1, dirty_flag=0 blockN=23, ec=-1, dirty_flag=0 aml_nand_scan_rsv_info 1134: page_num=1 aml_nand_scan_rsv_info 1137 nbbt valid addr: 28 aml_nand_bbt_check 1258 bbt is valid, reading. aml_nand_read_rsv_info:446,read nbbt info to 28 nenv: info size=0x1 max_scan_blk=32, start_blk=24 nenv : phy_blk_addr=24, ec=0, phy_page_addr=0, timestamp=5 nenv free list: blockN=25, ec=0, dirty_flag=1 blockN=26, ec=-1, dirty_flag=0 blockN=27, ec=-1, dirty_flag=0 blockN=28, ec=-1, dirty_flag=0 blockN=29, ec=-1, dirty_flag=0 blockN=30, ec=-1, dirty_flag=0 blockN=31, ec=-1, dirty_flag=0 aml_nand_scan_rsv_info 1134: page_num=32 aml_nand_scan_rsv_info 1137 nenv valid addr: 31 nkey: info size=0x8000 max_scan_blk=40, start_blk=32 nkey : phy_blk_addr=33, ec=0, phy_page_addr=0, timestamp=2 nkey fr
[PATCH v2 2/2] pinctr: qcom: sm8250: add special pins pins configuration data
Add the special pins configuration data to allow setup the bias of the UFS and SDCard pins on the SM8250 SoC. Signed-off-by: Neil Armstrong --- drivers/pinctrl/qcom/pinctrl-sm8250.c | 42 +++ 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250.c b/drivers/pinctrl/qcom/pinctrl-sm8250.c index dac24f11bc2..cab42fa64ed 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8250.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8250.c @@ -18,8 +18,37 @@ static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); static const struct pinctrl_function msm_pinctrl_functions[] = { { "qup12", 1 }, -{ "gpio", 0 }, -{ "sdc2_clk", 0 } }; +{ "gpio", 0 }, }; +#define SDC_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = pg_name,\ + .ctl_reg = ctl, \ + .io_reg = 0,\ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = pg_name,\ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +static const struct msm_special_pin_data sm8250_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", SOUTH + 0xb8000), + [1] = SDC_PINGROUP("sdc2_clk", NORTH + 0xb7000, 14, 6), + [2] = SDC_PINGROUP("sdc2_cmd", NORTH + 0xb7000, 11, 3), + [3] = SDC_PINGROUP("sdc2_data", NORTH + 0xb7000, 9, 0), +}; static const unsigned int sm8250_pin_offsets[] = { [0] = SOUTH, [1] = SOUTH, [2] = SOUTH, [3] = SOUTH, [4] = NORTH, [5] = NORTH, @@ -52,7 +81,6 @@ static const unsigned int sm8250_pin_offsets[] = { [162] = WEST, [163] = WEST, [164] = WEST, [165] = WEST, [166] = WEST, [167] = WEST, [168] = WEST, [169] = WEST, [170] = WEST, [171] = WEST, [172] = WEST, [173] = WEST, [174] = WEST, [175] = WEST, [176] = WEST, [177] = WEST, [178] = WEST, [179] = WEST, - [180] = 0, [181] = 0, [182] = 0, [183] = 0, }; static const char *sm8250_get_function_name(struct udevice *dev, unsigned int selector) @@ -62,7 +90,12 @@ static const char *sm8250_get_function_name(struct udevice *dev, unsigned int se static const char *sm8250_get_pin_name(struct udevice *dev, unsigned int selector) { - snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + if (selector >= 180 && selector <= 183) + snprintf(pin_name, MAX_PIN_NAME_LEN, +sm8250_special_pins_data[selector - 180].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + return pin_name; } @@ -76,6 +109,7 @@ static struct msm_pinctrl_data sm8250_data = { .pin_offsets = sm8250_pin_offsets, .pin_count = ARRAY_SIZE(sm8250_pin_offsets), .special_pins_start = 180, + .special_pins_data = sm8250_special_pins_data, }, .functions_count = ARRAY_SIZE(msm_pinctrl_functions), .get_function_name = sm8250_get_function_name, -- 2.34.1
[PATCH v2 1/2] gpio: msm: add support for special pins
Leverage the data introduced in the struct msm_special_pin_data to allow setting the gpio direction and value if supported by the pin data. Signed-off-by: Neil Armstrong --- drivers/gpio/msm_gpio.c | 97 + 1 file changed, 89 insertions(+), 8 deletions(-) diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c index 2fb266f1285..cea073b3297 100644 --- a/drivers/gpio/msm_gpio.c +++ b/drivers/gpio/msm_gpio.c @@ -34,13 +34,31 @@ struct msm_gpio_bank { #define GPIO_IN_OUT_REG(dev, x) \ (GPIO_CONFIG_REG(dev, x) + 0x4) +static void msm_gpio_direction_input_special(struct msm_gpio_bank *priv, +unsigned int gpio) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return; + + data = &priv->pin_data->special_pins_data[offset]; + + if (!data->ctl_reg || data->oe_bit >= 31) + return; + + /* switch direction */ + clrsetbits_le32(priv->base + data->ctl_reg, + BIT(data->oe_bit), 0); +} + static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio) { struct msm_gpio_bank *priv = dev_get_priv(dev); - /* Always NOP for special pins, assume they're in the correct state */ if (qcom_is_special_pin(priv->pin_data, gpio)) - return; + msm_gpio_direction_input_special(priv, gpio); /* Disable OE bit */ clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio), @@ -49,13 +67,33 @@ static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio) return; } +static int msm_gpio_set_value_special(struct msm_gpio_bank *priv, + unsigned int gpio, int value) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return 0; + + data = &priv->pin_data->special_pins_data[offset]; + + if (!data->io_reg || data->out_bit >= 31) + return 0; + + value = !!value; + /* set value */ + writel(value << data->out_bit, priv->base + data->io_reg); + + return 0; +} + static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value) { struct msm_gpio_bank *priv = dev_get_priv(dev); - /* Always NOP for special pins, assume they're in the correct state */ if (qcom_is_special_pin(priv->pin_data, gpio)) - return 0; + return msm_gpio_set_value_special(priv, gpio, value); value = !!value; /* set value */ @@ -64,14 +102,42 @@ static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value) return 0; } +static int msm_gpio_direction_output_special(struct msm_gpio_bank *priv, +unsigned int gpio, +int value) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return 0; + + data = &priv->pin_data->special_pins_data[offset]; + + if (!data->io_reg || data->out_bit >= 31) + return 0; + + value = !!value; + /* set value */ + writel(value << data->out_bit, priv->base + data->io_reg); + + if (!data->ctl_reg || data->oe_bit >= 31) + return 0; + + /* switch direction */ + clrsetbits_le32(priv->base + data->ctl_reg, + BIT(data->oe_bit), BIT(data->oe_bit)); + + return 0; +} + static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio, int value) { struct msm_gpio_bank *priv = dev_get_priv(dev); - /* Always NOP for special pins, assume they're in the correct state */ if (qcom_is_special_pin(priv->pin_data, gpio)) - return 0; + return msm_gpio_direction_output_special(priv, gpio, value); value = !!value; /* set value */ @@ -100,13 +166,28 @@ static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flag return 0; } +static int msm_gpio_get_value_special(struct msm_gpio_bank *priv, unsigned int gpio) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return 0; + + data = &priv->pin_data->special_pins_data[offse
[PATCH v2 0/2] qcom: allow msm_gpio to set special pins direction & value
After struct msm_special_pin_data was introduced in [1], use the data to setup the pin direction and/or value if supported by the pin data. Add the proper msm_special_pin_data for sm8250 after sm8550 and sm8650. [1] https://lore.kernel.org/all/20240528-topic-sm8x50-pinctrl-pinconf-v1-0-54d1e9ad7...@linaro.org/ Signed-off-by: Neil Armstrong --- Changes in v2: - dropped last line of sm8250_pin_offsets - Link to v1: https://lore.kernel.org/r/20240910-topic-sm8x50-msm-gpio-special-pins-sm8250-v1-0-50623a7e4...@linaro.org --- Neil Armstrong (2): gpio: msm: add support for special pins pinctr: qcom: sm8250: add special pins pins configuration data drivers/gpio/msm_gpio.c | 97 --- drivers/pinctrl/qcom/pinctrl-sm8250.c | 42 +-- 2 files changed, 127 insertions(+), 12 deletions(-) --- base-commit: ca55cf8104c0dd78aae45fa66dd8400ef1b3d0ac change-id: 20240910-topic-sm8x50-msm-gpio-special-pins-sm8250-943311b483e2 Best regards, -- Neil Armstrong
Re: [PATCH v3 2/3] pinctrl: qcom: add driver for SM8150 SoC
T, [106] = WEST, [107] = WEST, + [108] = WEST, [109] = WEST, [110] = WEST, [111] = WEST, + [112] = WEST, [113] = WEST, [114] = SOUTH, [115] = SOUTH, + [116] = SOUTH, [117] = SOUTH, [118] = SOUTH, [119] = SOUTH, + [120] = SOUTH, [121] = SOUTH, [122] = SOUTH, [123] = SOUTH, + [124] = SOUTH, [125] = WEST, [126] = SOUTH, [127] = SOUTH, + [128] = SOUTH, [129] = SOUTH, [130] = SOUTH, [131] = SOUTH, + [132] = SOUTH, [133] = SOUTH, [134] = SOUTH, [135] = SOUTH, + [136] = SOUTH, [137] = SOUTH, [138] = SOUTH, [139] = SOUTH, + [140] = SOUTH, [141] = SOUTH, [142] = SOUTH, [143] = SOUTH, + [144] = SOUTH, [145] = SOUTH, [146] = SOUTH, [147] = SOUTH, + [148] = SOUTH, [149] = SOUTH, [150] = SOUTH, [151] = SOUTH, + [152] = SOUTH, [153] = SOUTH, [154] = SOUTH, [155] = WEST, + [156] = WEST, [157] = WEST, [158] = WEST, [159] = WEST, + [160] = WEST, [161] = WEST, [162] = WEST, [163] = WEST, + [164] = WEST, [165] = WEST, [166] = WEST, [167] = WEST, + [168] = WEST, [169] = NORTH, [170] = NORTH, [171] = NORTH, + [172] = NORTH, [173] = NORTH, [174] = NORTH, +}; + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = pg_name,\ + .ctl_reg = ctl, \ + .io_reg = 0,\ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + } + +#define UFS_RESET(pg_name, offset)\ + { \ + .name = pg_name, \ + .ctl_reg = offset,\ + .io_reg = offset + 0x04, \ + .pull_bit = 3,\ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +static const struct msm_special_pin_data msm_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", SOUTH + 0xb6000), + [1] = SDC_QDSD_PINGROUP("sdc2_clk", NORTH + 0xb2000, 14, 6), + [2] = SDC_QDSD_PINGROUP("sdc2_cmd", NORTH + 0xb2000, 11, 3), + [3] = SDC_QDSD_PINGROUP("sdc2_data", NORTH + 0xb2000, 9, 0), +}; + +static const char *sm8150_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *sm8150_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= 175 && selector <= 178) + snprintf(pin_name, MAX_PIN_NAME_LEN, +msm_special_pins_data[selector - 175].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static unsigned int sm8150_get_function_mux(__maybe_unused unsigned int pin, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].val; +} + +static struct msm_pinctrl_data sm8150_data = { + .pin_data = { + .pin_offsets = sm8150_pin_offsets, + .pin_count = 179, + .special_pins_start = 175, + .special_pins_data = msm_special_pins_data, + }, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = sm8150_get_function_name, + .get_function_mux = sm8150_get_function_mux, + .get_pin_name = sm8150_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,sm8150-pinctrl", .data = (ulong)&sm8150_data }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(pinctrl_sm8150) = { + .name = "pinctrl_sm8150", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops= &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, +}; Reviewed-by: Neil Armstrong
Re: [PATCH v3 3/3] config: qcom: add sm8150 to qcom_defconfig
On 11/09/2024 19:13, Julius Lehmann wrote: Enable clk and pinctrl for sm8150 Signed-off-by: Julius Lehmann Reviewed-by: Caleb Connolly --- configs/qcom_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index 2a2253f766..e7ed03ff0f 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -48,6 +48,7 @@ CONFIG_CLK_QCOM_QCS404=y CONFIG_CLK_QCOM_SC7280=y CONFIG_CLK_QCOM_SDM845=y CONFIG_CLK_QCOM_SM6115=y +CONFIG_CLK_QCOM_SM8150=y CONFIG_CLK_QCOM_SM8250=y CONFIG_CLK_QCOM_SM8550=y CONFIG_CLK_QCOM_SM8650=y @@ -86,6 +87,7 @@ CONFIG_PINCTRL_QCOM_QCM2290=y CONFIG_PINCTRL_QCOM_QCS404=y CONFIG_PINCTRL_QCOM_SDM845=y CONFIG_PINCTRL_QCOM_SM6115=y +CONFIG_PINCTRL_QCOM_SM8150=y CONFIG_PINCTRL_QCOM_SM8250=y CONFIG_PINCTRL_QCOM_SM8550=y CONFIG_PINCTRL_QCOM_SM8650=y Reviewed-by: Neil Armstrong
Re: [PATCH v3 1/3] clk: qcom: add driver for SM8150 SoC
qcom_gate_clk_en(priv, GCC_USB3_SEC_PHY_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_SEC_PHY_COM_AUX_CLK); + break; + }; + + qcom_gate_clk_en(priv, clk->id); + + return 0; +} + +static const struct qcom_reset_map sm8150_gcc_resets[] = { + [GCC_EMAC_BCR] = { 0x6000 }, + [GCC_GPU_BCR] = { 0x71000 }, + [GCC_MMSS_BCR] = { 0xb000 }, + [GCC_NPU_BCR] = { 0x4d000 }, + [GCC_PCIE_0_BCR] = { 0x6b000 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_1_BCR] = { 0x8d000 }, + [GCC_PCIE_1_PHY_BCR] = { 0x8e01c }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PDM_BCR] = { 0x33000 }, + [GCC_PRNG_BCR] = { 0x34000 }, + [GCC_QSPI_BCR] = { 0x24008 }, + [GCC_QUPV3_WRAPPER_0_BCR] = { 0x17000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 }, + [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x5 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x5000c }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x50010 }, + [GCC_SDCC2_BCR] = { 0x14000 }, + [GCC_SDCC4_BCR] = { 0x16000 }, + [GCC_TSIF_BCR] = { 0x36000 }, + [GCC_UFS_CARD_BCR] = { 0x75000 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB30_PRIM_BCR] = { 0xf000 }, + [GCC_USB30_SEC_BCR] = { 0x1 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, +}; + +static const struct qcom_power_map sm8150_gcc_power_domains[] = { + [EMAC_GDSC] = { 0x6004 }, + [PCIE_0_GDSC] = { 0x6b004 }, + [PCIE_1_GDSC] = { 0x8d004 }, + [UFS_CARD_GDSC] = { 0x75004 }, + [UFS_PHY_GDSC] = { 0x77004 }, + [USB30_PRIM_GDSC] = { 0xf004 }, + [USB30_SEC_GDSC] = { 0x10004 }, +}; + +static struct msm_clk_data sm8150_clk_data = { + .resets = sm8150_gcc_resets, + .num_resets = ARRAY_SIZE(sm8150_gcc_resets), + .clks = sm8150_clks, + .num_clks = ARRAY_SIZE(sm8150_clks), + .power_domains = sm8150_gcc_power_domains, + .num_power_domains = ARRAY_SIZE(sm8150_gcc_power_domains), + + .enable = sm8150_clk_enable, + .set_rate = sm8150_clk_set_rate, +}; + +static const struct udevice_id gcc_sm8150_of_match[] = { + { + .compatible = "qcom,gcc-sm8150", + .data = (ulong)&sm8150_clk_data, + }, + { } +}; + +U_BOOT_DRIVER(gcc_sm8150) = { + .name = "gcc_sm8150", + .id = UCLASS_NOP, + .of_match = gcc_sm8150_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC, +}; Reviewed-by: Neil Armstrong
Re: [PATCH 2/3] pinctrl: qcom: add driver for SM8150 SoC
On 10/09/2024 18:01, Julius Lehmann wrote: Hi Neil and Caleb, thank you for taking a look at my patch. On 10.09.24 14:07, Neil Armstrong wrote: On 10/09/2024 14:05, Caleb Connolly wrote: Hi Julius, Thanks for the patch! On 09/09/2024 17:53, Julius Lehmann wrote: Add pinctrl and GPIO driver for SM8150. Driver code is based on the similar U-Boot drivers. All constants are taken from the corresponding Linux driver. This drivers differs from the similar U-Boot drivers, because SM8150 SoC have different function IDs for the same functions on different pins. Co-authored-by: Volodymyr Babchuk Signed-off-by: Julius Lehmann --- drivers/pinctrl/qcom/Kconfig | 8 ++ drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-sm8150.c | 119 ++ 3 files changed, 128 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-sm8150.c diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index b326fa8514..501939f783 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -74,6 +74,14 @@ config PINCTRL_QCOM_SM8650 select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SM8650 SoC, + as well as the associated GPIO driver. + +config PINCTRL_QCOM_SM8150 + bool "Qualcomm SM8150 GCC" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon SM8150 SoC, + as well as the associated GPIO driver. endmenu diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 4f1d96787b..cc3660a576 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o obj-$(CONFIG_PINCTRL_QCOM_SM8250) += pinctrl-sm8250.o obj-$(CONFIG_PINCTRL_QCOM_SM8550) += pinctrl-sm8550.o obj-$(CONFIG_PINCTRL_QCOM_SM8650) += pinctrl-sm8650.o +obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c new file mode 100644 index 00..c3af3448f6 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm8150.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Qualcomm SM8150 pinctrl and GPIO driver + * + * Volodymyr Babchuk + * Copyright (c) 2024 EPAM Systems. + * + * (C) Copyright 2024 Julius Lehmann + * + * Based on similar U-Boot drivers. Constants were taken from the Linux driver + */ + +#include + +#include "pinctrl-qcom.h" + +#define WEST 0x0010 +#define EAST 0x0050 +#define NORTH 0x0090 +#define SOUTH 0x00D0 + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +static const struct pinctrl_function msm_pinctrl_functions[] = { { "qup2", 1 }, + { "gpio", 0 }, + { "sdc4", 0 } }; + +static const unsigned int sm8150_pin_offsets[] = { + [0] = SOUTH, [1] = SOUTH, [2] = SOUTH, [3] = SOUTH, + [4] = SOUTH, [5] = SOUTH, [6] = SOUTH, [7] = SOUTH, + [8] = NORTH, [9] = NORTH, [10] = NORTH, [11] = NORTH, + [12] = NORTH, [13] = NORTH, [14] = NORTH, [15] = NORTH, + [16] = NORTH, [17] = NORTH, [18] = NORTH, [19] = NORTH, + [20] = NORTH, [21] = EAST, [22] = EAST, [23] = EAST, + [24] = EAST, [25] = EAST, [26] = EAST, [27] = EAST, + [28] = EAST, [29] = EAST, [30] = EAST, [31] = NORTH, + [32] = NORTH, [33] = NORTH, [34] = NORTH, [35] = NORTH, + [36] = NORTH, [37] = NORTH, [38] = SOUTH, [39] = NORTH, + [40] = NORTH, [41] = NORTH, [42] = NORTH, [43] = EAST, + [44] = EAST, [45] = EAST, [46] = EAST, [47] = EAST, + [48] = EAST, [49] = EAST, [50] = EAST, [51] = SOUTH, + [52] = SOUTH, [53] = SOUTH, [54] = SOUTH, [55] = SOUTH, + [56] = SOUTH, [57] = SOUTH, [58] = SOUTH, [59] = SOUTH, + [60] = SOUTH, [61] = SOUTH, [62] = SOUTH, [63] = SOUTH, + [64] = SOUTH, [65] = SOUTH, [66] = SOUTH, [67] = SOUTH, + [68] = SOUTH, [69] = SOUTH, [70] = SOUTH, [71] = SOUTH, + [72] = SOUTH, [73] = SOUTH, [74] = SOUTH, [75] = SOUTH, + [76] = SOUTH, [77] = SOUTH, [78] = SOUTH, [79] = SOUTH, + [80] = SOUTH, [81] = SOUTH, [82] = SOUTH, [83] = NORTH, + [84] = NORTH, [85] = NORTH, [86] = NORTH, [87] = EAST, + [88] = NORTH, [89] = NORTH, [90] = NORTH, [91] = NORTH, + [92] = NORTH, [93] = NORTH, [94] = NORTH, [95] = NORTH, + [96] = NORTH, [97] = NORTH, [98] = SOUTH, [99] = SOUTH, + [100] = SOUTH, [101] = SOUTH, [102] = NORTH, [103] = NORTH, + [104] = NORTH, [105] = WEST, [106] = WEST, [107] = WEST, + [108] = WEST, [109] = WEST, [110] = WEST, [111] = WEST, + [112] = WEST, [113] = WEST, [114] = SOUTH, [115] = SOUTH, + [116] = SOUTH, [117] = SOUTH, [118] = SOUTH, [119] = S
Re: [PATCH 12/13] ufs: core: remove link_startup_again logic
Hi, On 10/09/2024 13:36, Neha Malcom Francis wrote: Hi Neil On 10/09/24 14:50, Neil Armstrong wrote: The link_startup_again logic was added in Linux to handle device that were set in LinkDown state, which should not be the case since U-boot doesn't set LinkDown state are init, and Linux sets the device active in ufshcd_init() for the first link startup. While it worked to far, it breaks link startup for Qualcomm Controllers v5, let's just remove the logic. Signed-off-by: Neil Armstrong I had sent a review comment here https://patchwork.ozlabs.org/project/uboot/patch/20240528-topic-sm8x50-ufs-core-link-startup-again-v1-1-146ca43e8...@linaro.org/ Indeed I missed it, I'll fix the commit msg. Nevertheless, as I explain in the cover letter the double link startup is not done in Linux for the initial power-up: https://elixir.bootlin.com/linux/v6.10.9/source/drivers/ufs/core/ufshcd.c#L10548 ufshcd_set_ufs_dev_active(hba) is called at ufshcd_init() right before scheduling an ufshcd_async_scan that will call ufshcd_device_init() then ufshcd_link_startup(). The comment in probe says: /* * We are assuming that device wasn't put in sleep/power-down * state exclusively during the boot stage before kernel. * This assumption helps avoid doing link startup twice during * ufshcd_probe_hba(). */ we can assume the same from U-boot. Neil Would like Bhupesh to also have a look at this. --- drivers/ufs/ufs.c | 8 1 file changed, 8 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index d2df5c26f76..e34e4586224 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -462,9 +462,7 @@ static int ufshcd_link_startup(struct ufs_hba *hba) { int ret; int retries = DME_LINKSTARTUP_RETRIES; - bool link_startup_again = true; -link_startup: do { ufshcd_ops_link_startup_notify(hba, PRE_CHANGE); @@ -490,12 +488,6 @@ link_startup: /* failed to get the link up... retire */ goto out; - if (link_startup_again) { - link_startup_again = false; - retries = DME_LINKSTARTUP_RETRIES; - goto link_startup; - } - /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */ ufshcd_init_pwr_info(hba);
Re: [PATCH 2/2] pinctr: qcom: sm8250: add special pins pins configuration data
On 10/09/2024 14:14, Caleb Connolly wrote: On 10/09/2024 10:58, Neil Armstrong wrote: Add the special pins configuration data to allow setup the bias of the UFS and SDCard pins on the SM8250 SoC. Signed-off-by: Neil Armstrong --- drivers/pinctrl/qcom/pinctrl-sm8250.c | 41 --- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250.c b/drivers/pinctrl/qcom/pinctrl-sm8250.c index dac24f11bc2..69c907e3868 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8250.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8250.c @@ -18,8 +18,37 @@ static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); static const struct pinctrl_function msm_pinctrl_functions[] = { { "qup12", 1 }, -{ "gpio", 0 }, -{ "sdc2_clk", 0 } }; +{ "gpio", 0 }, }; +#define SDC_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = pg_name,\ + .ctl_reg = ctl, \ + .io_reg = 0,\ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = pg_name,\ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +static const struct msm_special_pin_data sm8250_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", SOUTH + 0xb8000), + [1] = SDC_PINGROUP("sdc2_clk", NORTH + 0xb7000, 14, 6), + [2] = SDC_PINGROUP("sdc2_cmd", NORTH + 0xb7000, 11, 3), + [3] = SDC_PINGROUP("sdc2_data", NORTH + 0xb7000, 9, 0), +}; static const unsigned int sm8250_pin_offsets[] = { Could you also remove the special pin entries at the end of this array? Sure ! Neil Kind regards, [0] = SOUTH, [1] = SOUTH, [2] = SOUTH, [3] = SOUTH, [4] = NORTH, [5] = NORTH, @@ -62,7 +91,12 @@ static const char *sm8250_get_function_name(struct udevice *dev, unsigned int se static const char *sm8250_get_pin_name(struct udevice *dev, unsigned int selector) { - snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + if (selector >= 180 && selector <= 183) + snprintf(pin_name, MAX_PIN_NAME_LEN, +sm8250_special_pins_data[selector - 180].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + return pin_name; } @@ -76,6 +110,7 @@ static struct msm_pinctrl_data sm8250_data = { .pin_offsets = sm8250_pin_offsets, .pin_count = ARRAY_SIZE(sm8250_pin_offsets), .special_pins_start = 180, + .special_pins_data = sm8250_special_pins_data, }, .functions_count = ARRAY_SIZE(msm_pinctrl_functions), .get_function_name = sm8250_get_function_name,
Re: [PATCH 2/3] pinctrl: qcom: add driver for SM8150 SoC
On 10/09/2024 14:05, Caleb Connolly wrote: Hi Julius, Thanks for the patch! On 09/09/2024 17:53, Julius Lehmann wrote: Add pinctrl and GPIO driver for SM8150. Driver code is based on the similar U-Boot drivers. All constants are taken from the corresponding Linux driver. This drivers differs from the similar U-Boot drivers, because SM8150 SoC have different function IDs for the same functions on different pins. Co-authored-by: Volodymyr Babchuk Signed-off-by: Julius Lehmann --- drivers/pinctrl/qcom/Kconfig | 8 ++ drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-sm8150.c | 119 ++ 3 files changed, 128 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-sm8150.c diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index b326fa8514..501939f783 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -74,6 +74,14 @@ config PINCTRL_QCOM_SM8650 select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SM8650 SoC, + as well as the associated GPIO driver. + +config PINCTRL_QCOM_SM8150 + bool "Qualcomm SM8150 GCC" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon SM8150 SoC, + as well as the associated GPIO driver. endmenu diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 4f1d96787b..cc3660a576 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o obj-$(CONFIG_PINCTRL_QCOM_SM8250) += pinctrl-sm8250.o obj-$(CONFIG_PINCTRL_QCOM_SM8550) += pinctrl-sm8550.o obj-$(CONFIG_PINCTRL_QCOM_SM8650) += pinctrl-sm8650.o +obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c new file mode 100644 index 00..c3af3448f6 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm8150.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Qualcomm SM8150 pinctrl and GPIO driver + * + * Volodymyr Babchuk + * Copyright (c) 2024 EPAM Systems. + * + * (C) Copyright 2024 Julius Lehmann + * + * Based on similar U-Boot drivers. Constants were taken from the Linux driver + */ + +#include + +#include "pinctrl-qcom.h" + +#define WEST 0x0010 +#define EAST 0x0050 +#define NORTH 0x0090 +#define SOUTH 0x00D0 + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +static const struct pinctrl_function msm_pinctrl_functions[] = { { "qup2", 1 }, +{ "gpio", 0 }, + { "sdc4", 0 } }; + +static const unsigned int sm8150_pin_offsets[] = { + [0] = SOUTH, [1] = SOUTH, [2] = SOUTH, [3] = SOUTH, + [4] = SOUTH, [5] = SOUTH, [6] = SOUTH, [7] = SOUTH, + [8] = NORTH, [9] = NORTH, [10] = NORTH, [11] = NORTH, + [12] = NORTH, [13] = NORTH, [14] = NORTH, [15] = NORTH, + [16] = NORTH, [17] = NORTH, [18] = NORTH, [19] = NORTH, + [20] = NORTH, [21] = EAST, [22] = EAST, [23] = EAST, + [24] = EAST, [25] = EAST, [26] = EAST, [27] = EAST, + [28] = EAST, [29] = EAST, [30] = EAST, [31] = NORTH, + [32] = NORTH, [33] = NORTH, [34] = NORTH, [35] = NORTH, + [36] = NORTH, [37] = NORTH, [38] = SOUTH, [39] = NORTH, + [40] = NORTH, [41] = NORTH, [42] = NORTH, [43] = EAST, + [44] = EAST, [45] = EAST, [46] = EAST, [47] = EAST, + [48] = EAST, [49] = EAST, [50] = EAST, [51] = SOUTH, + [52] = SOUTH, [53] = SOUTH, [54] = SOUTH, [55] = SOUTH, + [56] = SOUTH, [57] = SOUTH, [58] = SOUTH, [59] = SOUTH, + [60] = SOUTH, [61] = SOUTH, [62] = SOUTH, [63] = SOUTH, + [64] = SOUTH, [65] = SOUTH, [66] = SOUTH, [67] = SOUTH, + [68] = SOUTH, [69] = SOUTH, [70] = SOUTH, [71] = SOUTH, + [72] = SOUTH, [73] = SOUTH, [74] = SOUTH, [75] = SOUTH, + [76] = SOUTH, [77] = SOUTH, [78] = SOUTH, [79] = SOUTH, + [80] = SOUTH, [81] = SOUTH, [82] = SOUTH, [83] = NORTH, + [84] = NORTH, [85] = NORTH, [86] = NORTH, [87] = EAST, + [88] = NORTH, [89] = NORTH, [90] = NORTH, [91] = NORTH, + [92] = NORTH, [93] = NORTH, [94] = NORTH, [95] = NORTH, + [96] = NORTH, [97] = NORTH, [98] = SOUTH, [99] = SOUTH, + [100] = SOUTH, [101] = SOUTH, [102] = NORTH, [103] = NORTH, + [104] = NORTH, [105] = WEST, [106] = WEST, [107] = WEST, + [108] = WEST, [109] = WEST, [110] = WEST, [111] = WEST, + [112] = WEST, [113] = WEST, [114] = SOUTH, [115] = SOUTH, + [116] = SOUTH, [117] = SOUTH, [118] = SOUTH, [119] = SOUTH, + [120] = SOUTH, [121] = SOUT
[PATCH 0/4] ufs: add support for Qualcomm UFS Controller
This iass Add Support for the Host Controller driver for UFS HC present on Qualcomm Snapdragon SoCs. It adds 2 ops to allow more control on the UFS device. It has been successfully tested on SDM845, SM8250, SM8550 ant SM8650 SoCs. It builds-depends on the following serie: https://lore.kernel.org/all/20240910-topic-ufs-enhancements-v1-0-3ee0bffac...@linaro.org/ And at runtime it depends on: https://lore.kernel.org/all/20240910-topic-ufs-qcom-phy-v1-0-21ff4b87b...@linaro.org/ Signed-off-by: Neil Armstrong --- Bhupesh Sharma (1): ufs: Add Support for Qualcomm UFS HC driver Neil Armstrong (3): ufs: add device_reset callback ufs: add get_max_pwr_mode callback ufs: allow UFSHCI version 4.0 drivers/ufs/Kconfig| 7 + drivers/ufs/Makefile | 1 + drivers/ufs/ufs-qcom.c | 670 + drivers/ufs/ufs-qcom.h | 147 +++ drivers/ufs/ufs.c | 13 +- drivers/ufs/ufs.h | 21 ++ drivers/ufs/unipro.h | 6 + 7 files changed, 863 insertions(+), 2 deletions(-) --- base-commit: 7725e4eb07c03ca0842b0a7ed425af28e1b8ed37 change-id: 20240910-topic-ufs-qcom-controller-4b2905610963 Best regards, -- Neil Armstrong
[PATCH 4/4] ufs: Add Support for Qualcomm UFS HC driver
From: Bhupesh Sharma Add Support for the Host Controller driver for UFS HC present on Qualcomm Snapdragon SoCs. It has been successfully tested on SDM845, SM8250, SM8550 ant SM8650 SoCs. Signed-off-by: Bhupesh Sharma Signed-off-by: Neil Armstrong --- drivers/ufs/Kconfig| 7 + drivers/ufs/Makefile | 1 + drivers/ufs/ufs-qcom.c | 670 + drivers/ufs/ufs-qcom.h | 147 +++ drivers/ufs/unipro.h | 6 + 5 files changed, 831 insertions(+) diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig index 7da46faed6b..0ca1f2ae7dc 100644 --- a/drivers/ufs/Kconfig +++ b/drivers/ufs/Kconfig @@ -26,6 +26,13 @@ config UFS_PCI If unsure, say N. +config QCOM_UFS + bool "Qualcomm Host Controller driver for UFS" + depends on UFS && ARCH_SNAPDRAGON +help + This selects the platform driver for the UFS host + controller present on Qualcomm Snapdragon SoCs. + config TI_J721E_UFS bool "Glue Layer driver for UFS on TI J721E devices" help diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile index 67c42621aba..024382cd2ce 100644 --- a/drivers/ufs/Makefile +++ b/drivers/ufs/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o +obj-$(CONFIG_QCOM_UFS) += ufs-qcom.o obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o obj-$(CONFIG_UFS_PCI) += ufs-pci.o obj-$(CONFIG_UFS_RENESAS) += ufs-renesas.o diff --git a/drivers/ufs/ufs-qcom.c b/drivers/ufs/ufs-qcom.c new file mode 100644 index 000..843585726c7 --- /dev/null +++ b/drivers/ufs/ufs-qcom.c @@ -0,0 +1,670 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2013-2016, Linux Foundation. All rights reserved. + * Copyright (C) 2023-2024 Linaro Limited + * Authors: + * - Bhupesh Sharma + * - Neil Armstrong + * + * Based on Linux driver + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ufs.h" +#include "ufs-qcom.h" + +#define ceil(freq, div) ((freq) % (div) == 0 ? ((freq) / (div)) : ((freq) / (div) + 1)) + +static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_hba *hba, bool enable); + +static int ufs_qcom_enable_clks(struct ufs_qcom_priv *priv) +{ + int err; + + if (priv->is_clks_enabled) + return 0; + + err = clk_enable_bulk(&priv->clks); + if (err) + return err; + + priv->is_clks_enabled = true; + + return 0; +} + +static int ufs_qcom_init_clks(struct ufs_qcom_priv *priv) +{ + int err; + struct udevice *dev = priv->hba->dev; + + err = clk_get_bulk(dev, &priv->clks); + if (err) + return err; + + return 0; +} + +static int ufs_qcom_check_hibern8(struct ufs_hba *hba) +{ + int err, retry_count = 50; + u32 tx_fsm_val = 0; + + do { + err = ufshcd_dme_get(hba, + UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, + UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), + &tx_fsm_val); + if (err || tx_fsm_val == TX_FSM_HIBERN8) + break; + + /* max. 200us */ + udelay(200); + retry_count--; + } while (retry_count != 0); + + /* Check the state again */ + err = ufshcd_dme_get(hba, + UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, + UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), + &tx_fsm_val); + + if (err) { + dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n", + __func__, err); + } else if (tx_fsm_val != TX_FSM_HIBERN8) { + err = tx_fsm_val; + dev_err(hba->dev, "%s: invalid TX_FSM_STATE = %d\n", + __func__, err); + } + + return err; +} + +static void ufs_qcom_select_unipro_mode(struct ufs_qcom_priv *priv) +{ + ufshcd_rmwl(priv->hba, QUNIPRO_SEL, QUNIPRO_SEL, REG_UFS_CFG1); + + if (priv->hw_ver.major >= 0x05) + ufshcd_rmwl(priv->hba, QUNIPRO_G4_SEL, 0, REG_UFS_CFG0); +} + +/* + * ufs_qcom_reset - reset host controller and PHY + */ +static int ufs_qcom_reset(struct ufs_hba *hba) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + int ret; + + ret = reset_assert(&priv->core_reset); + if (ret) { + dev_err(hba->dev, "%s: core_reset assert failed, err = %d\n", + __func__, ret); + return ret; + } + + /* +* The hardware requirement for delay between assert/deassert +* is at least 3-4 sleep clock (32.7KHz) cycles, which comes to +* ~125us (4/3276
[PATCH 3/4] ufs: allow UFSHCI version 4.0
Add UFSHCI version 4.0 found on the recent Qualcomm UFS Controllers. Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 3 ++- drivers/ufs/ufs.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 1edd31677b2..f7d8c40c448 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -1974,7 +1974,8 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) hba->version != UFSHCI_VERSION_20 && hba->version != UFSHCI_VERSION_21 && hba->version != UFSHCI_VERSION_30 && - hba->version != UFSHCI_VERSION_31) + hba->version != UFSHCI_VERSION_31 && + hba->version != UFSHCI_VERSION_40) dev_err(hba->dev, "invalid UFS version 0x%x\n", hba->version); diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index fb47d0cd3a4..2ab593455e9 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -906,6 +906,7 @@ enum { UFSHCI_VERSION_21 = 0x0210, /* 2.1 */ UFSHCI_VERSION_30 = 0x0300, /* 3.0 */ UFSHCI_VERSION_31 = 0x0310, /* 3.1 */ + UFSHCI_VERSION_40 = 0x0400, /* 4.0 */ }; /* Interrupt disable masks */ -- 2.34.1
[PATCH 2/4] ufs: add get_max_pwr_mode callback
Add a new get_max_pwr_mode callback to permit the UFS controller driver manipulate the max_pwr_mode struct right before setting the new pwr_mode to the UFS device. It can be used to limit the HS Gear with errata and hardware limitations on some UFS controllers. Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 2 +- drivers/ufs/ufs.h | 11 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index de8ba011d57..1edd31677b2 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -1744,7 +1744,7 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba) } hba->max_pwr_info.is_valid = true; - return 0; + return ufshcd_ops_get_max_pwr_mode(hba, &hba->max_pwr_info); } static int ufshcd_change_power_mode(struct ufs_hba *hba, diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index faaebf1f9f7..fb47d0cd3a4 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -696,6 +696,8 @@ struct ufs_dev_cmd { struct ufs_hba_ops { int (*init)(struct ufs_hba *hba); + int (*get_max_pwr_mode)(struct ufs_hba *hba, + struct ufs_pwr_mode_info *max_pwr_info); int (*hce_enable_notify)(struct ufs_hba *hba, enum ufs_notify_change_status); int (*link_startup_notify)(struct ufs_hba *hba, @@ -861,6 +863,15 @@ static inline int ufshcd_ops_init(struct ufs_hba *hba) return 0; } +static inline int ufshcd_ops_get_max_pwr_mode(struct ufs_hba *hba, + struct ufs_pwr_mode_info *max_pwr_info) +{ + if (hba->ops && hba->ops->get_max_pwr_mode) + return hba->ops->get_max_pwr_mode(hba, max_pwr_info); + + return 0; +} + static inline int ufshcd_ops_hce_enable_notify(struct ufs_hba *hba, bool status) { -- 2.34.1
[PATCH 1/4] ufs: add device_reset callback
Add device_reset op to permit resetting the UFS device if the UFS controller drivers supports the operation. Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 8 drivers/ufs/ufs.h | 9 + 2 files changed, 17 insertions(+) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index e34e4586224..de8ba011d57 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -125,6 +125,11 @@ static void ufshcd_print_pwr_info(struct ufs_hba *hba) hba->pwr_info.hs_rate); } +static void ufshcd_device_reset(struct ufs_hba *hba) +{ + ufshcd_vops_device_reset(hba); +} + /** * ufshcd_ready_for_uic_cmd - Check if controller is ready *to accept UIC commands @@ -1997,6 +2002,9 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) mb(); + /* Reset the attached device */ + ufshcd_device_reset(hba); + err = ufshcd_hba_enable(hba); if (err) { dev_err(hba->dev, "Host controller enable failed\n"); diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index e8a14411560..faaebf1f9f7 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -701,6 +701,7 @@ struct ufs_hba_ops { int (*link_startup_notify)(struct ufs_hba *hba, enum ufs_notify_change_status); int (*phy_initialization)(struct ufs_hba *hba); + int (*device_reset)(struct ufs_hba *hba); }; struct ufs_hba { @@ -878,6 +879,14 @@ static inline int ufshcd_ops_link_startup_notify(struct ufs_hba *hba, return 0; } +static inline int ufshcd_vops_device_reset(struct ufs_hba *hba) +{ + if (hba->ops && hba->ops->device_reset) + return hba->ops->device_reset(hba); + + return 0; +} + /* Controller UFSHCI version */ enum { UFSHCI_VERSION_10 = 0x0001, /* 1.0 */ -- 2.34.1
[PATCH 13/13] MAINTAINERS: Add myself to the list of UFS maintainers
Adding myself to continue Bhupesh's work to enhance and fix UFS support in U-boot, especially for Qualcomm SoCs, and help review patches and maintain the UFS subsystem. Signed-off-by: Neil Armstrong --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7ab39d91a55..14809c057c9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1707,6 +1707,7 @@ T:git https://source.denx.de/u-boot/custodians/u-boot-ubi.git F: drivers/mtd/ubi/ UFS +M: Neil Armstrong M: Bhupesh Sharma M: Neha Malcom Francis S: Maintained -- 2.34.1
[PATCH 11/13] ufs: Fix debug message in 'ufs_start'
From: Bhupesh Sharma Minor typo fix and rewording of printf message inside 'ufs_start' which announces the availability of the UFS device. Signed-off-by: Bhupesh Sharma --- drivers/ufs/ufs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 5d4e5424358..d2df5c26f76 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -1925,7 +1925,7 @@ int ufs_start(struct ufs_hba *hba) return ret; } - printf("Device at %s up at:", hba->dev->name); + debug("UFS Device %s is up!\n", hba->dev->name); ufshcd_print_pwr_info(hba); } -- 2.34.1
[PATCH 09/13] ufs: Sync possible UFS Quirks with Linux UFS driver
From: Bhupesh Sharma Sync u-boot UFS driver to add all possible UFS Quirks as supported by Linux UFS driver as well. Signed-off-by: Bhupesh Sharma --- drivers/ufs/ufs.h | 151 +++--- 1 file changed, 120 insertions(+), 31 deletions(-) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 555f8a6857d..e8a14411560 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -712,38 +712,127 @@ struct ufs_hba { u32 version; u32 intr_mask; u32 quirks; -/* - * If UFS host controller is having issue in processing LCC (Line - * Control Command) coming from device then enable this quirk. - * When this quirk is enabled, host controller driver should disable - * the LCC transmission on UFS device (by clearing TX_LCC_ENABLE - * attribute of device to 0). - */ -#define UFSHCD_QUIRK_BROKEN_LCCBIT(0) -/* - * This quirk needs to be enabled if the host controller has - * 64-bit addressing supported capability but it doesn't work. - */ -#define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS BIT(1) - -/* - * This quirk needs to be enabled if the host controller has - * auto-hibernate capability but it's FASTAUTO only. - */ -#define UFSHCD_QUIRK_HIBERN_FASTAUTO BIT(2) - -/* - * This quirk needs to be enabled if the host controller has - * 64-bit addressing supported capability but it doesn't work. - */ -#define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS 0x2 - -/* - * This quirk needs to be enabled if the host controller has - * auto-hibernate capability but it's FASTAUTO only. - */ -#define UFSHCD_QUIRK_HIBERN_FASTAUTO 0x4 + /* Interrupt aggregation support is broken */ +#define UFSHCD_QUIRK_BROKEN_INTR_AGGR (1 << 0) + + /* +* delay before each dme command is required as the unipro +* layer has shown instabilities +*/ +#define UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS (1 << 1) + + /* +* If UFS host controller is having issue in processing LCC (Line +* Control Command) coming from device then enable this quirk. +* When this quirk is enabled, host controller driver should disable +* the LCC transmission on UFS device (by clearing TX_LCC_ENABLE +* attribute of device to 0). +*/ +#define UFSHCD_QUIRK_BROKEN_LCC(1 << 2) + + /* +* The attribute PA_RXHSUNTERMCAP specifies whether or not the +* inbound Link supports unterminated line in HS mode. Setting this +* attribute to 1 fixes moving to HS gear. +*/ +#define UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP (1 << 3) + + /* +* This quirk needs to be enabled if the host controller only allows +* accessing the peer dme attributes in AUTO mode (FAST AUTO or +* SLOW AUTO). +*/ +#define UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE (1 << 4) + + /* +* This quirk needs to be enabled if the host controller doesn't +* advertise the correct version in UFS_VER register. If this quirk +* is enabled, standard UFS host driver will call the vendor specific +* ops (get_ufs_hci_version) to get the correct version. +*/ +#define UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION(1 << 5) + + /* +* Clear handling for transfer/task request list is just opposite. +*/ +#define UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR (1 << 6) + + /* +* This quirk needs to be enabled if host controller doesn't allow +* that the interrupt aggregation timer and counter are reset by s/w. +*/ +#define UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR (1 << 7) + + /* +* This quirks needs to be enabled if host controller cannot be +* enabled via HCE register. +*/ +#define UFSHCI_QUIRK_BROKEN_HCE(1 << 8) + + /* +* This quirk needs to be enabled if the host controller regards +* resolution of the values of PRDTO and PRDTL in UTRD as byte. +*/ +#define UFSHCD_QUIRK_PRDT_BYTE_GRAN(1 << 9) + + /* +* This quirk needs to be enabled if the host controller reports +* OCS FATAL ERROR with device error through sense data +*/ +#define UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR(1 << 10) + + /* +* This quirk needs to be enabled if the host controller has +* auto-hibernate capability but it doesn't work. +*/ +#define UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8 (1 << 11) + + /* +* This quirk needs to disable manual flush for write booster +*/ +#define UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL (1 << 12) + + /* +* This quirk needs to disable unipro timeout values +* before power mode change +*/ +#define UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING (1 << 13) + + /* +* Align DMA SG
[PATCH 00/13] ufs: enhancements to support Qualcomm UFS controllers
This serie regroups all the fixes and base enhancements required to support the Qualcomm UFS controllers in U-Boot. This syncs headers & defines from Linux, and includes 2 set of fixes that were sent separately: - ufs: core: remove link_startup_again logic - ufs: properly fix cache operations Without those 2 sets, UFS cannot initialize on Qualcomm controlers since v5, and a numerous of Cache issues makes any UFS controller fail to initialize. Since UFS core hasn't changed for a while, and since UFS is core technology for the Qualcomm SoCs, I volunteer maintaininig the UFS subsystem if Bhupesh & Neha Malcom Francis are ok with that. Signed-off-by: Neil Armstrong --- Bhupesh Sharma (5): ufs/ufs.h: Add definition of 'ufshcd_rmwl()' ufs: Clear UECPA once due to LINERESET has happened during LINK_STARTUP ufs: Sync possible UFS Quirks with Linux UFS driver ufs: Add missing memory barriers ufs: Fix debug message in 'ufs_start' Marek Vasut (2): ufs: Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS ufs: Add UFSHCD_QUIRK_HIBERN_FASTAUTO Neil Armstrong (6): ufs: allocate descriptors with size aligned with DMA_MINALIGN ufs: fix dcache flush and invalidate range calculation ufs: split flush and invalidate to only invalidate when required ufs: use dcache helpers for scsi_cmd data and only invalidate if necessary ufs: core: remove link_startup_again logic MAINTAINERS: Add myself to the list of UFS maintainers MAINTAINERS | 1 + drivers/ufs/ufs.c | 98 -- drivers/ufs/ufs.h | 157 +++--- 3 files changed, 197 insertions(+), 59 deletions(-) --- base-commit: ca55cf8104c0dd78aae45fa66dd8400ef1b3d0ac change-id: 20240910-topic-ufs-enhancements-fe8ef9ce39d8 Best regards, -- Neil Armstrong
[PATCH 12/13] ufs: core: remove link_startup_again logic
The link_startup_again logic was added in Linux to handle device that were set in LinkDown state, which should not be the case since U-boot doesn't set LinkDown state are init, and Linux sets the device active in ufshcd_init() for the first link startup. While it worked to far, it breaks link startup for Qualcomm Controllers v5, let's just remove the logic. Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 8 1 file changed, 8 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index d2df5c26f76..e34e4586224 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -462,9 +462,7 @@ static int ufshcd_link_startup(struct ufs_hba *hba) { int ret; int retries = DME_LINKSTARTUP_RETRIES; - bool link_startup_again = true; -link_startup: do { ufshcd_ops_link_startup_notify(hba, PRE_CHANGE); @@ -490,12 +488,6 @@ link_startup: /* failed to get the link up... retire */ goto out; - if (link_startup_again) { - link_startup_again = false; - retries = DME_LINKSTARTUP_RETRIES; - goto link_startup; - } - /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */ ufshcd_init_pwr_info(hba); -- 2.34.1
[PATCH 10/13] ufs: Add missing memory barriers
From: Bhupesh Sharma Add missing wmb() and mb() barriers in the u-boot UFS core framework driver to allow registers updates to happen before follow-up read operations. This makes the barrier placement similar to the Linux UFS driver. Signed-off-by: Bhupesh Sharma --- drivers/ufs/ufs.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 565a6af1404..5d4e5424358 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -432,6 +432,12 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba) ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utmrdl), REG_UTP_TASK_REQ_LIST_BASE_H); + /* +* Make sure base address and interrupt setup are updated before +* enabling the run/stop registers below. +*/ + wmb(); + /* * UCRDY, UTMRLDY and UTRLRDY bits must be 1 */ @@ -861,6 +867,9 @@ static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); + /* Make sure doorbell reg is updated before reading interrupt status */ + wmb(); + start = get_timer(0); do { intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); @@ -1994,6 +2003,8 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) REG_INTERRUPT_STATUS); ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE); + mb(); + err = ufshcd_hba_enable(hba); if (err) { dev_err(hba->dev, "Host controller enable failed\n"); -- 2.34.1
[PATCH 08/13] ufs: Clear UECPA once due to LINERESET has happened during LINK_STARTUP
From: Bhupesh Sharma Clear UECPA once in u-boot UFS driver due to LINERESET has happened during LINK_STARTUP. This makes the u-boot ufs driver behavior related to UECPA similar to Linux UFS driver. Signed-off-by: Bhupesh Sharma --- drivers/ufs/ufs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index d99dcdef7d0..565a6af1404 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -504,6 +504,8 @@ link_startup: if (ret) goto out; + /* Clear UECPA once due to LINERESET has happened during LINK_STARTUP */ + ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); ret = ufshcd_make_hba_operational(hba); out: if (ret) -- 2.34.1
[PATCH 06/13] ufs: Add UFSHCD_QUIRK_HIBERN_FASTAUTO
From: Marek Vasut Add UFSHCD_QUIRK_HIBERN_FASTAUTO quirk for host controllers which supports auto-hibernate the capability but only FASTAUTO mode. Ported from Linux kernel commit 2f11bbc2c7f3 ("scsi: ufs: core: Add UFSHCD_QUIRK_HIBERN_FASTAUTO") Signed-off-by: Marek Vasut --- drivers/ufs/ufs.h | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index c92f47d82b5..b55c4a9e996 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -738,6 +738,12 @@ struct ufs_hba { */ #define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS 0x2 +/* + * This quirk needs to be enabled if the host controller has + * auto-hibernate capability but it's FASTAUTO only. + */ +#define UFSHCD_QUIRK_HIBERN_FASTAUTO 0x4 + /* Virtual memory reference */ struct utp_transfer_cmd_desc *ucdl; struct utp_transfer_req_desc *utrdl; -- 2.34.1
[PATCH 07/13] ufs/ufs.h: Add definition of 'ufshcd_rmwl()'
From: Bhupesh Sharma Add definition of 'ufshcd_rmwl()' helper function which would be later used by Qualcomm UFS driver to read-modify-write registers. Signed-off-by: Bhupesh Sharma --- drivers/ufs/ufs.h | 18 ++ 1 file changed, 18 insertions(+) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index b55c4a9e996..555f8a6857d 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -3,6 +3,7 @@ #define __UFS_H #include +#include #include "unipro.h" struct udevice; @@ -933,6 +934,23 @@ enum { #define ufshcd_readl(hba, reg) \ readl((hba)->mmio_base + (reg)) +/** + * ufshcd_rmwl - perform read/modify/write for a controller register + * @hba: per adapter instance + * @mask: mask to apply on read value + * @val: actual value to write + * @reg: register address + */ +static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg) +{ + u32 tmp; + + tmp = ufshcd_readl(hba, reg); + tmp &= ~mask; + tmp |= (val & mask); + ufshcd_writel(hba, tmp, reg); +} + /* UTRLRSR - UTP Transfer Request Run-Stop Register 60h */ #define UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT 0x1 -- 2.34.1
[PATCH 05/13] ufs: Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS
From: Marek Vasut Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS for host controllers which do not support 64-bit addressing. Ported from Linux kernel commit 6554400d6f66 ("scsi: ufs: core: Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS") with ufs_scsi_buffer_aligned() based on U-Boot generic bounce buffer. Signed-off-by: Marek Vasut --- drivers/ufs/ufs.h | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 43042c294bb..c92f47d82b5 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -732,6 +732,12 @@ struct ufs_hba { */ #define UFSHCD_QUIRK_HIBERN_FASTAUTO BIT(2) +/* + * This quirk needs to be enabled if the host controller has + * 64-bit addressing supported capability but it doesn't work. + */ +#define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS 0x2 + /* Virtual memory reference */ struct utp_transfer_cmd_desc *ucdl; struct utp_transfer_req_desc *utrdl; -- 2.34.1
[PATCH 04/13] ufs: use dcache helpers for scsi_cmd data and only invalidate if necessary
Now we have proper flush and invalidate helpers, we can use them directly to operate on the scsi_cmd data. Likewise, we do not need to flush then invalidate, just flush _or_ invalidate depending on the data direction. Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 14 -- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 5845fd694d3..d99dcdef7d0 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -1468,7 +1468,6 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) { struct utp_transfer_req_desc *req_desc = hba->utrdl; struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr; - uintptr_t aaddr = (uintptr_t)(pccb->pdata) & ~(ARCH_DMA_MINALIGN - 1); ulong datalen = pccb->datalen; int table_length; u8 *buf; @@ -1480,15 +1479,6 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) return; } - if (pccb->dma_dir == DMA_TO_DEVICE) { /* Write to device */ - flush_dcache_range(aaddr, - ALIGN((uintptr_t)pccb->pdata + datalen, ARCH_DMA_MINALIGN)); - } - - /* In any case, invalidate cache to avoid stale data in it. */ - invalidate_dcache_range(aaddr, - ALIGN((uintptr_t)pccb->pdata + datalen, ARCH_DMA_MINALIGN)); - table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY); buf = pccb->pdata; i = table_length; @@ -1517,8 +1507,12 @@ static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb) ufshcd_prepare_utp_scsi_cmd_upiu(hba, pccb, upiu_flags); prepare_prdt_table(hba, pccb); + ufshcd_cache_flush(pccb->pdata, pccb->datalen); + ufshcd_send_command(hba, TASK_TAG); + ufshcd_cache_invalidate(pccb->pdata, pccb->datalen); + ocs = ufshcd_get_tr_ocs(hba); switch (ocs) { case OCS_SUCCESS: -- 2.34.1
[PATCH 03/13] ufs: split flush and invalidate to only invalidate when required
There is no need to flush and invalidate all data updated by the driver, mainly because on ARM platforms flush also invalidates the cachelines. Split the function in two and add the appropriate cacheline invalidates after the UFS DMA operation finishes to make sure we read from memory. Flushing then invalidating cacheline unaligned data causes data corruption issues on Qualcomm platforms, and is largely unnecessary anyway, so let's cleanup the cache operations. Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 45 ++--- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 3d9a7d7ee12..5845fd694d3 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -696,17 +696,28 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) } /** - * ufshcd_cache_flush_and_invalidate - Flush and invalidate cache + * ufshcd_cache_flush - Flush cache * - * Flush and invalidate cache in aligned address..address+size range. - * The invalidation is in place to avoid stale data in cache. + * Flush cache in aligned address..address+size range. */ -static void ufshcd_cache_flush_and_invalidate(void *addr, unsigned long size) +static void ufshcd_cache_flush(void *addr, unsigned long size) { uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); flush_dcache_range(start_addr, end_addr); +} + +/** + * ufshcd_cache_invalidate - Invalidate cache + * + * Invalidate cache in aligned address..address+size range. + */ +static void ufshcd_cache_invalidate(void *addr, unsigned long size) +{ + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); + invalidate_dcache_range(start_addr, end_addr); } @@ -754,7 +765,7 @@ static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, req_desc->prd_table_length = 0; - ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc)); + ufshcd_cache_flush(req_desc, sizeof(*req_desc)); } static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, @@ -785,13 +796,13 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, /* Copy the Descriptor */ if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) { memcpy(ucd_req_ptr + 1, query->descriptor, len); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr)); } else { - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); } memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) @@ -809,8 +820,8 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } /** @@ -877,6 +888,8 @@ static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) */ static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) { + ufshcd_cache_invalidate(ucd_rsp_ptr, sizeof(*ucd_rsp_ptr)); + return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24; } @@ -888,6 +901,8 @@ static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba) { struct utp_transfer_req_desc *req_desc = hba->utrdl; + ufshcd_cache_invalidate(req_desc, sizeof(*req_desc)); + return le32_to_cpu(req_desc->header.dword_2) & MASK_OCS; } @@ -1437,8 +1452,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba, memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len); memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry, @@ -1461,7 +1476,7 @@ static void prepare_prdt_table(struct ufs_hba *hba, str
[PATCH 02/13] ufs: fix dcache flush and invalidate range calculation
The current calculation will omit doing a flush/invalidate on the last cacheline if the base address is not aligned with DMA_MINALIGN. This causes commands failures and write corruptions on Qualcomm platforms. Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 16 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index e005cc90608..3d9a7d7ee12 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -703,11 +703,11 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) */ static void ufshcd_cache_flush_and_invalidate(void *addr, unsigned long size) { - uintptr_t aaddr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); - unsigned long asize = ALIGN(size, ARCH_DMA_MINALIGN); + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); - flush_dcache_range(aaddr, aaddr + asize); - invalidate_dcache_range(aaddr, aaddr + asize); + flush_dcache_range(start_addr, end_addr); + invalidate_dcache_range(start_addr, end_addr); } /** @@ -1466,13 +1466,13 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) } if (pccb->dma_dir == DMA_TO_DEVICE) { /* Write to device */ - flush_dcache_range(aaddr, aaddr + - ALIGN(datalen, ARCH_DMA_MINALIGN)); + flush_dcache_range(aaddr, + ALIGN((uintptr_t)pccb->pdata + datalen, ARCH_DMA_MINALIGN)); } /* In any case, invalidate cache to avoid stale data in it. */ - invalidate_dcache_range(aaddr, aaddr + - ALIGN(datalen, ARCH_DMA_MINALIGN)); + invalidate_dcache_range(aaddr, + ALIGN((uintptr_t)pccb->pdata + datalen, ARCH_DMA_MINALIGN)); table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY); buf = pccb->pdata; -- 2.34.1
[PATCH 01/13] ufs: allocate descriptors with size aligned with DMA_MINALIGN
Align the allocation size with DMA_MINALIGN to make sure we do not flush/invalidate data from following allocations. Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index be64bf971f1..e005cc90608 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -633,7 +633,9 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) /* Allocate one Transfer Request Descriptor * Should be aligned to 1k boundary. */ - hba->utrdl = memalign(1024, sizeof(struct utp_transfer_req_desc)); + hba->utrdl = memalign(1024, + ALIGN(sizeof(struct utp_transfer_req_desc), + ARCH_DMA_MINALIGN)); if (!hba->utrdl) { dev_err(hba->dev, "Transfer Descriptor memory allocation failed\n"); return -ENOMEM; @@ -642,7 +644,9 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) /* Allocate one Command Descriptor * Should be aligned to 1k boundary. */ - hba->ucdl = memalign(1024, sizeof(struct utp_transfer_cmd_desc)); + hba->ucdl = memalign(1024, +ALIGN(sizeof(struct utp_transfer_cmd_desc), + ARCH_DMA_MINALIGN)); if (!hba->ucdl) { dev_err(hba->dev, "Command descriptor memory allocation failed\n"); return -ENOMEM; -- 2.34.1
[PATCH 2/2] phy: qcom: Add QMP UFS PHY driver
From: Bhupesh Sharma Add Qualcomm QMP UFS PHY driver which is available on the following Snapdragon SoCs - SDM845, SM8250, SM8550 and SM8650 SoCs. Signed-off-by: Bhupesh Sharma Signed-off-by: Neil Armstrong --- drivers/phy/qcom/Kconfig|6 + drivers/phy/qcom/Makefile |1 + drivers/phy/qcom/phy-qcom-qmp-ufs.c | 1116 +++ drivers/phy/qcom/phy-qcom-qmp.h | 115 4 files changed, 1238 insertions(+) diff --git a/drivers/phy/qcom/Kconfig b/drivers/phy/qcom/Kconfig index 3aae1813352..5c77203d606 100644 --- a/drivers/phy/qcom/Kconfig +++ b/drivers/phy/qcom/Kconfig @@ -12,6 +12,12 @@ config PHY_QCOM_IPQ4019_USB help Support for the USB PHY-s on Qualcomm IPQ40xx SoC-s. +config PHY_QCOM_QMP_UFS + tristate "Qualcomm QMP UFS PHY driver" + depends on PHY && ARCH_SNAPDRAGON + help + Enable this to support the UFS QMP PHY on various Qualcomm chipsets. + config PHY_QCOM_QUSB2 tristate "Qualcomm USB QUSB2 PHY driver" depends on PHY && ARCH_SNAPDRAGON diff --git a/drivers/phy/qcom/Makefile b/drivers/phy/qcom/Makefile index a5153061dfb..dc3ed492696 100644 --- a/drivers/phy/qcom/Makefile +++ b/drivers/phy/qcom/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o +obj-$(CONFIG_PHY_QCOM_QMP_UFS) += phy-qcom-qmp-ufs.o obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o obj-$(CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2) += phy-qcom-snps-femto-v2.o obj-$(CONFIG_PHY_QCOM_SNPS_EUSB2) += phy-qcom-snps-eusb2.o diff --git a/drivers/phy/qcom/phy-qcom-qmp-ufs.c b/drivers/phy/qcom/phy-qcom-qmp-ufs.c new file mode 100644 index 000..8908a34df54 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-ufs.c @@ -0,0 +1,1116 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (C) 2023-2024 Linaro Limited + * Authors: + * - Bhupesh Sharma + * - Neil Armstrong + * + * Based on Linux driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "phy-qcom-qmp.h" +#include "phy-qcom-qmp-pcs-ufs-v2.h" +#include "phy-qcom-qmp-pcs-ufs-v3.h" +#include "phy-qcom-qmp-pcs-ufs-v4.h" +#include "phy-qcom-qmp-pcs-ufs-v5.h" +#include "phy-qcom-qmp-pcs-ufs-v6.h" + +#include "phy-qcom-qmp-qserdes-com-v4.h" +#include "phy-qcom-qmp-qserdes-com-v6.h" +#include "phy-qcom-qmp-qserdes-txrx-v4.h" +#include "phy-qcom-qmp-qserdes-txrx-ufs-v6.h" + +/* QPHY_SW_RESET bit */ +#define SW_RESET BIT(0) +/* QPHY_POWER_DOWN_CONTROL */ +#define SW_PWRDN BIT(0) +/* QPHY_START_CONTROL bits */ +#define SERDES_START BIT(0) +#define PCS_START BIT(1) +/* QPHY_PCS_READY_STATUS bit */ +#define PCS_READY BIT(0) + +#define PHY_INIT_COMPLETE_TIMEOUT (200 * 1) + +struct qmp_ufs_init_tbl { + unsigned int offset; + unsigned int val; + /* +* mask of lanes for which this register is written +* for cases when second lane needs different values +*/ + u8 lane_mask; +}; + +#define QMP_PHY_INIT_CFG(o, v) \ + { \ + .offset = o,\ + .val = v, \ + .lane_mask = 0xff, \ + } + +#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ + { \ + .offset = o,\ + .val = v, \ + .lane_mask = l, \ + } + +/* set of registers with offsets different per-PHY */ +enum qphy_reg_layout { + /* PCS registers */ + QPHY_SW_RESET, + QPHY_START_CTRL, + QPHY_PCS_READY_STATUS, + QPHY_PCS_POWER_DOWN_CONTROL, + /* Keep last to ensure regs_layout arrays are properly initialized */ + QPHY_LAYOUT_SIZE +}; + +static const unsigned int ufsphy_v2_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = QPHY_V2_PCS_UFS_PHY_START, + [QPHY_PCS_READY_STATUS] = QPHY_V2_PCS_UFS_READY_STATUS, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V2_PCS_UFS_POWER_DOWN_CONTROL, +}; + +static const unsigned int ufsphy_v3_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = QPHY_V3_PCS_UFS_PHY_START, + [QPHY_PCS_READY_STATUS] = QPHY_V3_PCS_UFS_READY_STATUS, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_UFS_POWER_DOWN_CONTROL, +}; + +static const unsigned int ufsphy_v4_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = QPHY_V4_PCS_UFS_PHY_START, +
[PATCH 0/2] phy: qcom: add QMP UFS PHY support
This serie imports the QMP UFS PHY headers then adds the QMP PHY driver in order to support enabling the UFS PHY on the SDM845, SM8250, SM8550 and SM8650 platforms. Signed-off-by: Neil Armstrong --- Bhupesh Sharma (2): phy: qcom: Import QMP phy related header files from Linux phy: qcom: Add QMP UFS PHY driver drivers/phy/qcom/Kconfig |6 + drivers/phy/qcom/Makefile |1 + drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v2.h | 25 + drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v3.h | 21 + drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v4.h | 31 + drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v5.h | 32 + drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v6.h | 38 + drivers/phy/qcom/phy-qcom-qmp-pcs-v2.h | 43 + drivers/phy/qcom/phy-qcom-qmp-pcs-v3.h | 145 +++ drivers/phy/qcom/phy-qcom-qmp-pcs-v4.h | 135 +++ drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v3.h | 111 ++ drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v4.h | 123 +++ drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v6.h | 89 ++ drivers/phy/qcom/phy-qcom-qmp-qserdes-com.h| 140 +++ drivers/phy/qcom/phy-qcom-qmp-qserdes-pll.h| 69 ++ .../phy/qcom/phy-qcom-qmp-qserdes-txrx-ufs-v6.h| 52 + drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-v3.h| 68 ++ drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-v4.h| 233 drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx.h | 205 drivers/phy/qcom/phy-qcom-qmp-ufs.c| 1116 drivers/phy/qcom/phy-qcom-qmp.h| 115 ++ 21 files changed, 2798 insertions(+) --- base-commit: ca55cf8104c0dd78aae45fa66dd8400ef1b3d0ac change-id: 20240910-topic-ufs-qcom-phy-c3d5d0f4138d Best regards, -- Neil Armstrong
[PATCH 1/2] phy: qcom: Import QMP phy related header files from Linux
From: Bhupesh Sharma Import Qualcomm QMP phy related header files from Linux v6.11-rc7, limit to headers needed to setup QMP v2 to v6 UFS PHYs. Signed-off-by: Bhupesh Sharma Signed-off-by: Neil Armstrong --- drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v2.h | 25 +++ drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v3.h | 21 ++ drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v4.h | 31 +++ drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v5.h | 32 +++ drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v6.h | 38 drivers/phy/qcom/phy-qcom-qmp-pcs-v2.h | 43 drivers/phy/qcom/phy-qcom-qmp-pcs-v3.h | 145 + drivers/phy/qcom/phy-qcom-qmp-pcs-v4.h | 135 drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v3.h | 111 ++ drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v4.h | 123 +++ drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v6.h | 89 drivers/phy/qcom/phy-qcom-qmp-qserdes-com.h| 140 + drivers/phy/qcom/phy-qcom-qmp-qserdes-pll.h| 69 ++ .../phy/qcom/phy-qcom-qmp-qserdes-txrx-ufs-v6.h| 52 + drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-v3.h| 68 ++ drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-v4.h| 233 + drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx.h | 205 ++ 17 files changed, 1560 insertions(+) diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v2.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v2.h new file mode 100644 index 000..a0803a8783d --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v2.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_UFS_V2_H_ +#define QCOM_PHY_QMP_PCS_UFS_V2_H_ + +#define QPHY_V2_PCS_UFS_PHY_START 0x000 +#define QPHY_V2_PCS_UFS_POWER_DOWN_CONTROL 0x004 + +#define QPHY_V2_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x034 +#define QPHY_V2_PCS_UFS_TX_LARGE_AMP_POST_EMP_LVL 0x038 +#define QPHY_V2_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x03c +#define QPHY_V2_PCS_UFS_TX_SMALL_AMP_POST_EMP_LVL 0x040 + +#define QPHY_V2_PCS_UFS_RX_MIN_STALL_NOCONFIG_TIME_CAP 0x0cc +#define QPHY_V2_PCS_UFS_RX_SYM_RESYNC_CTRL 0x13c +#define QPHY_V2_PCS_UFS_RX_MIN_HIBERN8_TIME0x140 +#define QPHY_V2_PCS_UFS_RX_SIGDET_CTRL20x148 +#define QPHY_V2_PCS_UFS_RX_PWM_GEAR_BAND 0x154 + +#define QPHY_V2_PCS_UFS_READY_STATUS 0x168 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v3.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v3.h new file mode 100644 index 000..adea13c3a9e --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v3.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_UFS_V3_H_ +#define QCOM_PHY_QMP_PCS_UFS_V3_H_ + +#define QPHY_V3_PCS_UFS_PHY_START 0x000 +#define QPHY_V3_PCS_UFS_POWER_DOWN_CONTROL 0x004 +#define QPHY_V3_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x02c +#define QPHY_V3_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x034 +#define QPHY_V3_PCS_UFS_RX_SYM_RESYNC_CTRL 0x134 +#define QPHY_V3_PCS_UFS_RX_MIN_HIBERN8_TIME0x138 +#define QPHY_V3_PCS_UFS_RX_SIGDET_CTRL10x13c +#define QPHY_V3_PCS_UFS_RX_SIGDET_CTRL20x140 +#define QPHY_V3_PCS_UFS_READY_STATUS 0x160 +#define QPHY_V3_PCS_UFS_TX_MID_TERM_CTRL1 0x1bc +#define QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1 0x1c4 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v4.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v4.h new file mode 100644 index 000..a1c7d3d1715 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v4.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_UFS_V4_H_ +#define QCOM_PHY_QMP_PCS_UFS_V4_H_ + +/* Only for QMP V4 PHY - UFS PCS registers */ +#define QPHY_V4_PCS_UFS_PHY_START 0x000 +#define QPHY_V4_PCS_UFS_POWER_DOWN_CONTROL 0x004 +#define QPHY_V4_PCS_UFS_SW_RESET 0x008 +#define QPHY_V4_PCS_UFS_TIMER_20US_CORECLK_STEPS_MSB 0x00c +#define QPHY_V4_PCS_UFS_TIMER_20US_CORECLK_STEPS_LSB 0x010 +#define QPHY_V4_PCS_UFS_PLL_CNTL 0x02c +#define QPHY_V4_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x030 +#define QPHY_V4_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x038 +#define QPHY_V4_PCS_UFS_BIST_FIXED_PAT_CTRL0x060 +#define QPHY_V4_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074 +#define QPHY_V4_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0b4 +#define QPHY_V4_PCS_UFS_DEBUG_BUS_CLKSEL 0x124 +#define
[PATCH 2/2] pinctr: qcom: sm8250: add special pins pins configuration data
Add the special pins configuration data to allow setup the bias of the UFS and SDCard pins on the SM8250 SoC. Signed-off-by: Neil Armstrong --- drivers/pinctrl/qcom/pinctrl-sm8250.c | 41 --- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250.c b/drivers/pinctrl/qcom/pinctrl-sm8250.c index dac24f11bc2..69c907e3868 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8250.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8250.c @@ -18,8 +18,37 @@ static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); static const struct pinctrl_function msm_pinctrl_functions[] = { { "qup12", 1 }, -{ "gpio", 0 }, -{ "sdc2_clk", 0 } }; +{ "gpio", 0 }, }; +#define SDC_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = pg_name,\ + .ctl_reg = ctl, \ + .io_reg = 0,\ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = pg_name,\ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +static const struct msm_special_pin_data sm8250_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", SOUTH + 0xb8000), + [1] = SDC_PINGROUP("sdc2_clk", NORTH + 0xb7000, 14, 6), + [2] = SDC_PINGROUP("sdc2_cmd", NORTH + 0xb7000, 11, 3), + [3] = SDC_PINGROUP("sdc2_data", NORTH + 0xb7000, 9, 0), +}; static const unsigned int sm8250_pin_offsets[] = { [0] = SOUTH, [1] = SOUTH, [2] = SOUTH, [3] = SOUTH, [4] = NORTH, [5] = NORTH, @@ -62,7 +91,12 @@ static const char *sm8250_get_function_name(struct udevice *dev, unsigned int se static const char *sm8250_get_pin_name(struct udevice *dev, unsigned int selector) { - snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + if (selector >= 180 && selector <= 183) + snprintf(pin_name, MAX_PIN_NAME_LEN, +sm8250_special_pins_data[selector - 180].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + return pin_name; } @@ -76,6 +110,7 @@ static struct msm_pinctrl_data sm8250_data = { .pin_offsets = sm8250_pin_offsets, .pin_count = ARRAY_SIZE(sm8250_pin_offsets), .special_pins_start = 180, + .special_pins_data = sm8250_special_pins_data, }, .functions_count = ARRAY_SIZE(msm_pinctrl_functions), .get_function_name = sm8250_get_function_name, -- 2.34.1
[PATCH 1/2] gpio: msm: add support for special pins
Leverage the data introduced in the struct msm_special_pin_data to allow setting the gpio direction and value if supported by the pin data. Signed-off-by: Neil Armstrong --- drivers/gpio/msm_gpio.c | 97 + 1 file changed, 89 insertions(+), 8 deletions(-) diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c index 2fb266f1285..cea073b3297 100644 --- a/drivers/gpio/msm_gpio.c +++ b/drivers/gpio/msm_gpio.c @@ -34,13 +34,31 @@ struct msm_gpio_bank { #define GPIO_IN_OUT_REG(dev, x) \ (GPIO_CONFIG_REG(dev, x) + 0x4) +static void msm_gpio_direction_input_special(struct msm_gpio_bank *priv, +unsigned int gpio) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return; + + data = &priv->pin_data->special_pins_data[offset]; + + if (!data->ctl_reg || data->oe_bit >= 31) + return; + + /* switch direction */ + clrsetbits_le32(priv->base + data->ctl_reg, + BIT(data->oe_bit), 0); +} + static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio) { struct msm_gpio_bank *priv = dev_get_priv(dev); - /* Always NOP for special pins, assume they're in the correct state */ if (qcom_is_special_pin(priv->pin_data, gpio)) - return; + msm_gpio_direction_input_special(priv, gpio); /* Disable OE bit */ clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio), @@ -49,13 +67,33 @@ static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio) return; } +static int msm_gpio_set_value_special(struct msm_gpio_bank *priv, + unsigned int gpio, int value) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return 0; + + data = &priv->pin_data->special_pins_data[offset]; + + if (!data->io_reg || data->out_bit >= 31) + return 0; + + value = !!value; + /* set value */ + writel(value << data->out_bit, priv->base + data->io_reg); + + return 0; +} + static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value) { struct msm_gpio_bank *priv = dev_get_priv(dev); - /* Always NOP for special pins, assume they're in the correct state */ if (qcom_is_special_pin(priv->pin_data, gpio)) - return 0; + return msm_gpio_set_value_special(priv, gpio, value); value = !!value; /* set value */ @@ -64,14 +102,42 @@ static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value) return 0; } +static int msm_gpio_direction_output_special(struct msm_gpio_bank *priv, +unsigned int gpio, +int value) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return 0; + + data = &priv->pin_data->special_pins_data[offset]; + + if (!data->io_reg || data->out_bit >= 31) + return 0; + + value = !!value; + /* set value */ + writel(value << data->out_bit, priv->base + data->io_reg); + + if (!data->ctl_reg || data->oe_bit >= 31) + return 0; + + /* switch direction */ + clrsetbits_le32(priv->base + data->ctl_reg, + BIT(data->oe_bit), BIT(data->oe_bit)); + + return 0; +} + static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio, int value) { struct msm_gpio_bank *priv = dev_get_priv(dev); - /* Always NOP for special pins, assume they're in the correct state */ if (qcom_is_special_pin(priv->pin_data, gpio)) - return 0; + return msm_gpio_direction_output_special(priv, gpio, value); value = !!value; /* set value */ @@ -100,13 +166,28 @@ static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flag return 0; } +static int msm_gpio_get_value_special(struct msm_gpio_bank *priv, unsigned int gpio) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return 0; + + data = &priv->pin_data->special_pins_data[offse
[PATCH 0/2] qcom: allow msm_gpio to set special pins direction & value
After struct msm_special_pin_data was introduced in [1], use the data to setup the pin direction and/or value if supported by the pin data. Add the proper msm_special_pin_data for sm8250 after sm8550 and sm8650. [1] https://lore.kernel.org/all/20240528-topic-sm8x50-pinctrl-pinconf-v1-0-54d1e9ad7...@linaro.org/ Signed-off-by: Neil Armstrong --- Neil Armstrong (2): gpio: msm: add support for special pins pinctr: qcom: sm8250: add special pins pins configuration data drivers/gpio/msm_gpio.c | 97 --- drivers/pinctrl/qcom/pinctrl-sm8250.c | 41 +-- 2 files changed, 127 insertions(+), 11 deletions(-) --- base-commit: ca55cf8104c0dd78aae45fa66dd8400ef1b3d0ac change-id: 20240910-topic-sm8x50-msm-gpio-special-pins-sm8250-943311b483e2 Best regards, -- Neil Armstrong
Re: [PATCH] Revert "gpio: qcom_pmic: add a quirk to skip GPIO configuration"
On 09/09/2024 14:06, Caleb Connolly wrote: This reverts commit 19f000b72b2fa7e4540f7cdb91287aff594239bd. The bug in writing was caused by a long-standing error in the SPMI driver which has since been fixed - c2de620d64d4 ("spmi: msm: fix version 5 support"). We can safely enable writing GPIO configuration now. Signed-off-by: Caleb Connolly --- Tested on SDM845/pm8998 (OnePlus 6) --- drivers/gpio/qcom_pmic_gpio.c | 27 +-- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/drivers/gpio/qcom_pmic_gpio.c b/drivers/gpio/qcom_pmic_gpio.c index 80fee841ee3f..f2ef4e5ce144 100644 --- a/drivers/gpio/qcom_pmic_gpio.c +++ b/drivers/gpio/qcom_pmic_gpio.c @@ -68,19 +68,8 @@ #define REG_EN_CTL 0x46 #define REG_EN_CTL_ENABLE (1 << 7) -/** - * pmic_gpio_match_data - platform specific configuration - * - * @PMIC_MATCH_READONLY: treat all GPIOs as readonly, don't attempt to configure them. - * This is a workaround for an unknown bug on some platforms where trying to write the - * GPIO configuration registers causes the board to hang. - */ -enum pmic_gpio_quirks { - QCOM_PMIC_QUIRK_READONLY = (1 << 0), -}; - struct qcom_pmic_gpio_data { uint32_t pid; /* Peripheral ID on SPMI bus */ bool lv_mv_type; /* If subtype is GPIO_LV(0x10) or GPIO_MV(0x11) */ u32 pin_count; @@ -127,15 +116,10 @@ static int qcom_gpio_set_direction(struct udevice *dev, unsigned int offset, bool input, int value) { struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); uint32_t gpio_base = plat->pid + REG_OFFSET(offset); - ulong quirks = dev_get_driver_data(dev); int ret = 0; - /* Some PMICs don't like their GPIOs being configured */ - if (quirks & QCOM_PMIC_QUIRK_READONLY) - return 0; - /* Disable the GPIO */ ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, REG_EN_CTL_ENABLE, 0); if (ret < 0) @@ -277,9 +261,8 @@ static const struct dm_gpio_ops qcom_gpio_ops = { static int qcom_gpio_bind(struct udevice *dev) { struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); - ulong quirks = dev_get_driver_data(dev); struct udevice *child; struct driver *drv; int ret; @@ -291,9 +274,9 @@ static int qcom_gpio_bind(struct udevice *dev) /* Bind the GPIO driver as a child of the PMIC. */ ret = device_bind_with_driver_data(dev, drv, dev->name, - quirks, dev_ofnode(dev), &child); + 0, dev_ofnode(dev), &child); if (ret) return log_msg_ret("bind", ret); dev_set_plat(child, plat); @@ -360,13 +343,13 @@ static int qcom_gpio_probe(struct udevice *dev) static const struct udevice_id qcom_gpio_ids[] = { { .compatible = "qcom,pm8916-gpio" }, { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */ - { .compatible = "qcom,pm8998-gpio", .data = QCOM_PMIC_QUIRK_READONLY }, + { .compatible = "qcom,pm8998-gpio" }, { .compatible = "qcom,pms405-gpio" }, - { .compatible = "qcom,pm6125-gpio", .data = QCOM_PMIC_QUIRK_READONLY }, - { .compatible = "qcom,pm8150-gpio", .data = QCOM_PMIC_QUIRK_READONLY }, - { .compatible = "qcom,pm8550-gpio", .data = QCOM_PMIC_QUIRK_READONLY }, + { .compatible = "qcom,pm6125-gpio" }, + { .compatible = "qcom,pm8150-gpio" }, + { .compatible = "qcom,pm8550-gpio" }, { } }; U_BOOT_DRIVER(qcom_pmic_gpio) = { Reviewed-by: Neil Armstrong
[PATCH 1/2] soc: qcom: rpmh-rsc: add back __tcs_set_trigger() for SM8550/SM8650
The TCS writes has no effect after the removal of the __tcs_set_trigger() call, obviously it seems the RSC version 3 requires it to complete the transactions. Fixes: 80c5be164ad ("soc: qcom: rpmh-rsc: drop unused multi-threading and non-active TCS support") Signed-off-by: Neil Armstrong --- drivers/soc/qcom/rpmh-rsc.c | 43 +++ 1 file changed, 43 insertions(+) diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 61fb2e69558..aee9e55194e 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -293,6 +293,48 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id, write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable); } +/** + * __tcs_set_trigger() - Start xfer on a TCS or unset trigger on a borrowed TCS + * @drv: The controller. + * @tcs_id: The global ID of this TCS. + * @trigger: If true then untrigger/retrigger. If false then just untrigger. + * + * In the normal case we only ever call with "trigger=true" to start a + * transfer. That will un-trigger/disable the TCS from the last transfer + * then trigger/enable for this transfer. + * + * If we borrowed a wake TCS for an active-only transfer we'll also call + * this function with "trigger=false" to just do the un-trigger/disable + * before using the TCS for wake purposes again. + * + * Note that the AP is only in charge of triggering active-only transfers. + * The AP never triggers sleep/wake values using this function. + */ +static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger) +{ + u32 enable; + u32 reg = drv->regs[RSC_DRV_CONTROL]; + + /* +* HW req: Clear the DRV_CONTROL and enable TCS again +* While clearing ensure that the AMC mode trigger is cleared +* and then the mode enable is cleared. +*/ + enable = read_tcs_reg(drv, reg, tcs_id); + enable &= ~TCS_AMC_MODE_TRIGGER; + write_tcs_reg_sync(drv, reg, tcs_id, enable); + enable &= ~TCS_AMC_MODE_ENABLE; + write_tcs_reg_sync(drv, reg, tcs_id, enable); + + if (trigger) { + /* Enable the AMC mode on the TCS and then trigger the TCS */ + enable = TCS_AMC_MODE_ENABLE; + write_tcs_reg_sync(drv, reg, tcs_id, enable); + enable |= TCS_AMC_MODE_TRIGGER; + write_tcs_reg(drv, reg, tcs_id, enable); + } +} + /** * rpmh_rsc_send_data() - Write / trigger active-only message. * @drv: The controller. @@ -348,6 +390,7 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) * of __tcs_set_trigger() below. */ __tcs_buffer_write(drv, tcs_id, 0, msg); + __tcs_set_trigger(drv, tcs_id, true); /* U-Boot: Now wait for the TCS to be cleared, indicating that we're done */ for (i = 0; i < USEC_PER_SEC; i++) { -- 2.34.1
[PATCH 2/2] regulator: qcom-rpmh-regulator: add support for PM8550 & related regulators
Add the PM8550 & related regulators found on the SM8550 and SM8650 platforms. The tables are imported from the Linux driver. Signed-off-by: Neil Armstrong --- drivers/power/regulator/qcom-rpmh-regulator.c | 136 ++ 1 file changed, 136 insertions(+) diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c index 06fd3f31956..2dc261d83e3 100644 --- a/drivers/power/regulator/qcom-rpmh-regulator.c +++ b/drivers/power/regulator/qcom-rpmh-regulator.c @@ -357,6 +357,69 @@ static const struct dm_regulator_ops rpmh_regulator_vrm_drms_ops = { .get_mode = rpmh_regulator_vrm_get_mode, }; +static struct dm_regulator_mode pmic_mode_map_pmic5_bob[] = { + { + .id = REGULATOR_MODE_LPM, + .register_value = PMIC5_BOB_MODE_PFM, + .name = "PMIC5_BOB_MODE_PFM" + }, { + .id = REGULATOR_MODE_AUTO, + .register_value = PMIC5_BOB_MODE_AUTO, + .name = "PMIC5_BOB_MODE_AUTO" + }, { + .id = REGULATOR_MODE_HPM, + .register_value = PMIC5_BOB_MODE_PWM, + .name = "PMIC5_BOB_MODE_PWM" + }, +}; + +static struct dm_regulator_mode pmic_mode_map_pmic5_smps[] = { + { + .id = REGULATOR_MODE_RETENTION, + .register_value = PMIC5_SMPS_MODE_RETENTION, + .name = "PMIC5_SMPS_MODE_RETENTION" + }, { + .id = REGULATOR_MODE_LPM, + .register_value = PMIC5_SMPS_MODE_PFM, + .name = "PMIC5_SMPS_MODE_PFM" + }, { + .id = REGULATOR_MODE_AUTO, + .register_value = PMIC5_SMPS_MODE_AUTO, + .name = "PMIC5_SMPS_MODE_AUTO" + }, { + .id = REGULATOR_MODE_HPM, + .register_value = PMIC5_SMPS_MODE_PWM, + .name = "PMIC5_SMPS_MODE_PWM" + }, +}; + +static const struct rpmh_vreg_hw_data pmic5_bob = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(300, 0, 31, 32000), + .n_voltages = 32, + .pmic_mode_map = pmic_mode_map_pmic5_bob, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_bob), +}; + +static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(30, 0, 267, 4000), + .n_voltages = 268, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps), +}; + +static const struct rpmh_vreg_hw_data pmic5_ftsmps525_mv = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(60, 0, 267, 8000), + .n_voltages = 268, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps), +}; + static struct dm_regulator_mode pmic_mode_map_pmic5_ldo[] = { { .id = REGULATOR_MODE_RETENTION, @@ -393,6 +456,16 @@ static const struct rpmh_vreg_hw_data pmic5_pldo_lv = { .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo), }; +static const struct rpmh_vreg_hw_data pmic5_nldo515 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(32, 0, 210, 8000), + .n_voltages = 211, + .hpm_min_load_uA = 3, + .pmic_mode_map = pmic_mode_map_pmic5_ldo, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo), +}; + #define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \ { \ .name = _name, \ @@ -412,6 +485,57 @@ static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = { {} }; +static const struct rpmh_vreg_init_data pm8550_vreg_data[] = { + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515,"vdd-l1-l4-l10"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo,"vdd-l2-l13-l14"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515,"vdd-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515,"vdd-l1-l4-l10"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo,"vdd-l5-l16"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l7"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l6-l7"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l8-l9"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo,"vdd-l8-l9"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo
[PATCH 0/2] regulators: qcom-rpmh: support SM8550 and SM8650 platforms
Fix the RSC and add the tables for the PM8550 and related regulators. Signed-off-by: Neil Armstrong --- Neil Armstrong (2): soc: qcom: rpmh-rsc: add back __tcs_set_trigger() for SM8550/SM8650 regulator: qcom-rpmh-regulator: add support for PM8550 & related regulators drivers/power/regulator/qcom-rpmh-regulator.c | 136 ++ drivers/soc/qcom/rpmh-rsc.c | 43 2 files changed, 179 insertions(+) --- base-commit: bb403c895887eb5b29652f916646f886b34c6309 change-id: 20240903-topic-sm8x50-regulators-support-b149f2417299 Best regards, -- Neil Armstrong
[GIT PULL] Please pull u-boot-amlogic-next-20240902
Hi Tom, A simple set of changes to allow using the bootrom NAND pages, ported from Linux. Thanks, Neil The following changes since commit ee2af844ba1b27b2e959c4e649e4b769fbeb4074: Merge tag 'efi-2024-10-rc4' of https://source.denx.de/u-boot/custodians/u-boot-efi (2024-08-24 14:03:28 -0600) are available in the Git repository at: https://source.denx.de/u-boot/custodians/u-boot-amlogic.git tags/u-boot-amlogic-next-20240902 for you to fetch changes up to 35ff967a99e97b523732096628bdbc78758922f6: mtd: rawnand: meson: read/write access for boot ROM pages (2024-08-28 16:05:45 +0200) - meson_nand: R/W support for pages used by boot ROM Arseniy Krasnov (3): mtd: rawnand: nand_base: support for 'NAND_IS_BOOT_MEDIUM' flag mtd: rawnand: meson: refactor use of 'meson_nfc_cmd_access()' mtd: rawnand: meson: read/write access for boot ROM pages drivers/mtd/nand/raw/meson_nand.c | 84 ++- drivers/mtd/nand/raw/nand_base.c | 3 ++ include/linux/mtd/rawnand.h | 5 +++ 3 files changed, 65 insertions(+), 27 deletions(-)
Re: [u-boot-test-hooks PATCH v4 3/3] Provide some basic scripts for Labgrid integration
On 30/08/2024 03:09, Simon Glass wrote: Hi Tom, On Thu, 29 Aug 2024 at 09:20, Tom Rini wrote: On Thu, Aug 29, 2024 at 09:02:38AM -0600, Simon Glass wrote: Hi Neil, On Thu, 29 Aug 2024 at 08:44, wrote: On 29/08/2024 14:17, Simon Glass wrote: Hi Peter, On Thu, 29 Aug 2024 at 04:43, Peter Robinson wrote: On Wed, 28 Aug 2024 at 22:25, Simon Glass wrote: Hi Peter, On Wed, 28 Aug 2024 at 12:14, Peter Robinson wrote: Hi Simon, With Labgrid we don't need to specify the various methods, except for the console, which simply calls labgrid-client. This allows supporting any boards in your lab, without adding per-board configuration to these hooks. Provide ellesmere files as an example. What's ellesmere? It is a lake but also the name of a computer. Signed-off-by: Simon Glass --- Changes in v4: - Support pytest fully with dual-build boards like Beagleplay Changes in v3: - Update scripts for latest version of Labgrid integration - Add poweroff.none and poweron.none - Provide -n flag when querying board info - Target the grpc version of Labgrid which is now in -master - Update README to cover the changes Changes in v2: - Make use of the common script (only) to set bin_dir README.md| 50 Maybe that should be in a separate labsgrid readme? My hope is that Labgrid becomes the normal way of running these tests, Generally I agree with automated testing platforms, I think makes sense, there's a bunch like Linaro and a bunch in the arm ecosystem use LAVA [1] and there's a bunch more that I'm aware of. I am somewhat familiar with LAVA and I believe it can be used to test U-Boot, although I need to learn how. Looking at a test run [2] for beaglebone black I see that it is using a recent kernel but the U-Boot seems to be older. Does it make sense, of course at some point in the future post this being merged, make sense to look at a general way of making it easier to plugin these sort of HW test platforms using this as a basis? I ask mostly because putting a bunch of my devices into some sort of platform can auto test things and of course everyone has an opinion to which is the best one :-P Yes. I had heard from Tom that Labgrid is the new hotness for now. Having dug into it I believe it is a good solution, although it can certainly be improved to handle scale better. Anyway, IMO the current test hooks are not a great solution, just because the configuration is spread all over the place and it relies on lots of little shell scripts. So I believe that the Labgrid integration is a closer to where we want to be with others that come along. I'd say all those scripts are actually here to ease integration with any system, booting U-Boot and Linux are two different beasts. That's fine, go ahead and use the scripts. My point is that Labgrid doesn't need them and in fact it makes everything pretty painful if we try to use all of them. I guess I really need to clean-up and post my former co-workers scripts as I strongly disagree with that statement. See some examples below. Bear in mind also that my goal has been to get my lab fully running, that includes interactive access to boards, as well as running tests. For that I have been using tbot (with integrated build and software-loading features). WIth Labgrid I have been able to replace most of the pytest scripts, tbot and Labman with Labgrid + 60 patches and some configuration files. Let's look through the scripts: u-boot-test-common - new script u-boot-test-console - needed u-boot-test-flash - here's an example: . poweroff.${power_impl} sleep 0.1 . flash.sdwire_common_mount . poweron.${power_impl} Here's another: # Handles the common SDwire mounting (caller does power control) mount_dir=/media/${mount_point} # Switch over to get USB card access sd-mux-ctrl --device-serial ${sdwire_serial} --ts complete=false for i in {0..9}; do if out="$(mount UUID=${mount_uuid} 2>&1)"; then complete=true break fi echo $out # If it is already mounted, try to unmount it first. It may have been # mounted by another user so we won't have the access we need. If this gives # an error then we know we cannot continue if [[ $out == *"already mounted"* ]]; then umount UUID=${mount_uuid} fi sleep 1 done if [[ $complete = false ]]; then echo "Failed to mount UUID ${mount_uuid} after 10 tries" exit 1 fi # Sanity check if ! mountpoint -q ${mount_dir}; then echo "Mount ${mount_dir} not available after 'mount'" exit 1 fi # Perform the write, pass along as much environment as possible . writer.${flash_writer} complete=false for i in {0..9}; do if out="$(umount ${mount_dir} 2>&1)"; then complete=true break fi echo $out sleep 1 done if [[ $complete = false ]]; then echo "Failed to umount UUID ${mount_uuid} after 10 tries" exit 1 fi # Sanity check if
Re: [u-boot-test-hooks PATCH v4 3/3] Provide some basic scripts for Labgrid integration
On 29/08/2024 14:17, Simon Glass wrote: Hi Peter, On Thu, 29 Aug 2024 at 04:43, Peter Robinson wrote: On Wed, 28 Aug 2024 at 22:25, Simon Glass wrote: Hi Peter, On Wed, 28 Aug 2024 at 12:14, Peter Robinson wrote: Hi Simon, With Labgrid we don't need to specify the various methods, except for the console, which simply calls labgrid-client. This allows supporting any boards in your lab, without adding per-board configuration to these hooks. Provide ellesmere files as an example. What's ellesmere? It is a lake but also the name of a computer. Signed-off-by: Simon Glass --- Changes in v4: - Support pytest fully with dual-build boards like Beagleplay Changes in v3: - Update scripts for latest version of Labgrid integration - Add poweroff.none and poweron.none - Provide -n flag when querying board info - Target the grpc version of Labgrid which is now in -master - Update README to cover the changes Changes in v2: - Make use of the common script (only) to set bin_dir README.md| 50 Maybe that should be in a separate labsgrid readme? My hope is that Labgrid becomes the normal way of running these tests, Generally I agree with automated testing platforms, I think makes sense, there's a bunch like Linaro and a bunch in the arm ecosystem use LAVA [1] and there's a bunch more that I'm aware of. I am somewhat familiar with LAVA and I believe it can be used to test U-Boot, although I need to learn how. Looking at a test run [2] for beaglebone black I see that it is using a recent kernel but the U-Boot seems to be older. Does it make sense, of course at some point in the future post this being merged, make sense to look at a general way of making it easier to plugin these sort of HW test platforms using this as a basis? I ask mostly because putting a bunch of my devices into some sort of platform can auto test things and of course everyone has an opinion to which is the best one :-P Yes. I had heard from Tom that Labgrid is the new hotness for now. Having dug into it I believe it is a good solution, although it can certainly be improved to handle scale better. Anyway, IMO the current test hooks are not a great solution, just because the configuration is spread all over the place and it relies on lots of little shell scripts. So I believe that the Labgrid integration is a closer to where we want to be with others that come along. I'd say all those scripts are actually here to ease integration with any system, booting U-Boot and Linux are two different beasts. Most of the time you need special jumpers enabled to setup vendor-specific bootrom mode to reflash or ram-boot U-Boot. So forcing us people to switch to Labgrid because it matches your boards behavior is a little adventurous, and while we can add some enhancement to the actual pytest and hooks, I'm against saying Labgrid should be the golden CI system. Neil I would love for you to add a board into Labgrid and see how you go. [1] https://validation.linaro.org/ so having it in the main place (and perhaps eventually removing the old way) is my goal. bin/console.labgrid | 42 ++ bin/ellesmere/common-labgrid | 46 + bin/ellesmere/conf.all | 24 + bin/getrole.labgrid | 25 ++ bin/release.labgrid | 22 bin/release.none | 22 bin/u-boot-test-getrole | 38 +++ bin/u-boot-test-release | 26 +++ 9 files changed, 295 insertions(+) create mode 100644 bin/console.labgrid create mode 100755 bin/ellesmere/common-labgrid create mode 100644 bin/ellesmere/conf.all create mode 100644 bin/getrole.labgrid create mode 100644 bin/release.labgrid create mode 100644 bin/release.none create mode 100755 bin/u-boot-test-getrole create mode 100755 bin/u-boot-test-release [..] Regards, Simon Regards, Simon [2] https://validation.linaro.org/scheduler/job/4089871#results_482796468
Re: [PATCH v5 01/20] test: Allow signaling that U-Boot is ready
On 29/08/2024 16:22, neil.armstr...@linaro.org wrote: On 29/08/2024 00:08, Simon Glass wrote: When Labgrid is used, it can get U-Boot ready for running tests. It prints a message when it has done so. Add logic to detect this message and accept it. So labgrid can boot and wait for `board_type & board_identity` itself right ? Sorry bad copy paste, I was meaning `Hit any key to stop autoboot: ` It's cool, but if the boots fails for a reason, what would happen ? Having the U-Boot pytest to parse the U-Boot boot log makes sure we can identify crash and report them in the pytest log. And this adds a labgrid-only string to parse, which could potentially collide with pre-uboot or whatever log when not using labgrid. Neil Signed-off-by: Simon Glass --- (no changes since v1) test/py/u_boot_console_base.py | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py index 76a550d45a1..882d04cd1e9 100644 --- a/test/py/u_boot_console_base.py +++ b/test/py/u_boot_console_base.py @@ -22,6 +22,7 @@ pattern_stop_autoboot_prompt = re.compile('Hit any key to stop autoboot: ') pattern_unknown_command = re.compile('Unknown command \'.*\' - try \'help\'') pattern_error_notification = re.compile('## Error: ') pattern_error_please_reset = re.compile('### ERROR ### Please RESET the board ###') +pattern_ready_prompt = re.compile('U-Boot is ready') PAT_ID = 0 PAT_RE = 1 @@ -196,15 +197,15 @@ class ConsoleBase(object): self.bad_pattern_ids[m - 1]) self.u_boot_version_string = self.p.after while True: - m = self.p.expect([self.prompt_compiled, + m = self.p.expect([self.prompt_compiled, pattern_ready_prompt, pattern_stop_autoboot_prompt] + self.bad_patterns) - if m == 0: + if m == 0 or m == 1: break - if m == 1: + if m == 2: self.p.send(' ') continue raise Exception('Bad pattern found on console: ' + - self.bad_pattern_ids[m - 2]) + self.bad_pattern_ids[m - 3]) except Exception as ex: self.log.error(str(ex))
Re: [PATCH v5 17/20] test: Try to shut down the lab console gracefully
On 29/08/2024 00:08, Simon Glass wrote: Send the Labgrid quit characters to ask it to exit gracefully. This typically allows it to power off the board being used. Sending those characters every time could collide with other CI systems, I don't think it's a good idea. If that doesn't work, try the less graceful approach. Signed-off-by: Simon Glass --- (no changes since v1) test/py/u_boot_spawn.py | 17 +++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/py/u_boot_spawn.py b/test/py/u_boot_spawn.py index c0ff0813554..ec1fa465047 100644 --- a/test/py/u_boot_spawn.py +++ b/test/py/u_boot_spawn.py @@ -16,6 +16,9 @@ import termios import time import traceback +# Character to send (twice) to exit the terminal +EXIT_CHAR = 0x1d# FS (Ctrl + ]) + class Timeout(Exception): """An exception sub-class that indicates that a timeout occurred.""" @@ -304,15 +307,25 @@ class Spawn: None. Returns: -Nothing. +str: Type of closure completed """ +self.send(chr(EXIT_CHAR) * 2) +# Wait about 10 seconds for Labgrid to close and power off the board +for _ in range(100): +if not self.isalive(): +return 'normal' +time.sleep(0.1) + +# That didn't work, so try closing the PTY os.close(self.fd) for _ in range(100): if not self.isalive(): -break +return 'break' time.sleep(0.1) +return 'timeout' + def get_expect_output(self): """Return the output read by expect()
Re: [PATCH v5 03/20] test: Pass stderr to stdout
On 29/08/2024 00:08, Simon Glass wrote: Some tests may output things to stderr. Ensure that this output is not dropped, by redirecting it to stdout Can't you make sure to output all labgrid output to stdout in the hook script instead ? Signed-off-by: Simon Glass --- (no changes since v1) test/py/u_boot_spawn.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/py/u_boot_spawn.py b/test/py/u_boot_spawn.py index 97e95e07c80..81a09a9d639 100644 --- a/test/py/u_boot_spawn.py +++ b/test/py/u_boot_spawn.py @@ -10,6 +10,7 @@ import re import pty import signal import select +import sys import time import traceback @@ -59,6 +60,7 @@ class Spawn: signal.signal(signal.SIGHUP, signal.SIG_DFL) if cwd: os.chdir(cwd) +sys.stderr = sys.stdout os.execvp(args[0], args) except: print('CHILD EXECEPTION:')
Re: [PATCH v5 01/20] test: Allow signaling that U-Boot is ready
On 29/08/2024 00:08, Simon Glass wrote: When Labgrid is used, it can get U-Boot ready for running tests. It prints a message when it has done so. Add logic to detect this message and accept it. So labgrid can boot and wait for `board_type & board_identity` itself right ? It's cool, but if the boots fails for a reason, what would happen ? Having the U-Boot pytest to parse the U-Boot boot log makes sure we can identify crash and report them in the pytest log. And this adds a labgrid-only string to parse, which could potentially collide with pre-uboot or whatever log when not using labgrid. Neil Signed-off-by: Simon Glass --- (no changes since v1) test/py/u_boot_console_base.py | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py index 76a550d45a1..882d04cd1e9 100644 --- a/test/py/u_boot_console_base.py +++ b/test/py/u_boot_console_base.py @@ -22,6 +22,7 @@ pattern_stop_autoboot_prompt = re.compile('Hit any key to stop autoboot: ') pattern_unknown_command = re.compile('Unknown command \'.*\' - try \'help\'') pattern_error_notification = re.compile('## Error: ') pattern_error_please_reset = re.compile('### ERROR ### Please RESET the board ###') +pattern_ready_prompt = re.compile('U-Boot is ready') PAT_ID = 0 PAT_RE = 1 @@ -196,15 +197,15 @@ class ConsoleBase(object): self.bad_pattern_ids[m - 1]) self.u_boot_version_string = self.p.after while True: -m = self.p.expect([self.prompt_compiled, +m = self.p.expect([self.prompt_compiled, pattern_ready_prompt, pattern_stop_autoboot_prompt] + self.bad_patterns) -if m == 0: +if m == 0 or m == 1: break -if m == 1: +if m == 2: self.p.send(' ') continue raise Exception('Bad pattern found on console: ' + -self.bad_pattern_ids[m - 2]) +self.bad_pattern_ids[m - 3]) except Exception as ex: self.log.error(str(ex))
Re: [PATCH v5 08/20] test: Introduce the concept of a role
Hi, On 29/08/2024 00:08, Simon Glass wrote: In Labgrid there is the concept of a 'role', which is similar to the U-Boot board ID in U-Boot's pytest subsystem. The role indicates both the target and information about the U-Boot build to use. It can also provide any amount of other configuration. The information is obtained using the 'labgrid-client query' operation. Make use of this in tests, so that only the role is required in gitlab and other situations. The board type and other things can be queried as needed. Use a new 'u-boot-test-getrole' script to obtain the requested information. With this it is possible to run lab tests in gitlab with just a single 'ROLE' variable for each board. Can't this be in the hook script ? I mean allmost no CI system have a 1:1 usage of board_type & board_identity, but we use those fields and transform them accordingly. u-boot-test-getrole is labgrid only, all script receives board_type & board_identity, so why add some labgrind specific python here ? Neil Signed-off-by: Simon Glass --- Changes in v5: - Add a few more comments - Comment out the debugging, which might be useful later test/py/conftest.py | 38 ++ 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/test/py/conftest.py b/test/py/conftest.py index 6547c6922c6..03dfd8ab562 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -23,6 +23,7 @@ from pathlib import Path import pytest import re from _pytest.runner import runtestprotocol +import subprocess import sys # Globals: The HTML log file, and the connection to the U-Boot console. @@ -79,6 +80,7 @@ def pytest_addoption(parser): parser.addoption('--gdbserver', default=None, help='Run sandbox under gdbserver. The argument is the channel '+ 'over which gdbserver should communicate, e.g. localhost:1234') +parser.addoption('--role', help='U-Boot board role (for Labgrid)') parser.addoption('--no-prompt-wait', default=False, action='store_true', help="Assume that U-Boot is ready and don't wait for a prompt") @@ -130,12 +132,40 @@ def get_details(config): str: Build directory str: Source directory """ -board_type = config.getoption('board_type') -board_identity = config.getoption('board_identity') +role = config.getoption('role') + +# Get a few provided parameters build_dir = config.getoption('build_dir') +if role: +# When using a role, build_dir and build_dir_extra are normally not set, +# since they are picked up from Labgrid via the u-boot-test-getrole +# script +board_identity = role +cmd = ['u-boot-test-getrole', role, '--configure'] +env = os.environ.copy() +if build_dir: +env['U_BOOT_BUILD_DIR'] = build_dir +proc = subprocess.run(cmd, capture_output=True, encoding='utf-8', + env=env) +if proc.returncode: +raise ValueError(proc.stderr) +# For debugging +# print('conftest: lab:', proc.stdout) +vals = {} +for line in proc.stdout.splitlines(): +item, value = line.split(' ', maxsplit=1) +k = item.split(':')[-1] +vals[k] = value +# For debugging +# print('conftest: lab info:', vals) +board_type, default_build_dir, source_dir = (vals['board'], +vals['build_dir'], vals['source_dir']) +else: +board_type = config.getoption('board_type') +board_identity = config.getoption('board_identity') -source_dir = os.path.dirname(os.path.dirname(TEST_PY_DIR)) -default_build_dir = source_dir + '/build-' + board_type +source_dir = os.path.dirname(os.path.dirname(TEST_PY_DIR)) +default_build_dir = source_dir + '/build-' + board_type if not build_dir: build_dir = default_build_dir
Re: [PATCH v3 0/3] Meson: R/W support for pages used by boot ROM
Hi, On Mon, 26 Aug 2024 16:17:07 +0300, Arseniy Krasnov wrote: > Patchset is based on patchset for Linux (today merged to nand-next): > https://lore.kernel.org/linux-mtd/20240507230903.3399594-1-avkras...@salutedevices.com/ > > Here is description from it: > > > Amlogic's boot ROM code needs that some pages on NAND must be written > > in special "short" ECC mode with scrambling enabled. Such pages: > > 1) Contain some metadata about hardware. > > 2) Located with some interval starting from 0 offset, until some > > specified offset. Interval and second offset are set in the > > device tree. > > > > This patchset adds R/W support for such pages. To enable it we can setup > > it in dts: > > > > nand-is-boot-medium; > > amlogic,boot-pages = <1024>; > > amlogic,boot-page-step = <128>; > > > > It means that each 128th page in range 0 to 1024 pages will be accessed > > in special mode ("short" ECC + scrambling). In practice this feature is > > needed when we want to update first block of NAND - driver will enable > > required mode by itself using value from device tree. > > [...] Thanks, Applied to https://source.denx.de/u-boot/custodians/u-boot-amlogic (u-boot-amlogic-next) [1/3] mtd: rawnand: nand_base: support for 'NAND_IS_BOOT_MEDIUM' flag https://source.denx.de/u-boot/custodians/u-boot-amlogic/-/commit/9905e77edaa9b4a43285e587317c600ffa7be7ca [2/3] mtd: rawnand: meson: refactor use of 'meson_nfc_cmd_access()' https://source.denx.de/u-boot/custodians/u-boot-amlogic/-/commit/33acfbf41819d06e13bcccf1ffdf7d01160f4b1e [3/3] mtd: rawnand: meson: read/write access for boot ROM pages https://source.denx.de/u-boot/custodians/u-boot-amlogic/-/commit/35ff967a99e97b523732096628bdbc78758922f6 -- Neil
Re: [PATCH] doc/develop/sending_patches.rst: Reword where our git tree is slightly
On 26/08/2024 19:01, Tom Rini wrote: We shouldn't have had the link to our git tree be contained within "``" as that meant that it did not work as a link, so remove those. And rather than make this a link plus text, keep this as a link within the text for overall clarity. Suggested-by: Quentin Schulz Signed-off-by: Tom Rini --- doc/develop/sending_patches.rst | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/develop/sending_patches.rst b/doc/develop/sending_patches.rst index 82efb717b179..990cb9912a92 100644 --- a/doc/develop/sending_patches.rst +++ b/doc/develop/sending_patches.rst @@ -76,11 +76,10 @@ General Patch Submission Rules compression, no attachments. Just plain text. The best way the generate patches is by using the ``git format-patch`` command. For a patch that is fixing a bug or regression of some sort, please use the ``master`` branch of - the mainline U-Boot git repository - (``https://source.denx.de/u-boot/u-boot.git``) as reference. For new - features, if the ``next`` branch has been opened (which happens with the - release of ``-rc2``) that branch should be used, otherwise ``master`` is - acceptable. + the mainline U-Boot git repository located at + https://source.denx.de/u-boot/u-boot.git as reference. For new features, if + the ``next`` branch has been opened (which happens with the release of + ``-rc2``) that branch should be used, otherwise ``master`` is acceptable. * Make sure that your mailer does not mangle the patch by automatic changes like wrapping of longer lines etc. Reviewed-by: Neil Armstrong
Re: [PATCH v2 0/3] Meson: R/W support for pages used by boot ROM
On 23/08/2024 10:29, Arseniy Krasnov wrote: Hi! Got it, thanks! On 23.08.2024 11:10, Michael Nazzareno Trimarchi wrote: Hi Arseniy On Thu, Aug 22, 2024 at 9:04 AM Arseniy Krasnov wrote: Hi, thanks! Thanks, Arseniy On 22.08.2024 00:17, Michael Nazzareno Trimarchi wrote: Hi I will read them tomorrow ;) Thank you for understanding All the series are delegated to Neil. I will review anyway but I think that will then pick from him Sure I can pick them if reviewed! Neil Michael Michael Il mer 21 ago 2024, 22:25 Arseniy Krasnov ha scritto: Hi, sorry, pls ping 😄 Thanks On 08.07.2024 10:13, Arseniy Krasnov wrote: Patchset is based on patchset for Linux (today merged to nand-next): https://lore.kernel.org/linux-mtd/20240507230903.3399594-1-avkras...@salutedevices.com/ Here is description from it: > Amlogic's boot ROM code needs that some pages on NAND must be written > in special "short" ECC mode with scrambling enabled. Such pages: > 1) Contain some metadata about hardware. > 2) Located with some interval starting from 0 offset, until some > specified offset. Interval and second offset are set in the > device tree. > > This patchset adds R/W support for such pages. To enable it we can setup > it in dts: > > nand-is-boot-medium; > amlogic,boot-pages = <1024>; > amlogic,boot-page-step = <128>; > > It means that each 128th page in range 0 to 1024 pages will be accessed > in special mode ("short" ECC + scrambling). In practice this feature is > needed when we want to update first block of NAND - driver will enable > required mode by itself using value from device tree. The only difference is that patchset for Linux updates DT bindings, while this adds NAND_IS_BOOT_MEDIUM flag support. Changelog: v1 -> v2: * Pls see per-patch changelog. Arseniy Krasnov (3): mtd: rawnand: nand_base: support for 'NAND_IS_BOOT_MEDIUM' flag mtd: rawnand: meson: refactor use of 'meson_nfc_cmd_access()' mtd: rawnand: meson: read/write access for boot ROM pages drivers/mtd/nand/raw/meson_nand.c | 84 +-- drivers/mtd/nand/raw/nand_base.c | 3 ++ include/linux/mtd/rawnand.h | 5 ++ 3 files changed, 65 insertions(+), 27 deletions(-)
Re: [PATCH v2 1/7] clk/qcom: add initial clock driver for sc7280
On 22/08/2024 14:12, Caleb Connolly wrote: On 22/08/2024 04:59, Simon Glass wrote: Hi Caleb, On Wed, 21 Aug 2024 at 14:33, Caleb Connolly wrote: On 21/08/2024 20:27, Simon Glass wrote: Hi Caleb, On Wed, 21 Aug 2024 at 10:47, Caleb Connolly wrote: On 21/08/2024 18:16, Simon Glass wrote: Hi Caleb, On Wed, 21 Aug 2024 at 08:49, Caleb Connolly wrote: On 21/08/2024 16:37, Simon Glass wrote: Hi Caleb, On Wed, 21 Aug 2024 at 08:11, Caleb Connolly wrote: Hi Simon, +U_BOOT_DRIVER(gcc_sc7280) = { + .name = "gcc_sc7280", + .id = UCLASS_NOP, + .of_match = gcc_sc7280_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; This should use driver model, with a UCLASS_CLK and UCLASS_RESET Please refer to qcom_cc_bind() which binds the clock, reset, and power domain drivers. Gosh, why? Are these devices not in the devicetree? They are, the gcc block contains clock, reset, and pd parts. On Linux this is not an issue because a single device can be multiple different classes (e..g when you register a reset you do it for a device) whereas U-Boot requires a device per class. e.g. see devm_reset_controller_register() in Linux, it populates a struct reset_controller_dev which references the struct device created for the node. In U-Boot you have to create a new device which _is_ the reset controller. OK, I see. Rockchip has a CRU (Clock & Reset Unit) which uses syscon to access registers. The clock driver 'owns' the node in U-Boot and it manually binds a reset driver. It isn't great, either. Looking at drivers/clk/qcom/clock-sdm845.c (for example), I can't actually find "qcom,gcc-sdm845" (for example) in U-Boot, except as a binding. Can you please point me to the node? It's in dts/upstream/src/arm64/qcom/sdm845.dtsi Re devm_reset_controller_register(), yes the U-Boot driver model is a lot more regular, e.g. we don't really want drivers creating their own struct udevice. We want all devices to be created automatically by the devicetree and most memory allocations to be done automatically. This helps to reduce code size and execution time. You probably know all this :-) Yeah, U-Boot's model is simpler for most cases. This makes sense. But it doesn't reflect the reality of DT so well in cases like this. To a significant degree, the devicetree bindings are created without much thought to efficient operation in U-Boot. I hope that eventually this might change. I strongly disagree with this mental model. This is the approach I see vendors take in their BSP sources and the result is not pleasant. DT should (within reason) never be written with the OS in mind. It is an agnostic structure to describe the hardware. I think the new power sequencing subsystem in Linux does a good job at embodying how we should approach consuming DT. I'm only really involved in mainline and don't really see vendor trees much. An example is where pinctrl has a GPIO controller but it is not mentioned in the devicetree. It would be better for U-Boot to add a subnode for each GPIO controller. In general, if the SoC has a device, it should be in the devicetree. The concept of a device is an OS one. DT is not "telling the OS how to use the hardware", it is describing the hardware. This distinction is important because it's the only way to ensure that future OS changes can be done regardless of the DT. And also of course because different OS's will have different ideas of how to model devices (case in point). The GCC block on Qualcomm platforms is a single hardware block. The datasheets and hardware programming guides describe it as such. The clocks, resets, and GDSCs are all entwined at the hardware level. They also have overlapping register addresses. The further away DT gets from describing the hardware in favour of simplifying the OS, the more likely we are to start running into issues with fitting hardware changes into our arbitrary model. I completely agree with everything you are saying, but you don't go far enough. We should additionally require that all hardware has a description in the devicetree. See for example the GPIO controller I mentioned. When Linux wants it, it gets it, when it doesn't, it isn't there. Sorry to have to say it, but that's not right. If it's only used in U-Boot, that's justification enough to add the node upstream? Part of this difference (between U-Boot and Linux) comes about because Linux device setup is fairly manual, whereas U-Boot tries to put all of that in common DM code. Whenever you are including dm/device-internal.h that is often a sign that the binding is causing issues. To me this indicates an inability for U-Boot's DM to handle complicated devices. I don't think U-Boot should dictate the design of devicetree. I don't know how else to describe this. This issue has been litigated over and over again on the kernel mailing list. Every
Re: [PATCH] board/qualcomm: add debug config fragments for some SoCs
On 21/08/2024 01:00, Caleb Connolly wrote: We already have some documentation describing how to enable debug UART for Qualcomm SoCs. However the UART address varies per-soc... Add some config fragments to enable debug UART for few well supported SoCs. These can be used like: $ make qcom_defconfig debug-sdm845.config Signed-off-by: Caleb Connolly --- board/qualcomm/debug-sdm845.config | 5 + board/qualcomm/debug-sm6115.config | 5 + board/qualcomm/debug-sm8250.config | 5 + 3 files changed, 15 insertions(+) create mode 100644 board/qualcomm/debug-sdm845.config create mode 100644 board/qualcomm/debug-sm6115.config create mode 100644 board/qualcomm/debug-sm8250.config diff --git a/board/qualcomm/debug-sdm845.config b/board/qualcomm/debug-sdm845.config new file mode 100644 index ..31ad6d02a3a7 --- /dev/null +++ b/board/qualcomm/debug-sdm845.config @@ -0,0 +1,5 @@ +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_DEBUG_UART_BASE=0xa84000 +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_CLOCK=7372800 diff --git a/board/qualcomm/debug-sm6115.config b/board/qualcomm/debug-sm6115.config new file mode 100644 index ..131c6e230de8 --- /dev/null +++ b/board/qualcomm/debug-sm6115.config @@ -0,0 +1,5 @@ +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_DEBUG_UART_BASE=0x4a9 +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_CLOCK=14745600 diff --git a/board/qualcomm/debug-sm8250.config b/board/qualcomm/debug-sm8250.config new file mode 100644 index ..4d3cc4cc97f4 --- /dev/null +++ b/board/qualcomm/debug-sm8250.config @@ -0,0 +1,5 @@ +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_DEBUG_UART_BASE=0xa9 +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_CLOCK=14745600 Reviewed-by: Neil Armstrong
Re: [PATCH 5/7] qcom_defconfig: enable SC7280 clocks
On 09/08/2024 02:48, Caleb Connolly wrote: Enable clocks on SC7280 Signed-off-by: Caleb Connolly --- configs/qcom_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index 24b71ba7be29..1a079264a554 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -44,8 +44,9 @@ CONFIG_CLK=y CONFIG_CLK_QCOM_APQ8016=y CONFIG_CLK_QCOM_APQ8096=y CONFIG_CLK_QCOM_QCM2290=y CONFIG_CLK_QCOM_QCS404=y +CONFIG_CLK_QCOM_SC7280=y CONFIG_CLK_QCOM_SDM845=y CONFIG_CLK_QCOM_SM6115=y CONFIG_CLK_QCOM_SM8250=y CONFIG_CLK_QCOM_SM8550=y Reviewed-by: Neil Armstrong
Re: [PATCH 4/7] iommu: qcom-smmu: add sc7280-smmu-500 compatible
On 09/08/2024 02:48, Caleb Connolly wrote: This soc doesn't have the generic compatible. Signed-off-by: Caleb Connolly --- drivers/iommu/qcom-hyp-smmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/qcom-hyp-smmu.c b/drivers/iommu/qcom-hyp-smmu.c index 7b646d840dd4..1b5a09bb7b39 100644 --- a/drivers/iommu/qcom-hyp-smmu.c +++ b/drivers/iommu/qcom-hyp-smmu.c @@ -380,8 +380,9 @@ static struct iommu_ops qcom_smmu_ops = { }; static const struct udevice_id qcom_smmu500_ids[] = { { .compatible = "qcom,sdm845-smmu-500" }, + { .compatible = "qcom,sc7280-smmu-500" }, { .compatible = "qcom,smmu-500", }, { /* sentinel */ } }; Reviewed-by: Neil Armstrong
Re: [PATCH 1/7] clk/qcom: add initial clock driver for sc7280
USB3_PRIM_AXI_CLK: + qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK); + fallthrough; + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK); + break; + } + + qcom_gate_clk_en(priv, clk->id); + + return 0; +} + +static const struct qcom_reset_map sc7280_gcc_resets[] = { + [GCC_PCIE_0_BCR] = { 0x6b000 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_1_BCR] = { 0x8d000 }, + [GCC_PCIE_1_PHY_BCR] = { 0x8e01c }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 }, + [GCC_SDCC1_BCR] = { 0x75000 }, + [GCC_SDCC2_BCR] = { 0x14000 }, + [GCC_SDCC4_BCR] = { 0x16000 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB30_PRIM_BCR] = { 0xf000 }, + [GCC_USB30_SEC_BCR] = { 0x9e000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x5 }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, +}; + +static const struct qcom_power_map sc7280_gdscs[] = { + [GCC_UFS_PHY_GDSC] = { 0x77004 }, + [GCC_USB30_PRIM_GDSC] = { 0xf004 }, +}; + +static struct msm_clk_data qcs404_gcc_data = { + .resets = sc7280_gcc_resets, + .num_resets = ARRAY_SIZE(sc7280_gcc_resets), + .clks = sc7280_clks, + .num_clks = ARRAY_SIZE(sc7280_clks), + + .power_domains = sc7280_gdscs, + .num_power_domains = ARRAY_SIZE(sc7280_gdscs), + + .enable = sc7280_enable, + .set_rate = sc7280_set_rate, +}; + +static const struct udevice_id gcc_sc7280_of_match[] = { + { + .compatible = "qcom,gcc-sc7280", + .data = (ulong)&qcs404_gcc_data, + }, + { } +}; + +U_BOOT_DRIVER(gcc_sc7280) = { + .name = "gcc_sc7280", + .id = UCLASS_NOP, + .of_match = gcc_sc7280_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; Reviewed-by: Neil Armstrong
Re: [PATCH 00/11] mach-snapdragon: various improvements for newer boards
On 09/08/2024 01:59, Caleb Connolly wrote: Supporting the newer SM8550 and SM8650 SoCs unfortunately requires a bump in complexity for us. Qualcomm changed a lot about how the memory map is handed over to the "kernel", adding many holes, not mapping certain regions, and adding regions with 0 size. The SM8650 HDK has a whopping 14 memory regions, some as small as 44k. Supporting this properly has proven to be a bit of a headache, but I think this implementation is "pretty good". In addition, we set a valid fallback fdt_addr_r in the U-Boot environment, allocate a buffer for fastboot, and set the loadaddr variable too. board_fdt_blob_setup() is refactored for readability and potential future expansion (e.g. if supporting multi-dtb FIT becomes desirable). Finally, a function is proposed to allow for mapping new memory regions at runtime, and the cmd-db driver makes use of it to map itself, since SM8650 boards don't seem to include it in their memory map. Tested on SM8650 HDK, SDM845 OnePlus 6, SM6115 RB2, SM8250 RB5. --- Caleb Connolly (10): mach-snapdragon: refactor board_fdt_blob_setup() mach-snapdragon: parse memory ourselves mach-snapdragon: set serial number mach-snapdragon: allocate fastboot buffer dynamically mach-snapdragon: populate fallback FDT mach-snapdragon: set loadaddr armv8: mmu: add a way to map additional regions soc: qcom: cmd-db: use strncmp() instead of memcmp() soc: qcom: cmd-db: map cmd-db region qcom_defconfig: bump CONFIG_NR_DRAM_BANKS Neil Armstrong (1): mach-snapdragon: use 1MiB for get_page_table_size() arch/arm/cpu/armv8/cache_v8.c| 25 + arch/arm/include/asm/system.h| 10 ++ arch/arm/mach-snapdragon/board.c | 203 ++- configs/qcom_defconfig | 1 + drivers/soc/qcom/cmd-db.c| 11 ++- 5 files changed, 221 insertions(+), 29 deletions(-) --- change-id: 20240809-b4-snapdragon-improvements-fd6d714a7fbd base-commit: a2ce853383b18a2cf920268ee341f2585a11adef // Caleb (they/them) Thanks for posting those :-) Please add my: Reviewed-by: Neil Armstrong I'll rebase my tree and test it ASAP ! Neil
[PATCH v2 3/3] usb: dwc3: invalidate dcache on buffer used in interrupt handling
On Qualcomm systems, the setup buffer and even buffers are in a bad state at interrupt handling, so invalidate the dcache lines for the setup_buf and event buffer to make sure we read correct data written by the hardware. This fixes the following error: dwc3-generic-peripheral usb@a60: UNKNOWN IRQ type -1 dwc3-generic-peripheral usb@a60: UNKNOWN IRQ type 4673109 and invalid situation in dwc3_gadget_giveback() because setup_buf content is read at 0s and leads to fatal crash fixed by [1]. [1] https://lore.kernel.org/all/20240528-topic-sm8x50-dwc3-gadget-crash-fix-v1-1-58434ab4b...@linaro.org/ Reviewed-by: Mattijs Korpershoek Signed-off-by: Neil Armstrong --- drivers/usb/dwc3/ep0.c| 2 ++ drivers/usb/dwc3/gadget.c | 2 ++ drivers/usb/dwc3/io.h | 8 3 files changed, 12 insertions(+) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 0c7e0123368..fc1d5892106 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -743,6 +743,8 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, if (!dwc->gadget_driver) goto out; + dwc3_invalidate_cache(ctrl, sizeof(*ctrl)); + len = le16_to_cpu(ctrl->wLength); if (!len) { dwc->three_stage_setup = false; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d41b590afb8..0bc9aee4daa 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2503,6 +2503,8 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) while (left > 0) { union dwc3_event event; + dwc3_invalidate_cache((uintptr_t)evt->buf, evt->length); + event.raw = *(u32 *) (evt->buf + evt->lpos); dwc3_process_event_entry(dwc, &event); diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index 1aaf5413c6d..7cf05203b0d 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -55,4 +55,12 @@ static inline void dwc3_flush_cache(uintptr_t addr, int length) flush_dcache_range(start_addr, end_addr); } + +static inline void dwc3_invalidate_cache(uintptr_t addr, int length) +{ + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + length, ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start_addr, end_addr); +} #endif /* __DRIVERS_USB_DWC3_IO_H */ -- 2.34.1
[PATCH v2 2/3] usb: dwc3: fix dcache flush range calculation
The current flush operation will omit doing a flush/invalidate on the first and last bytes if the base address and size are not aligned with DMA_MINALIGN. This causes operation failures Qualcomm platforms. Take in account the alignment and size of the buffer and also flush the previous and last cacheline. Reviewed-by: Mattijs Korpershoek Signed-off-by: Neil Armstrong --- drivers/usb/dwc3/io.h | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index 04791d4c9be..1aaf5413c6d 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -50,6 +50,9 @@ static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value) static inline void dwc3_flush_cache(uintptr_t addr, int length) { - flush_dcache_range(addr, addr + ROUND(length, CACHELINE_SIZE)); + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + length, ARCH_DMA_MINALIGN); + + flush_dcache_range(start_addr, end_addr); } #endif /* __DRIVERS_USB_DWC3_IO_H */ -- 2.34.1
[PATCH v2 0/3] dwc3: gadget: properly fix cache operations
We experience huge problems with cache handling on Qualcomm systems, and it appears the dcache handling in the DWC3 gadget code is quite wrong and causes operational issues. This serie fixes the dcache operations on unaligned data, and properly invalidate buffers when reading back data from hardware. Signed-off-by: Neil Armstrong --- Changes in v2: - Fix typo in drivers/usb/dwc3/core.h and rewrite patch 1 commit message - Link to v1: https://lore.kernel.org/r/20240719-u-boot-dwc3-gadget-dcache-fixup-v1-0-58a5f026e...@linaro.org --- Neil Armstrong (3): usb: dwc3: allocate setup_buf with dma_alloc_coherent() usb: dwc3: fix dcache flush range calculation usb: dwc3: invalidate dcache on buffer used in interrupt handling drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/ep0.c| 6 -- drivers/usb/dwc3/gadget.c | 10 ++ drivers/usb/dwc3/io.h | 13 - 4 files changed, 24 insertions(+), 7 deletions(-) --- base-commit: 3f772959501c99fbe5aa0b22a36efe3478d1ae1c change-id: 20240719-u-boot-dwc3-gadget-dcache-fixup-ea1e92758663 Best regards, -- Neil Armstrong
[PATCH v2 1/3] usb: dwc3: allocate setup_buf with dma_alloc_coherent()
Since setup_buf is also consumed by hardware DMA, aligns it's allocation like other hardware buffers by introduce setup_buf_addr populated by dma_alloc_coherent(), and use it to pass the physical address of the buffer to the hardware. Reviewed-by: Mattijs Korpershoek Signed-off-by: Neil Armstrong --- drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/ep0.c| 4 ++-- drivers/usb/dwc3/gadget.c | 8 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 7374ce950da..b572ea340c8 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -670,6 +670,7 @@ struct dwc3_scratchpad_array { * @ep0_trb: dma address of ep0_trb * @ep0_usb_req: dummy req used while handling STD USB requests * @ep0_bounce_addr: dma address of ep0_bounce + * @setup_buf_addr: dma address of setup_buf * @scratch_addr: dma address of scratchbuf * @lock: for synchronizing * @dev: pointer to our struct device @@ -757,6 +758,7 @@ struct dwc3 { dma_addr_t ep0_trb_addr; dma_addr_t ep0_bounce_addr; dma_addr_t scratch_addr; + dma_addr_t setup_buf_addr; struct dwc3_request ep0_usb_req; /* device lock */ diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 16b11ce3d9f..0c7e0123368 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -381,7 +381,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, dep = dwc->eps[0]; dwc->ep0_usb_req.dep = dep; dwc->ep0_usb_req.request.length = sizeof(*response_pkt); - dwc->ep0_usb_req.request.buf = dwc->setup_buf; + dwc->ep0_usb_req.request.buf = (void *)dwc->setup_buf_addr; dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); @@ -663,7 +663,7 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dep = dwc->eps[0]; dwc->ep0_usb_req.dep = dep; dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; - dwc->ep0_usb_req.request.buf = dwc->setup_buf; + dwc->ep0_usb_req.request.buf = (void *)dwc->setup_buf_addr; dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 7d6bcc2627f..d41b590afb8 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2622,8 +2622,8 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err1; } - dwc->setup_buf = memalign(CONFIG_SYS_CACHELINE_SIZE, - DWC3_EP0_BOUNCE_SIZE); + dwc->setup_buf = dma_alloc_coherent(DWC3_EP0_BOUNCE_SIZE, + (unsigned long *)&dwc->setup_buf_addr); if (!dwc->setup_buf) { ret = -ENOMEM; goto err2; @@ -2670,7 +2670,7 @@ err4: dma_free_coherent(dwc->ep0_bounce); err3: - kfree(dwc->setup_buf); + dma_free_coherent(dwc->setup_buf); err2: dma_free_coherent(dwc->ep0_trb); @@ -2692,7 +2692,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dma_free_coherent(dwc->ep0_bounce); - kfree(dwc->setup_buf); + dma_free_coherent(dwc->setup_buf); dma_free_coherent(dwc->ep0_trb); -- 2.34.1
Re: [PATCH 1/3] usb: dwc3: allocate setup_buf with dma_alloc_coherent()
On 24/07/2024 17:03, Mattijs Korpershoek wrote: Hi Neil, Thank you for the patch. On ven., juil. 19, 2024 at 15:56, Neil Armstrong wrote: Also allocate the setup_buf with dma_alloc_coherent() since it's The subject of the patch says: "usb: dwc3: allocate setup_buf with dma_alloc_coherent()" Isn't this line just repeating the title? also consumed by the hardware DMA. Yeah it's a verbose rewrite of the subject, I'll rewrite it to be less bad! thanks Neil Signed-off-by: Neil Armstrong --- drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/ep0.c| 4 ++-- drivers/usb/dwc3/gadget.c | 8 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 7374ce950da..ce35460c405 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -670,6 +670,7 @@ struct dwc3_scratchpad_array { * @ep0_trb: dma address of ep0_trb * @ep0_usb_req: dummy req used while handling STD USB requests * @ep0_bounce_addr: dma address of ep0_bounce + * @setup_buf_addr: dma address if setup_buf if -> of Both remarks being minor, please add: Reviewed-by: Mattijs Korpershoek * @scratch_addr: dma address of scratchbuf * @lock: for synchronizing * @dev: pointer to our struct device @@ -757,6 +758,7 @@ struct dwc3 { dma_addr_t ep0_trb_addr; dma_addr_t ep0_bounce_addr; dma_addr_t scratch_addr; + dma_addr_t setup_buf_addr; struct dwc3_request ep0_usb_req; /* device lock */ diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 16b11ce3d9f..0c7e0123368 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -381,7 +381,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, dep = dwc->eps[0]; dwc->ep0_usb_req.dep = dep; dwc->ep0_usb_req.request.length = sizeof(*response_pkt); - dwc->ep0_usb_req.request.buf = dwc->setup_buf; + dwc->ep0_usb_req.request.buf = (void *)dwc->setup_buf_addr; dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); @@ -663,7 +663,7 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dep = dwc->eps[0]; dwc->ep0_usb_req.dep = dep; dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; - dwc->ep0_usb_req.request.buf = dwc->setup_buf; + dwc->ep0_usb_req.request.buf = (void *)dwc->setup_buf_addr; dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 7d6bcc2627f..d41b590afb8 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2622,8 +2622,8 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err1; } - dwc->setup_buf = memalign(CONFIG_SYS_CACHELINE_SIZE, - DWC3_EP0_BOUNCE_SIZE); + dwc->setup_buf = dma_alloc_coherent(DWC3_EP0_BOUNCE_SIZE, + (unsigned long *)&dwc->setup_buf_addr); if (!dwc->setup_buf) { ret = -ENOMEM; goto err2; @@ -2670,7 +2670,7 @@ err4: dma_free_coherent(dwc->ep0_bounce); err3: - kfree(dwc->setup_buf); + dma_free_coherent(dwc->setup_buf); err2: dma_free_coherent(dwc->ep0_trb); @@ -2692,7 +2692,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dma_free_coherent(dwc->ep0_bounce); - kfree(dwc->setup_buf); + dma_free_coherent(dwc->setup_buf); dma_free_coherent(dwc->ep0_trb); -- 2.34.1
[PATCH 3/3] usb: dwc3: invalidate dcache on buffer used in interrupt handling
On Qualcomm systems, the setup buffer and even buffers are in a bad state at interrupt handling, so invalidate the dcache lines for the setup_buf and event buffer to make sure we read correct data written by the hardware. This fixes the following error: dwc3-generic-peripheral usb@a60: UNKNOWN IRQ type -1 dwc3-generic-peripheral usb@a60: UNKNOWN IRQ type 4673109 and invalid situation in dwc3_gadget_giveback() because setup_buf content is read at 0s and leads to fatal crash fixed by [1]. [1] https://lore.kernel.org/all/20240528-topic-sm8x50-dwc3-gadget-crash-fix-v1-1-58434ab4b...@linaro.org/ Signed-off-by: Neil Armstrong --- drivers/usb/dwc3/ep0.c| 2 ++ drivers/usb/dwc3/gadget.c | 2 ++ drivers/usb/dwc3/io.h | 8 3 files changed, 12 insertions(+) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 0c7e0123368..fc1d5892106 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -743,6 +743,8 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, if (!dwc->gadget_driver) goto out; + dwc3_invalidate_cache(ctrl, sizeof(*ctrl)); + len = le16_to_cpu(ctrl->wLength); if (!len) { dwc->three_stage_setup = false; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d41b590afb8..0bc9aee4daa 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2503,6 +2503,8 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) while (left > 0) { union dwc3_event event; + dwc3_invalidate_cache((uintptr_t)evt->buf, evt->length); + event.raw = *(u32 *) (evt->buf + evt->lpos); dwc3_process_event_entry(dwc, &event); diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index 1aaf5413c6d..7cf05203b0d 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -55,4 +55,12 @@ static inline void dwc3_flush_cache(uintptr_t addr, int length) flush_dcache_range(start_addr, end_addr); } + +static inline void dwc3_invalidate_cache(uintptr_t addr, int length) +{ + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + length, ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start_addr, end_addr); +} #endif /* __DRIVERS_USB_DWC3_IO_H */ -- 2.34.1
[PATCH 2/3] usb: dwc3: fix dcache flush range calculation
The current flush operation will omit doing a flush/invalidate on the first and last bytes if the base address and size are not aligned with DMA_MINALIGN. This causes operation failures Qualcomm platforms. Take in account the alignment and size of the buffer and also flush the previous and last cacheline. Signed-off-by: Neil Armstrong --- drivers/usb/dwc3/io.h | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index 04791d4c9be..1aaf5413c6d 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -50,6 +50,9 @@ static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value) static inline void dwc3_flush_cache(uintptr_t addr, int length) { - flush_dcache_range(addr, addr + ROUND(length, CACHELINE_SIZE)); + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + length, ARCH_DMA_MINALIGN); + + flush_dcache_range(start_addr, end_addr); } #endif /* __DRIVERS_USB_DWC3_IO_H */ -- 2.34.1
[PATCH 1/3] usb: dwc3: allocate setup_buf with dma_alloc_coherent()
Also allocate the setup_buf with dma_alloc_coherent() since it's also consumed by the hardware DMA. Signed-off-by: Neil Armstrong --- drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/ep0.c| 4 ++-- drivers/usb/dwc3/gadget.c | 8 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 7374ce950da..ce35460c405 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -670,6 +670,7 @@ struct dwc3_scratchpad_array { * @ep0_trb: dma address of ep0_trb * @ep0_usb_req: dummy req used while handling STD USB requests * @ep0_bounce_addr: dma address of ep0_bounce + * @setup_buf_addr: dma address if setup_buf * @scratch_addr: dma address of scratchbuf * @lock: for synchronizing * @dev: pointer to our struct device @@ -757,6 +758,7 @@ struct dwc3 { dma_addr_t ep0_trb_addr; dma_addr_t ep0_bounce_addr; dma_addr_t scratch_addr; + dma_addr_t setup_buf_addr; struct dwc3_request ep0_usb_req; /* device lock */ diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 16b11ce3d9f..0c7e0123368 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -381,7 +381,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, dep = dwc->eps[0]; dwc->ep0_usb_req.dep = dep; dwc->ep0_usb_req.request.length = sizeof(*response_pkt); - dwc->ep0_usb_req.request.buf = dwc->setup_buf; + dwc->ep0_usb_req.request.buf = (void *)dwc->setup_buf_addr; dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); @@ -663,7 +663,7 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dep = dwc->eps[0]; dwc->ep0_usb_req.dep = dep; dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; - dwc->ep0_usb_req.request.buf = dwc->setup_buf; + dwc->ep0_usb_req.request.buf = (void *)dwc->setup_buf_addr; dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 7d6bcc2627f..d41b590afb8 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2622,8 +2622,8 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err1; } - dwc->setup_buf = memalign(CONFIG_SYS_CACHELINE_SIZE, - DWC3_EP0_BOUNCE_SIZE); + dwc->setup_buf = dma_alloc_coherent(DWC3_EP0_BOUNCE_SIZE, + (unsigned long *)&dwc->setup_buf_addr); if (!dwc->setup_buf) { ret = -ENOMEM; goto err2; @@ -2670,7 +2670,7 @@ err4: dma_free_coherent(dwc->ep0_bounce); err3: - kfree(dwc->setup_buf); + dma_free_coherent(dwc->setup_buf); err2: dma_free_coherent(dwc->ep0_trb); @@ -2692,7 +2692,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dma_free_coherent(dwc->ep0_bounce); - kfree(dwc->setup_buf); + dma_free_coherent(dwc->setup_buf); dma_free_coherent(dwc->ep0_trb); -- 2.34.1
[PATCH 0/3] dwc3: gadget: properly fix cache operations
We experience huge problems with cache handling on Qualcomm systems, and it appears the dcache handling in the DWC3 gadget code is quite wrong and causes operational issues. This serie fixes the dcache operations on unaligned data, and properly invalidate buffers when reading back data from hardware. Signed-off-by: Neil Armstrong --- Neil Armstrong (3): usb: dwc3: allocate setup_buf with dma_alloc_coherent() usb: dwc3: fix dcache flush range calculation usb: dwc3: invalidate dcache on buffer used in interrupt handling drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/ep0.c| 6 -- drivers/usb/dwc3/gadget.c | 10 ++ drivers/usb/dwc3/io.h | 13 - 4 files changed, 24 insertions(+), 7 deletions(-) --- base-commit: 3f772959501c99fbe5aa0b22a36efe3478d1ae1c change-id: 20240719-u-boot-dwc3-gadget-dcache-fixup-ea1e92758663 Best regards, -- Neil Armstrong
[PATCH 3/4] ufs: split flush and invalidate to only invalidate when required
There is no need to flush and invalidate all data updated by the driver, mainly because on ARM platforms flush also invalidates the cachelines. Split the function in two and add the appropriate cacheline invalidates after the UFS DMA operation finishes to make sure we read from memory. Flushing then invalidating cacheline unaligned data causes data corruption issues on Qualcomm platforms, and is largely unnecessary anyway, so let's cleanup the cache operations. Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.c | 45 ++--- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index db487d1ff9a..76cda83ce81 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -697,17 +697,28 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) } /** - * ufshcd_cache_flush_and_invalidate - Flush and invalidate cache + * ufshcd_cache_flush - Flush cache * - * Flush and invalidate cache in aligned address..address+size range. - * The invalidation is in place to avoid stale data in cache. + * Flush cache in aligned address..address+size range. */ -static void ufshcd_cache_flush_and_invalidate(void *addr, unsigned long size) +static void ufshcd_cache_flush(void *addr, unsigned long size) { uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); flush_dcache_range(start_addr, end_addr); +} + +/** + * ufshcd_cache_invalidate - Invalidate cache + * + * Invalidate cache in aligned address..address+size range. + */ +static void ufshcd_cache_invalidate(void *addr, unsigned long size) +{ + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); + invalidate_dcache_range(start_addr, end_addr); } @@ -755,7 +766,7 @@ static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, req_desc->prd_table_length = 0; - ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc)); + ufshcd_cache_flush(req_desc, sizeof(*req_desc)); } static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, @@ -786,13 +797,13 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, /* Copy the Descriptor */ if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) { memcpy(ucd_req_ptr + 1, query->descriptor, len); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr)); } else { - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); } memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) @@ -810,8 +821,8 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } /** @@ -878,6 +889,8 @@ static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) */ static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) { + ufshcd_cache_invalidate(ucd_rsp_ptr, sizeof(*ucd_rsp_ptr)); + return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24; } @@ -889,6 +902,8 @@ static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba) { struct utp_transfer_req_desc *req_desc = hba->utrdl; + ufshcd_cache_invalidate(req_desc, sizeof(*req_desc)); + return le32_to_cpu(req_desc->header.dword_2) & MASK_OCS; } @@ -1438,8 +1453,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba, memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len); memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry, @@ -1462,7 +1477,7 @@ static void prepare_prdt_table(struct ufs_hba *hba, str