summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2025-04-11 09:12:16 -0600
committerTom Rini <trini@konsulko.com>2025-04-11 09:12:16 -0600
commitff0b7d741dec48c9d1ce5e80ada5eaeac19b1b93 (patch)
tree8f3952ebeb31a9ce0a35d419121e80cae41b547b
parent295376ce8a32268a1bb0879eb0448e0c0e580727 (diff)
parentf3563fc30356c8079527b90e532407050dff7c7b (diff)
Merge tag 'qcom-for-2025.07' of https://source.denx.de/u-boot/custodians/u-boot-snapdragon
Qualcomm changes for v2025.07: CI: https://source.denx.de/u-boot/custodians/u-boot-snapdragon/-/pipelines/25653 There's been a surprising amount of activity lately on the Qualcomm side with the two oldest boards getting some fresh attention and a lot of cleanup and polish going on across the board. * SDM660 gets USB phy fixes and a pinctrl driver * The recently added SA8775P/QCS9100 SoC gets a pinctrl driver * The Qualcomm pinctrl driver now handles reserved pins correctly, fixing crashes on some boards when running "gpio status -a" * OF_UPSTREAM_BUILD_VENDOR is enabled in qcom_defconfig * SDM845 and SC7280 get missing clocks added (since we're now stricter about those). This gets USB working more reliably in more cases. * DM_USB_GADGET is enabled for all boards using DWC3 and fasbtoot is enabled too * A bug in the livetree fixup code is fixed (making USB work on a lot more platforms) * Button label lookup is made case insensitive* bootretry becomes more dynamic, allowing it to be hijacked to make a "persistent" boot menu that allows dropping to U-Boot shell later on * A new qcom-phone.config fragment is added along with a phone-specific default environment and phone-specific debugging/bringup docs. These make U-Boot more usable on devices without a serial port or keyboard. * The db820c gets fixed up and updated documentation * The db410c also gets some love and modernisation as well as a new reviewer. * A new driver is added for the USB VBUS regulator found on various Qualcomm PMICs * The Qualcomm SPMI driver gets some fixes and cleanup for SPMI v5 and v7 support.
-rw-r--r--arch/arm/Kconfig3
-rw-r--r--arch/arm/dts/apq8016-sbc-u-boot.dtsi2
-rw-r--r--arch/arm/mach-snapdragon/include/mach/gpio.h15
-rw-r--r--arch/arm/mach-snapdragon/of_fixup.c20
-rw-r--r--board/qualcomm/dragonboard410c/MAINTAINERS3
-rw-r--r--board/qualcomm/dragonboard410c/dragonboard410c.c67
-rw-r--r--board/qualcomm/dragonboard410c/dragonboard410c.env38
-rw-r--r--board/qualcomm/dragonboard820c/dragonboard820c.c2
-rw-r--r--board/qualcomm/dragonboard820c/readme.txt47
-rw-r--r--board/qualcomm/qcom-phone.config29
-rw-r--r--board/qualcomm/qcom-phone.env47
-rw-r--r--boot/Kconfig7
-rw-r--r--boot/bootretry.c2
-rw-r--r--common/cli_hush.c6
-rw-r--r--common/cli_hush_upstream.c6
-rw-r--r--configs/dragonboard410c_defconfig11
-rw-r--r--configs/dragonboard820c_defconfig2
-rw-r--r--configs/hmibsc_defconfig1
-rw-r--r--configs/qcom_defconfig8
-rw-r--r--doc/board/qualcomm/board.rst5
-rw-r--r--doc/board/qualcomm/index.rst1
-rw-r--r--doc/board/qualcomm/phones.rst144
-rw-r--r--drivers/button/button-qcom-pmic.c8
-rw-r--r--drivers/button/button-uclass.c2
-rw-r--r--drivers/clk/clk-stub.c3
-rw-r--r--drivers/clk/qcom/clock-apq8096.c5
-rw-r--r--drivers/clk/qcom/clock-sc7280.c11
-rw-r--r--drivers/clk/qcom/clock-sdm845.c3
-rw-r--r--drivers/gpio/msm_gpio.c53
-rw-r--r--drivers/phy/qcom/phy-qcom-qusb2.c44
-rw-r--r--drivers/pinctrl/qcom/Kconfig15
-rw-r--r--drivers/pinctrl/qcom/Makefile2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcom.c67
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sa8775p.c623
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sdm660.c226
-rw-r--r--drivers/power/regulator/Kconfig7
-rw-r--r--drivers/power/regulator/Makefile1
-rw-r--r--drivers/power/regulator/qcom-rpmh-regulator.c45
-rw-r--r--drivers/power/regulator/qcom_usb_vbus_regulator.c111
-rw-r--r--drivers/spmi/spmi-msm.c59
-rw-r--r--include/configs/dragonboard410c.h11
41 files changed, 1598 insertions, 164 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b7311d3b754..d8c99d3ab19 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1120,12 +1120,13 @@ config ARCH_SNAPDRAGON
select SPMI
select BOARD_LATE_INIT
select OF_BOARD
- select SAVE_PREV_BL_FDT_ADDR
+ select SAVE_PREV_BL_FDT_ADDR if !ENABLE_ARM_SOC_BOOT0_HOOK
select LINUX_KERNEL_IMAGE_HEADER if !ENABLE_ARM_SOC_BOOT0_HOOK
select SYSRESET
select SYSRESET_PSCI
imply OF_UPSTREAM
imply CMD_DM
+ imply DM_USB_GADGET
config ARCH_SOCFPGA
bool "Altera SOCFPGA family"
diff --git a/arch/arm/dts/apq8016-sbc-u-boot.dtsi b/arch/arm/dts/apq8016-sbc-u-boot.dtsi
index 585d54d2962..c8a46ed1448 100644
--- a/arch/arm/dts/apq8016-sbc-u-boot.dtsi
+++ b/arch/arm/dts/apq8016-sbc-u-boot.dtsi
@@ -6,7 +6,7 @@
/ {
/* When running as a first-stage bootloader this isn't filled in automatically */
memory@80000000 {
- reg = <0 0x80000000 0 0x3da00000>;
+ reg = <0 0x80000000 0 0x40000000>;
};
};
diff --git a/arch/arm/mach-snapdragon/include/mach/gpio.h b/arch/arm/mach-snapdragon/include/mach/gpio.h
index cc8f405e20b..11e8104baf2 100644
--- a/arch/arm/mach-snapdragon/include/mach/gpio.h
+++ b/arch/arm/mach-snapdragon/include/mach/gpio.h
@@ -46,4 +46,19 @@ static inline bool qcom_is_special_pin(const struct msm_pin_data *pindata, unsig
return pindata->special_pins_start && pin >= pindata->special_pins_start;
}
+struct udevice;
+
+/**
+ * msm_pinctrl_is_reserved() - Check if a pin lies in a reserved range
+ *
+ * @dev: pinctrl device
+ * @pin: Pin number
+ *
+ * Returns: true if pin is reserved, otherwise false
+ *
+ * Call using dev_get_parent() from the GPIO device, it is a child of
+ * the pinctrl device.
+ */
+bool msm_pinctrl_is_reserved(struct udevice *dev, unsigned int pin);
+
#endif /* _QCOM_GPIO_H_ */
diff --git a/arch/arm/mach-snapdragon/of_fixup.c b/arch/arm/mach-snapdragon/of_fixup.c
index 55368dd43b6..1ea0c18c2f2 100644
--- a/arch/arm/mach-snapdragon/of_fixup.c
+++ b/arch/arm/mach-snapdragon/of_fixup.c
@@ -86,13 +86,13 @@ static int fixup_qcom_dwc3(struct device_node *glue_np)
}
/* Overwrite "phy-names" to only contain a single entry */
- ret = of_write_prop(dwc3, "phy-names", strlen("usb2-phy"), "usb2-phy");
+ ret = of_write_prop(dwc3, "phy-names", strlen("usb2-phy") + 1, "usb2-phy");
if (ret) {
log_err("Failed to overwrite 'phy-names' property: %d\n", ret);
return ret;
}
- ret = of_write_prop(dwc3, "maximum-speed", strlen("high-speed"), "high-speed");
+ ret = of_write_prop(dwc3, "maximum-speed", strlen("high-speed") + 1, "high-speed");
if (ret) {
log_err("Failed to set 'maximum-speed' property: %d\n", ret);
return ret;
@@ -161,14 +161,14 @@ int ft_board_setup(void *blob, struct bd_info __maybe_unused *bd)
struct fdt_header *fdt = blob;
int node;
- /* We only want to do this fix-up for the RB1 board, quick return for all others */
- if (!fdt_node_check_compatible(fdt, 0, "qcom,qrb4210-rb2"))
- return 0;
-
- fdt_for_each_node_by_compatible(node, blob, 0, "snps,dwc3") {
- log_debug("%s: Setting 'dr_mode' to OTG\n", fdt_get_name(blob, node, NULL));
- fdt_setprop_string(fdt, node, "dr_mode", "otg");
- break;
+ /* On RB1/2 we need to fix-up the dr_mode */
+ if (!fdt_node_check_compatible(fdt, 0, "qcom,qrb4210-rb2") ||
+ !fdt_node_check_compatible(fdt, 0, "qcom,qrb2210-rb1")) {
+ fdt_for_each_node_by_compatible(node, blob, 0, "snps,dwc3") {
+ log_debug("%s: Setting 'dr_mode' to OTG\n", fdt_get_name(blob, node, NULL));
+ fdt_setprop_string(fdt, node, "dr_mode", "otg");
+ break;
+ }
}
return 0;
diff --git a/board/qualcomm/dragonboard410c/MAINTAINERS b/board/qualcomm/dragonboard410c/MAINTAINERS
index e78f5b2d642..9c10fa3053b 100644
--- a/board/qualcomm/dragonboard410c/MAINTAINERS
+++ b/board/qualcomm/dragonboard410c/MAINTAINERS
@@ -1,5 +1,6 @@
DRAGONBOARD410C BOARD
-M: Ramon Fried <rfried.dev@gmail.com>
+M: Stephan Gerhold <stephan@gerhold.net>
+R: Sam Day <me@samcday.com>
S: Maintained
F: board/qualcomm/dragonboard410c/
F: include/configs/dragonboard410c.h
diff --git a/board/qualcomm/dragonboard410c/dragonboard410c.c b/board/qualcomm/dragonboard410c/dragonboard410c.c
index fcbf2c3fe60..4698b9d5e3e 100644
--- a/board/qualcomm/dragonboard410c/dragonboard410c.c
+++ b/board/qualcomm/dragonboard410c/dragonboard410c.c
@@ -22,21 +22,6 @@
DECLARE_GLOBAL_DATA_PTR;
-/* UNSTUFF_BITS macro taken from Linux Kernel: drivers/mmc/core/sd.c */
-#define UNSTUFF_BITS(resp, start, size) \
- ({ \
- const int __size = size; \
- const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
- const int __off = 3 - ((start) / 32); \
- const int __shft = (start) & 31; \
- u32 __res; \
- \
- __res = resp[__off] >> __shft; \
- if (__size + __shft > 32) \
- __res |= resp[__off - 1] << ((32 - __shft) % 32); \
- __res & __mask; \
- })
-
static u32 msm_board_serial(void)
{
struct mmc *mmc_dev;
@@ -48,7 +33,8 @@ static u32 msm_board_serial(void)
if (mmc_init(mmc_dev))
return 0;
- return UNSTUFF_BITS(mmc_dev->cid, 16, 32);
+ /* MMC serial number */
+ return mmc_dev->cid[2] << 16 | mmc_dev->cid[3] >> 16;
}
static void msm_generate_mac_addr(u8 *mac)
@@ -65,28 +51,6 @@ static void msm_generate_mac_addr(u8 *mac)
put_unaligned_be32(msm_board_serial(), &mac[2]);
}
-/* Check for vol- button - if pressed - stop autoboot */
-int misc_init_r(void)
-{
- struct udevice *btn;
- int ret;
- enum button_state_t state;
-
- ret = button_get_by_label("vol_down", &btn);
- if (ret < 0) {
- printf("Couldn't find power button!\n");
- return ret;
- }
-
- state = button_get_state(btn);
- if (state == BUTTON_ON) {
- env_set("preboot", "setenv preboot; fastboot 0");
- printf("vol_down pressed - Starting fastboot.\n");
- }
-
- return 0;
-}
-
int qcom_late_init(void)
{
char serial[16];
@@ -97,9 +61,9 @@ int qcom_late_init(void)
return 0;
}
-/* Fixup of DTB for Linux Kernel
- * 1. Fixup installed DRAM.
- * 2. Fixup WLAN/BT Mac address:
+/*
+ * Fixup of DTB for Linux Kernel
+ * 1. Fixup WLAN/BT Mac address:
* First, check if MAC addresses for WLAN/BT exists as environemnt
* variables wlanaddr,btaddr. if not, generate a unique address.
*/
@@ -107,6 +71,7 @@ int qcom_late_init(void)
int ft_board_setup(void *blob, struct bd_info *bd)
{
u8 mac[ARP_HLEN];
+ int i;
if (!eth_env_get_enetaddr("wlanaddr", mac)) {
msm_generate_mac_addr(mac);
@@ -118,12 +83,24 @@ int ft_board_setup(void *blob, struct bd_info *bd)
if (!eth_env_get_enetaddr("btaddr", mac)) {
msm_generate_mac_addr(mac);
-/* The BD address is same as WLAN MAC address but with
- * least significant bit flipped.
- */
- mac[0] ^= 0x01;
+ /*
+ * The BD address is same as WLAN MAC address but with
+ * least significant bit flipped.
+ */
+ mac[ARP_HLEN - 1] ^= 0x01;
};
+ /*
+ * Reverse array since local-bd-address is formatted with least
+ * significant byte first (little endian).
+ */
+ for (i = 0; i < ARP_HLEN / 2; ++i) {
+ u8 tmp = mac[i];
+
+ mac[i] = mac[ARP_HLEN - 1 - i];
+ mac[ARP_HLEN - 1 - i] = tmp;
+ }
+
do_fixup_by_compat(blob, "qcom,wcnss-bt",
"local-bd-address", mac, ARP_HLEN, 1);
return 0;
diff --git a/board/qualcomm/dragonboard410c/dragonboard410c.env b/board/qualcomm/dragonboard410c/dragonboard410c.env
index 9d9a575a0c3..38399d65c64 100644
--- a/board/qualcomm/dragonboard410c/dragonboard410c.env
+++ b/board/qualcomm/dragonboard410c/dragonboard410c.env
@@ -1,36 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-
-/* Does what recovery does */
-#define REFLASH(file, partnum) \
-part start mmc 0 partnum start && \
-part size mmc 0 partnum size && \
-tftp $loadaddr file && \
-mmc write $loadaddr $start $size &&
-
-reflash=
-mmc dev 0 &&
-usb start &&
-dhcp &&
-tftp $loadaddr dragonboard/rescue/gpt_both0.bin &&
-mmc write $loadaddr 0 43 &&
-mmc rescan &&
-REFLASH(dragonboard/rescue/NON-HLOS.bin, 1)
-REFLASH(dragonboard/rescue/sbl1.mbn, 2)
-REFLASH(dragonboard/rescue/rpm.mbn, 3)
-REFLASH(dragonboard/rescue/tz.mbn, 4)
-REFLASH(dragonboard/rescue/hyp.mbn, 5)
-REFLASH(dragonboard/rescue/sec.dat, 6)
-REFLASH(dragonboard/rescue/emmc_appsboot.mbn, 7)
-REFLASH(dragonboard/u-boot.img, 8)
-usb stop &&
-echo Reflash completed
-
-loadaddr=0x81000000
initrd_high=0xffffffffffffffff
-linux_image=Image
-kernel_addr_r=0x81000000
-fdtfile=qcom/apq8016-sbc.dtb
-fdt_addr_r=0x83000000
-ramdisk_addr_r=0x84000000
-scriptaddr=0x90000000
-pxefile_addr_r=0x90100000
+fastboot=fastboot -l $fastboot_addr_r usb 0
+boot_targets=usb mmc1 mmc0 pxe
+button_cmd_0_name=vol_down
+button_cmd_0=run fastboot
diff --git a/board/qualcomm/dragonboard820c/dragonboard820c.c b/board/qualcomm/dragonboard820c/dragonboard820c.c
index d3333a59db0..12a9273ec4b 100644
--- a/board/qualcomm/dragonboard820c/dragonboard820c.c
+++ b/board/qualcomm/dragonboard820c/dragonboard820c.c
@@ -106,7 +106,7 @@ int misc_init_r(void)
int ret;
enum button_state_t state;
- ret = button_get_by_label("pwrkey", &btn);
+ ret = button_get_by_label("Power Button", &btn);
if (ret < 0) {
printf("Couldn't find power button!\n");
return ret;
diff --git a/board/qualcomm/dragonboard820c/readme.txt b/board/qualcomm/dragonboard820c/readme.txt
index 966e9520e85..a01d24122cb 100644
--- a/board/qualcomm/dragonboard820c/readme.txt
+++ b/board/qualcomm/dragonboard820c/readme.txt
@@ -16,10 +16,7 @@
Build & Run instructions
================================================================================
-1) Install mkbootimg and dtbTool from Codeaurora:
-
- git://codeaurora.org/quic/kernel/skales
- commit 8492547e404e969262d9070dee9bdd15668bb70f worked for me.
+1) Install mkbootimg
2) Setup CROSS_COMPILE to aarch64 compiler or if you use ccache just do
CROSS_COMPILE="ccache aarch64-linux-gnu-"
@@ -33,15 +30,15 @@
$ touch rd
-5) Generate qualcomm device tree table with dtbTool
+5) Append the dtb to the u-boot binary discarding the internal dtb.
- $ dtbTool -o dt.img arch/arm/dts
+ $ gzip u-boot-nodtb.bin
+ $ cat u-boot.dtb >> u-boot-nodtb.bin.gz
6) Generate Android boot image with mkbootimg:
- $ mkbootimg --kernel=u-boot-dtb.bin \
+ $ mkbootimg --kernel=u-boot-nodtb.bin.gz \
--output=u-boot.img \
- --dt=dt.img \
--pagesize 4096 \
--base 0x80000000 \
--ramdisk=rd \
@@ -251,44 +248,42 @@ Wait for 5 seconds before proceeding
[5300] booting linux @ 0x80080000, ramdisk @ 0x82200000 (0), tags/device tree @ 0x82000000
[5310] Jumping to kernel via monitor
-U-Boot 2017.11-00145-ge895117 (Nov 29 2017 - 10:04:06 +0100)
+U-Boot 2025.04-rc5-00020-g40a61ca0e7eb-dirty (Apr 07 2025 - 09:37:03 +0200)
Qualcomm-DragonBoard 820C
-DRAM: 3 GiB
-PSCI: v1.0
-MMC: sdhci@74a4900: 0
+DRAM: 3.5 GiB (effective 3 GiB)
+Core: 136 devices, 18 uclasses, devicetree: board
+MMC: Bulk clocks not available (-19), trying core clock
+mmc@74a4900: 0
+Loading Environment from EXT4... OK
In: serial@75b0000
Out: serial@75b0000
Err: serial@75b0000
-Net: Net Initialization Skipped
-No ethernet found.
+Net: No ethernet found.
Hit any key to stop autoboot: 0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found /extlinux/extlinux.conf
Retrieving file: /extlinux/extlinux.conf
-433 bytes read in 71 ms (5.9 KiB/s)
1: nfs root
-
+Enter choice: 1: nfs root
Retrieving file: /uImage
-19397184 bytes read in 2024 ms (9.1 MiB/s)
-append: root=/dev/nfs rw nfsroot=192.168.1.2:/db820c/rootfs,v3,tcp rootwait ip=dhcp consoleblank=0 console=tty0 console=ttyMSM0,115200n8 earlyprintk earlycon=msm_serial_dm,0x75b0000 androidboot.bootdevice=624000.ufshc androidboot.verifiedbootstate=orange androidboot.ver0
-
+append: root=/dev/nfs rw nfsroot=192.168.1.6:/home/jramirez/Src/qualcomm-lt/db820c/rootfs,v3,tcp rootwait ip=dhcp consoleblank=0 console=tty0 console=ttyMSM0,115200n8 earlyprintk earlyco0
Retrieving file: /apq8096-db820c.dtb
-38134 bytes read in 37 ms (1005.9 KiB/s)
-
-## Booting kernel from Legacy Image at 95000000 ...
+## Booting kernel from Legacy Image at 155000000 ...
Image Name: Dragonboard820c
Image Type: AArch64 Linux Kernel Image (uncompressed)
Data Size: 19397120 Bytes = 18.5 MiB
Load Address: 80080000
Entry Point: 80080000
Verifying Checksum ... OK
-## Flattened Device Tree blob at 93000000
- Booting using the fdt blob at 0x93000000
- Loading Kernel Image ... OK
- Using Device Tree in place at 0000000093000000, end 000000009300c4f5
+## Flattened Device Tree blob at 148600000
+ Booting using the fdt blob at 0x148600000
+Working FDT set to 148600000
+ Loading Kernel Image to 80080000
+ Using Device Tree in place at 0000000148600000, end 000000014860c4f5
+Working FDT set to 148600000
Starting kernel ...
diff --git a/board/qualcomm/qcom-phone.config b/board/qualcomm/qcom-phone.config
new file mode 100644
index 00000000000..913c91757c1
--- /dev/null
+++ b/board/qualcomm/qcom-phone.config
@@ -0,0 +1,29 @@
+# Settings for phones
+CONFIG_DEFAULT_ENV_FILE="board/qualcomm/qcom-phone.env"
+# Hang on panic so the error message can be read
+CONFIG_PANIC_HANG=y
+# We use pause in various places to allow text to be read
+# before it scrolls off the screen
+CONFIG_CMD_PAUSE=y
+CONFIG_BOOT_RETRY=y
+CONFIG_BOOT_RETRY_TIME=1
+CONFIG_BUTTON_REMAP_PHONE_KEYS=y
+CONFIG_RETRY_BOOTCMD=y
+CONFIG_FASTBOOT_BUF_ADDR=0x1A000000
+CONFIG_USB_FUNCTION_FASTBOOT=y
+CONFIG_USB_FUNCTION_ACM=y
+CONFIG_CMD_UMS_ABORT_KEYED=y
+
+# Record all console output and let it be dumped via fastboot
+CONFIG_CONSOLE_RECORD=y
+CONFIG_CONSOLE_RECORD_INIT_F=y
+CONFIG_CONSOLE_RECORD_OUT_SIZE=0x6000
+CONFIG_FASTBOOT_CMD_OEM_CONSOLE=y
+
+# Only MMC is supported by fastboot currently, but this is still useful.
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=0
+CONFIG_FASTBOOT_OEM_RUN=y
+
+# Many phones don't actually define a serial port in their DTS
+# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
diff --git a/board/qualcomm/qcom-phone.env b/board/qualcomm/qcom-phone.env
new file mode 100644
index 00000000000..e91ae3ecdfb
--- /dev/null
+++ b/board/qualcomm/qcom-phone.env
@@ -0,0 +1,47 @@
+bootdelay=0
+bootretry=1
+stdin=serial,button-kbd
+stdout=serial,vidconsole
+stderr=serial,vidconsole
+
+# Fastboot is keen to use the address from kconfig, but we
+# allocate its buffer at runtime.
+fastboot=fastboot -l $fastboot_addr_r usb 0
+
+# Always probe for UFS storage, though it should be done by board code.
+preboot=scsi scan
+
+# Shortcut to enable USB serial gadget and disable bootretry
+serial_gadget=setenv stdin serial,button-kbd,usbacm; \
+ setenv stdout serial,vidconsole,usbacm; \
+ setenv stderr serial,vidconsole,usbacm; \
+ setenv bootretry -1; \
+ echo Enabled U-Boot console serial gadget
+
+# bootretry will run this command over and over, if we fail once
+# then bail out to the boot menu instead (with a pause to read
+# the error message)
+bootcmd=bootefi bootmgr; pause; run menucmd
+
+# When entering the menu (either from button press or failed boot)
+# remap bootcmd so it will re-open the menu and we won't get stuck
+# at the console with no way to type
+menucmd=setenv bootcmd run menucmd; bootmenu -1
+
+# Pause is used so the output can be read on the display
+bootmenu_0=Boot=bootefi bootmgr; pause
+bootmenu_1=Enable serial console gadget=run serial_gadget
+bootmenu_2=Enable USB mass storage=echo "Press any key to exit UMS mode"; ums 0 scsi 0
+bootmenu_3=Enable fastboot mode=run fastboot
+# Disabling bootretry means we'll just drop the shell
+bootmenu_4=Drop to shell=setenv bootretry -1
+bootmenu_5=Reset device=reset
+bootmenu_6=Dump clocks=clk dump; pause
+bootmenu_7=Dump environment=printenv; pause
+bootmenu_8=Board info=bdinfo; pause
+bootmenu_9=Dump bootargs=fdt print /chosen bootargs; pause
+
+# Allow holding the volume down button while U-Boot loads to enter
+# the boot menu
+button_cmd_0_name=Volume Down
+button_cmd_0=run menucmd
diff --git a/boot/Kconfig b/boot/Kconfig
index f101200ba7a..fb37d912bc9 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -1704,6 +1704,13 @@ config RESET_TO_RETRY
After the countdown timed out, the board will be reset to restart
again.
+config RETRY_BOOTCMD
+ bool "Run bootcmd on retry"
+ depends on BOOT_RETRY && HUSH_PARSER && !RESET_TO_RETRY
+ help
+ If this option is enabled, the "bootcmd" will be run after the
+ countdown times out.
+
endmenu
menu "Image support"
diff --git a/boot/bootretry.c b/boot/bootretry.c
index 587b2de7d6b..a60767eaa2e 100644
--- a/boot/bootretry.c
+++ b/boot/bootretry.c
@@ -37,6 +37,8 @@ void bootretry_init_cmd_timeout(void)
*/
void bootretry_reset_cmd_timeout(void)
{
+ /* Parse changes to bootretry */
+ bootretry_init_cmd_timeout();
endtime = endtick(retry_time);
}
diff --git a/common/cli_hush.c b/common/cli_hush.c
index 9f437ae5f47..7bd6943d3ed 100644
--- a/common/cli_hush.c
+++ b/common/cli_hush.c
@@ -1028,8 +1028,10 @@ static void get_user_input(struct in_str *i)
puts("\nTimeout waiting for command\n");
# ifdef CONFIG_RESET_TO_RETRY
do_reset(NULL, 0, 0, NULL);
-# else
-# error "This currently only works with CONFIG_RESET_TO_RETRY enabled"
+# elif IS_ENABLED(CONFIG_RETRY_BOOTCMD)
+ strcpy(console_buffer, "run bootcmd\n");
+# else
+# error "This only works with CONFIG_RESET_TO_RETRY or CONFIG_BOOT_RETRY_COMMAND enabled"
# endif
}
#endif
diff --git a/common/cli_hush_upstream.c b/common/cli_hush_upstream.c
index ab5aa5f9b36..748ef60ac90 100644
--- a/common/cli_hush_upstream.c
+++ b/common/cli_hush_upstream.c
@@ -2907,8 +2907,10 @@ static void get_user_input(struct in_str *i)
puts("\nTimeout waiting for command\n");
# ifdef CONFIG_RESET_TO_RETRY
do_reset(NULL, 0, 0, NULL);
-# else
-# error "This currently only works with CONFIG_RESET_TO_RETRY enabled"
+# elif IS_ENABLED(CONFIG_RETRY_BOOTCMD)
+ strcpy(console_buffer, "run bootcmd\n");
+# else
+# error "This only works with CONFIG_RESET_TO_RETRY or CONFIG_BOOT_RETRY_COMMAND enabled"
# endif
}
# endif
diff --git a/configs/dragonboard410c_defconfig b/configs/dragonboard410c_defconfig
index 967817f4f58..449d48a3c00 100644
--- a/configs/dragonboard410c_defconfig
+++ b/configs/dragonboard410c_defconfig
@@ -1,6 +1,6 @@
CONFIG_ARM=y
CONFIG_SYS_BOARD="dragonboard410c"
-CONFIG_COUNTER_FREQUENCY=19000000
+CONFIG_COUNTER_FREQUENCY=19200000
CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK=y
CONFIG_ARCH_SNAPDRAGON=y
CONFIG_TEXT_BASE=0x8f600000
@@ -14,18 +14,16 @@ CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_SYS_LOAD_ADDR=0x80080000
CONFIG_IDENT_STRING="\nQualcomm-DragonBoard 410C"
CONFIG_REMAKE_ELF=y
-# CONFIG_ANDROID_BOOT_IMAGE is not set
+CONFIG_BUTTON_CMD=y
CONFIG_FIT=y
-CONFIG_DISTRO_DEFAULTS=y
+CONFIG_BOOTSTD_FULL=y
CONFIG_OF_BOARD_SETUP=y
CONFIG_USE_PREBOOT=y
CONFIG_SYS_CBSIZE=512
CONFIG_SYS_PBSIZE=548
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set
-CONFIG_MISC_INIT_R=y
CONFIG_SYS_PROMPT="dragonboard410c => "
-# CONFIG_CMD_IMI is not set
CONFIG_CMD_MD5SUM=y
CONFIG_CMD_MEMINFO=y
CONFIG_CMD_GPIO=y
@@ -35,6 +33,7 @@ CONFIG_CMD_USB=y
CONFIG_BOOTP_BOOTFILESIZE=y
CONFIG_CMD_CACHE=y
CONFIG_CMD_TIMER=y
+CONFIG_CMD_SYSBOOT=y
CONFIG_ENV_IS_IN_MMC=y
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_SYS_MMC_ENV_PART=2
@@ -60,6 +59,7 @@ CONFIG_PMIC_QCOM=y
CONFIG_MSM_SERIAL=y
CONFIG_SPMI_MSM=y
CONFIG_USB=y
+# CONFIG_DM_USB_GADGET is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_ULPI_VIEWPORT=y
@@ -68,6 +68,7 @@ CONFIG_USB_HOST_ETHER=y
CONFIG_USB_ETHER_ASIX=y
CONFIG_USB_ETHER_ASIX88179=y
CONFIG_USB_ETHER_MCS7830=y
+CONFIG_USB_ETHER_RTL8152=y
CONFIG_USB_ETHER_SMSC95XX=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VENDOR_NUM=0x18d1
diff --git a/configs/dragonboard820c_defconfig b/configs/dragonboard820c_defconfig
index e29bea7deb2..2a5b7212f74 100644
--- a/configs/dragonboard820c_defconfig
+++ b/configs/dragonboard820c_defconfig
@@ -45,4 +45,6 @@ CONFIG_PINCTRL_QCOM_APQ8096=y
CONFIG_DM_PMIC=y
CONFIG_PMIC_QCOM=y
CONFIG_MSM_SERIAL=y
+CONFIG_MSM_GPIO=y
CONFIG_SPMI_MSM=y
+CONFIG_CLK_STUB=y
diff --git a/configs/hmibsc_defconfig b/configs/hmibsc_defconfig
index 88c9c70a639..4550eba71ab 100644
--- a/configs/hmibsc_defconfig
+++ b/configs/hmibsc_defconfig
@@ -70,6 +70,7 @@ CONFIG_PMIC_QCOM=y
CONFIG_MSM_SERIAL=y
CONFIG_SPMI_MSM=y
CONFIG_USB=y
+# CONFIG_DM_USB_GADGET is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_ULPI_VIEWPORT=y
diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig
index ba4d38d100e..537806450dc 100644
--- a/configs/qcom_defconfig
+++ b/configs/qcom_defconfig
@@ -41,6 +41,7 @@ CONFIG_CMD_RNG=y
CONFIG_CMD_REGULATOR=y
CONFIG_CMD_LOG=y
CONFIG_OF_LIVE=y
+CONFIG_OF_UPSTREAM_BUILD_VENDOR=y
CONFIG_USE_DEFAULT_ENV_FILE=y
CONFIG_DEFAULT_ENV_FILE="board/qualcomm/default.env"
CONFIG_BUTTON_QCOM_PMIC=y
@@ -62,6 +63,11 @@ CONFIG_CLK_QCOM_X1E80100=y
CONFIG_DFU_MMC=y
CONFIG_DFU_SCSI=y
CONFIG_SYS_DFU_DATA_BUF_SIZE=0x200000
+CONFIG_USB_FUNCTION_FASTBOOT=y
+CONFIG_FASTBOOT_BUF_ADDR=0x0
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=0
+CONFIG_FASTBOOT_MMC_USER_SUPPORT=y
CONFIG_MSM_GPIO=y
CONFIG_QCOM_PMIC_GPIO=y
CONFIG_DM_I2C=y
@@ -75,7 +81,6 @@ CONFIG_QCOM_HYP_SMMU=y
CONFIG_MISC=y
CONFIG_NVMEM=y
CONFIG_I2C_EEPROM=y
-CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ADMA=y
CONFIG_MMC_SDHCI_MSM=y
@@ -97,6 +102,7 @@ CONFIG_PINCTRL_QCOM_APQ8016=y
CONFIG_PINCTRL_QCOM_APQ8096=y
CONFIG_PINCTRL_QCOM_QCM2290=y
CONFIG_PINCTRL_QCOM_QCS404=y
+CONFIG_PINCTRL_QCOM_SA8775P=y
CONFIG_PINCTRL_QCOM_SC7280=y
CONFIG_PINCTRL_QCOM_SDM845=y
CONFIG_PINCTRL_QCOM_SM6115=y
diff --git a/doc/board/qualcomm/board.rst b/doc/board/qualcomm/board.rst
index 4d793209f9e..003d59a18eb 100644
--- a/doc/board/qualcomm/board.rst
+++ b/doc/board/qualcomm/board.rst
@@ -90,6 +90,11 @@ Or for db410c (and other boards not supported by the generic target)::
make CROSS_COMPILE=aarch64-linux-gnu- O=.output dragonboard410c_defconfig
make O=.output -j$(nproc)
+Or for smartphones::
+
+ make CROSS_COMPILE=aarch64-linux-gnu- O=.output qcom_defconfig qcom-phone.config
+ make O=.output -j$(nproc)
+
- gzip u-boot::
gzip u-boot-nodtb.bin
diff --git a/doc/board/qualcomm/index.rst b/doc/board/qualcomm/index.rst
index 66bc922033a..e2fcbfa19c2 100644
--- a/doc/board/qualcomm/index.rst
+++ b/doc/board/qualcomm/index.rst
@@ -9,5 +9,6 @@ Qualcomm
dragonboard410c
rb3gen2
board
+ phones
debugging
rdp
diff --git a/doc/board/qualcomm/phones.rst b/doc/board/qualcomm/phones.rst
new file mode 100644
index 00000000000..1d27196cf54
--- /dev/null
+++ b/doc/board/qualcomm/phones.rst
@@ -0,0 +1,144 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Caleb Connolly <caleb.connolly@linaro.org>
+
+======================================
+Booting U-Boot on Qualcomm smartphones
+======================================
+
+About this
+----------
+
+This page attempts to the describe U-Boot support for Qualcomm phones, as a user guide but also a
+technical introduction to How Stuff Works to help new porters.
+
+In broad strokes, U-Boot should boot if the SoC is supported, and the device is already capable of
+booting an upstream Linux kernel.
+
+The list of supported Qualcomm SoCs changes often, for now it is best to look in
+``drivers/clk/qcom/`` to get a rough idea.
+
+For building instructions, see :doc:`board`.
+
+Phone bringup
+-------------
+
+It is usually easier to get Linux booting first, there are many good resources for this such as the
+`postmarketOS wiki`_. Once the device can boot Linux with logs on the display and ideally USB gadget
+support, it is highly likely that U-Boot will boot as well.
+
+For logs on display, you should have a simple framebuffer node defined in your DT, newer devices
+require that this follow the downstream naming scheme (that the DTB is compiled with labels enabled
+and the framebuffer reserved-memory region is labelled ``cont_splash``). Once this is working in
+Linux it should also work in U-Boot.
+
+In practise, U-Boot still has many more papercuts than Linux, which can be sticking points when
+porting a new device. In particular, drivers failing to bind/probe (especially pre-relocation) can
+be tricky to debug without UART since U-Boot will simply panic with no way to inform you of
+the error. As a result, bringing up a new device can be quite frustrating, but there are quite a few
+things you can try.
+
+The phone config
+^^^^^^^^^^^^^^^^
+
+Since most phones lack a physical keyboard or serial port, a special config fragment and environment
+file can be used to provide a more seamless experience. This can be enabled by generating the config
+with::
+
+ make CROSS_COMPILE=aarch64-linux-gnu- O=.output qcom_defconfig qcom-phone.config
+
+The config and associated environment file can be found in board/qualcomm/. The main changes are:
+
+- Panic on hang (so the panic message can be read on the display)
+- Boot retry (to automatically open and re-open the bootmenu)
+- A boot menu with helpful shortcuts (including USB console gadget)
+- Launch the boot menu if power is held during boot or on boot failure
+
+Fastboot mode
+-------------
+
+U-Boot's fastboot implementation is much more limited than Qualcomm's, and currently does not have a
+backend for UFS storage. If your device uses eMMC or has an sdcard slot, fastboot will use that by
+default.
+
+You may need to run the fastboot command on your PC as root since the USB product/vendor ID may not
+match the android udev rules.
+
+You can also use fastboot to run arbitrary U-Boot commands with ``fastboot oem run``
+
+Retrieving early logs
+^^^^^^^^^^^^^^^^^^^^^
+
+U-Boot is configured to save it's internal log to a buffer, this can help with debugging some driver
+bind/probe issues. If your device can boot and has working USB, you can enable fastboot mode (either
+via the U-Boot menu or by adding ``run fastboot`` to the end of the ``preboot=`` config in
+``board/qualcomm/qcom-phone.env``).
+
+You can then retrieve U-Boot's log buffer with the ``fastboot oem log`` command on your PC.
+
+Hang/crash bisection
+--------------------
+
+Without a way to get logs, we can still get quite far with only a few bits of information: what
+happens when you ``fastboot boot u-boot.img``?
+
+Does the device disconnect?
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This can be verified by watching ``dmesg -w``. If it stays connected, it likely means the boot image
+doesn't match what the bootloader expected, use ``unpack_bootimg`` to compare it with a known-good
+boot image (ideally one with an upstream kernel).
+
+Does the device hang?
+^^^^^^^^^^^^^^^^^^^^^
+
+If it stays on a black screen and does nothing, then that's a hang! Since ``qcom-phone.config``
+enables CONFIG_PANIC_HANG, this likely means that you're successfully executing U-Boot code (yay!),
+but something is causing a panic.
+
+It could also be due to a bad memory or register access triggering a secure interrupt, it's worth
+waiting for around a minute to see if the device eventually reboots or goes to crashdump mode. You
+can also disable CONFIG_PANIC_HANG and see if that causes the device to reboot instead, if so then
+it is definitely a U-Boot panic.
+
+With enough time and patience, it should be possible to narrow down the cause of the panic by
+inserting calls to ``reset_cpu()`` (with CONFIG_PANIC_HANG enabled). Then if the device resets you
+know it executed the ``reset_cpu()`` call.
+
+A good place to start is ``board_fdt_blob_setup()`` in ``arch/arm/mach-snapdragon/board.c``, this
+function is called extremely early so adding a reset call is a good way to validate that U-Boot is
+definitely running.
+
+You can then do a binary search starting from the end of ``board_init_f()`` / start of
+``board_init_r()`` and work from there using the init sequences for reference.
+
+The Qualcomm RAM parsing code is a likely culprit, as ABL is known to sometimes give bogus entries
+in the memory node which can trip U-Boot up.
+
+To rule out crashes that might be caused by specific drivers, it's a good idea to disable them and
+re-enable them one by one. Here is a non-exhaustive list of drivers to disable:
+
+- pinctrl
+- mmc
+- scsi/ufs
+- usb (dwc3)
+- phy (usb, ufs)
+- clk (remove clock references from your framebuffer node in DT)
+
+Ideally, it would be possible to use the framebuffer as an early console / debug output, at the time
+of writing there are out of tree patches for this but they haven't been submitted upstream yet.
+
+Does the device reboot or go to crashdump mode?
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+On many devices crashdump mode is disabled, so they will reboot instead (maybe after some delay).
+The same approach as suggested above can be used to figure out where the crash occurs.
+
+If the device is rebooting, you can insert calls to ``hang()`` instead of ``reset_cpu()`` when
+following the instructions above.
+
+The most likely cause of a crashdump is the pinctrl/gpio driver or the SMMU driver, ensure that the
+``apps_smmu`` node in your SoCs devicetree file has one of its compatible strings referenced in
+``drivers/iommu/qcom-hyp-smmu.c``, you can also try disabling the pinctrl driver for your SoC (or
+``CONFIG_PINCTRL`` altogether).
+
+.. _`postmarketOS wiki`: https://wiki.postmarketos.org/wiki/Mainlining
diff --git a/drivers/button/button-qcom-pmic.c b/drivers/button/button-qcom-pmic.c
index f9f0948ae09..e3bb9bd758a 100644
--- a/drivers/button/button-qcom-pmic.c
+++ b/drivers/button/button-qcom-pmic.c
@@ -73,25 +73,25 @@ static const struct qcom_pmic_btn_data qcom_pmic_btn_data_table[] = {
.compatible = "qcom,pm8941-pwrkey",
.status_bit = PON_KPDPWR_N_SET,
.code = KEY_ENTER,
- .label = "pwrkey",
+ .label = "Power Button",
},
{
.compatible = "qcom,pm8941-resin",
.status_bit = PON_RESIN_N_SET,
.code = KEY_DOWN,
- .label = "vol_down",
+ .label = "Volume Down",
},
{
.compatible = "qcom,pmk8350-pwrkey",
.status_bit = PON_GEN3_KPDPWR_N_SET,
.code = KEY_ENTER,
- .label = "pwrkey",
+ .label = "Power Button",
},
{
.compatible = "qcom,pmk8350-resin",
.status_bit = PON_GEN3_RESIN_N_SET,
.code = KEY_DOWN,
- .label = "vol_down",
+ .label = "Volume Down",
},
};
diff --git a/drivers/button/button-uclass.c b/drivers/button/button-uclass.c
index 729983d5870..025917887e8 100644
--- a/drivers/button/button-uclass.c
+++ b/drivers/button/button-uclass.c
@@ -21,7 +21,7 @@ int button_get_by_label(const char *label, struct udevice **devp)
struct button_uc_plat *uc_plat = dev_get_uclass_plat(dev);
/* Ignore the top-level button node */
- if (uc_plat->label && !strcmp(label, uc_plat->label))
+ if (uc_plat->label && !strcasecmp(label, uc_plat->label))
return uclass_get_device_tail(dev, 0, devp);
}
diff --git a/drivers/clk/clk-stub.c b/drivers/clk/clk-stub.c
index 343fa5cd3fe..5f5aca41d5b 100644
--- a/drivers/clk/clk-stub.c
+++ b/drivers/clk/clk-stub.c
@@ -14,7 +14,7 @@
static const struct udevice_id nop_parent_ids[] = {
{ .compatible = "qcom,rpm-proc" },
{ .compatible = "qcom,glink-rpm" },
- { .compatible = "qcom,rpm-sm6115" },
+ { .compatible = "qcom,glink-smd-rpm" },
{ }
};
@@ -50,6 +50,7 @@ static struct clk_ops stub_clk_ops = {
static const struct udevice_id stub_clk_ids[] = {
{ .compatible = "qcom,rpmcc" },
+ { .compatible = "qcom,sdm845-rpmh-clk" },
{ .compatible = "qcom,sc7280-rpmh-clk" },
{ .compatible = "qcom,sm8150-rpmh-clk" },
{ .compatible = "qcom,sm8250-rpmh-clk" },
diff --git a/drivers/clk/qcom/clock-apq8096.c b/drivers/clk/qcom/clock-apq8096.c
index c77d69128b0..551f52d5197 100644
--- a/drivers/clk/qcom/clock-apq8096.c
+++ b/drivers/clk/qcom/clock-apq8096.c
@@ -83,11 +83,12 @@ static ulong apq8096_clk_set_rate(struct clk *clk, ulong rate)
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
switch (clk->id) {
- case GCC_SDCC1_APPS_CLK: /* SDC1 */
+ case GCC_SDCC2_APPS_CLK: /* SDC2 */
return clk_init_sdc(priv, rate);
break;
case GCC_BLSP2_UART2_APPS_CLK: /*UART2*/
- return clk_init_uart(priv);
+ clk_init_uart(priv);
+ return 7372800;
default:
return 0;
}
diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c
index 8691f08109b..9aff8a847ad 100644
--- a/drivers/clk/qcom/clock-sc7280.c
+++ b/drivers/clk/qcom/clock-sc7280.c
@@ -107,6 +107,17 @@ static const struct gate_clk sc7280_clks[] = {
GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x52008, BIT(10)),
GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x52008, BIT(11)),
GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x52008, BIT(13)),
+ GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77010, BIT(0)),
+ GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770cc, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77018, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x7705c, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x7709c, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x7701c, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x77020, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_1_CLK, 0x770b8, BIT(0)),
+ GATE_CLK(GCC_UFS_1_CLKREF_EN, 0x8c000, BIT(0)),
+ GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14008, BIT(0)),
+ GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, BIT(0)),
};
static int sc7280_enable(struct clk *clk)
diff --git a/drivers/clk/qcom/clock-sdm845.c b/drivers/clk/qcom/clock-sdm845.c
index 6a0bf16ba2d..5c8702ef2fe 100644
--- a/drivers/clk/qcom/clock-sdm845.c
+++ b/drivers/clk/qcom/clock-sdm845.c
@@ -77,7 +77,9 @@ static ulong sdm845_clk_set_rate(struct clk *clk, ulong rate)
}
static const struct gate_clk sdm845_clks[] = {
+ GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x8201c, 0x00000001),
GATE_CLK(GCC_AGGRE_USB3_SEC_AXI_CLK, 0x82020, 0x00000001),
+ GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x0502c, 0x00000001),
GATE_CLK(GCC_CFG_NOC_USB3_SEC_AXI_CLK, 0x05030, 0x00000001),
GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, 0x00000400),
GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, 0x00000800),
@@ -112,6 +114,7 @@ static const struct gate_clk sdm845_clks[] = {
GATE_CLK(GCC_UFS_CARD_TX_SYMBOL_0_CLK, 0x75014, 0x00000001),
GATE_CLK(GCC_UFS_CARD_UNIPRO_CORE_CLK, 0x75054, 0x00000001),
GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, 0x00000001),
+ GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x82024, 0x00000001),
GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77010, 0x00000001),
GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x7700c, 0x00000001),
GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77058, 0x00000001),
diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c
index cea073b3297..6783fc756f4 100644
--- a/drivers/gpio/msm_gpio.c
+++ b/drivers/gpio/msm_gpio.c
@@ -151,6 +151,9 @@ static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio,
static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flags)
{
+ if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
+ return -EPERM;
+
if (flags & GPIOD_IS_OUT_ACTIVE) {
return msm_gpio_direction_output(dev, gpio, 1);
} else if (flags & GPIOD_IS_OUT) {
@@ -172,12 +175,19 @@ static int msm_gpio_get_value_special(struct msm_gpio_bank *priv, unsigned int g
const struct msm_special_pin_data *data;
if (!priv->pin_data->special_pins_data)
- return 0;
+ return -EINVAL;
data = &priv->pin_data->special_pins_data[offset];
- if (!data->io_reg || data->in_bit >= 31)
- return 0;
+ if (!data->io_reg)
+ return -EINVAL;
+
+ if (data->in_bit >= 31) {
+ if (data->out_bit >= 31)
+ return -EINVAL;
+
+ return !!(readl(priv->base + data->io_reg) >> data->out_bit);
+ }
return !!(readl(priv->base + data->io_reg) >> data->in_bit);
}
@@ -186,19 +196,54 @@ static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
+ if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
+ return -EPERM;
+
if (qcom_is_special_pin(priv->pin_data, gpio))
return msm_gpio_get_value_special(priv, gpio);
return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
}
+static int msm_gpio_get_function_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 GPIOF_UNKNOWN;
+
+ data = &priv->pin_data->special_pins_data[offset];
+
+ /* No I/O fields, cannot control/read the I/O value */
+ if (!data->io_reg || (data->out_bit >= 31 && data->in_bit >= 31))
+ return GPIOF_FUNC;
+
+ /* No Output-Enable register, cannot control I/O direction */
+ if (!data->ctl_reg || data->oe_bit >= 31) {
+ if (data->out_bit >= 31)
+ return GPIOF_INPUT;
+ else
+ return GPIOF_OUTPUT;
+ }
+
+ if (readl(priv->base + data->ctl_reg) & BIT(data->oe_bit))
+ return GPIOF_OUTPUT;
+
+ return GPIOF_INPUT;
+}
+
static int msm_gpio_get_function(struct udevice *dev, unsigned int gpio)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
+ if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
+ return GPIOF_UNKNOWN;
+
/* 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_get_function_special(priv, gpio);
if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
return GPIOF_OUTPUT;
diff --git a/drivers/phy/qcom/phy-qcom-qusb2.c b/drivers/phy/qcom/phy-qcom-qusb2.c
index c91ba18c4ab..d98f6108e69 100644
--- a/drivers/phy/qcom/phy-qcom-qusb2.c
+++ b/drivers/phy/qcom/phy-qcom-qusb2.c
@@ -122,6 +122,9 @@ struct qusb2_phy_cfg {
/* true if PHY has PLL_CORE_INPUT_OVERRIDE register to reset PLL */
bool has_pll_override;
+
+ /* true if PHY default clk scheme is single-ended */
+ bool se_clk_scheme_default;
};
/* set of registers with offsets different per-PHY */
@@ -173,6 +176,19 @@ static const unsigned int sm6115_regs_layout[] = {
[QUSB2PHY_PORT_POWERDOWN] = 0xb4, [QUSB2PHY_INTR_CTRL] = 0xbc,
};
+static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xf8),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0xb3),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0x83),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0xc0),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
+};
+
static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
@@ -214,6 +230,19 @@ static const struct qusb2_phy_cfg sm6115_phy_cfg = {
.regs = sm6115_regs_layout,
.has_pll_test = true,
+ .se_clk_scheme_default = true,
+ .disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
+ .mask_core_ready = PLL_LOCKED,
+ .autoresume_en = BIT(3),
+};
+
+static const struct qusb2_phy_cfg sdm660_phy_cfg = {
+ .tbl = msm8996_init_tbl,
+ .tbl_num = ARRAY_SIZE(msm8996_init_tbl),
+ .regs = sm6115_regs_layout,
+
+ .has_pll_test = true,
+ .se_clk_scheme_default = false,
.disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
.mask_core_ready = PLL_LOCKED,
.autoresume_en = BIT(3),
@@ -228,6 +257,7 @@ static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
POWER_DOWN),
.mask_core_ready = CORE_READY_STATUS,
.has_pll_override = true,
+ .se_clk_scheme_default = true,
.autoresume_en = BIT(0),
.update_tune1_with_efuse = true,
};
@@ -316,8 +346,18 @@ static int qusb2phy_power_on(struct phy *phy)
/* Required to get phy pll lock successfully */
udelay(150);
+ /*
+ * Not all the SoCs have got a readable TCSR_PHY_CLK_SCHEME
+ * register in the TCSR so, if there's none, use the default
+ * value hardcoded in the configuration.
+ */
+ qphy->has_se_clk_scheme = cfg->se_clk_scheme_default;
+
if (cfg->has_pll_test) {
- val |= CLK_REF_SEL;
+ if (!qphy->has_se_clk_scheme)
+ val &= ~CLK_REF_SEL;
+ else
+ val |= CLK_REF_SEL;
writel(val, qphy->base + QUSB2PHY_PLL_TEST);
@@ -413,6 +453,8 @@ static const struct udevice_id qusb2phy_ids[] = {
{ .compatible = "qcom,qusb2-phy" },
{ .compatible = "qcom,qcm2290-qusb2-phy",
.data = (ulong)&sm6115_phy_cfg },
+ { .compatible = "qcom,sdm660-qusb2-phy",
+ .data = (ulong)&sdm660_phy_cfg },
{ .compatible = "qcom,sm6115-qusb2-phy",
.data = (ulong)&sm6115_phy_cfg },
{ .compatible = "qcom,qusb2-v2-phy", .data = (ulong)&qusb2_v2_phy_cfg },
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index f4a3942ee2f..e567cb113a3 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -48,12 +48,25 @@ config PINCTRL_QCOM_QCS404
Say Y here to enable support for pinctrl on the Snapdragon QCS404 SoC,
as well as the associated GPIO driver.
+config PINCTRL_QCOM_SA8775P
+ bool "Qualcomm SA8775P Pinctrl"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the Snapdragon SA8775P SoC,
+ as well as the associated GPIO driver.
+
config PINCTRL_QCOM_SC7280
bool "Qualcomm SC7280/QCM6490 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the Snapdragon SC7280 SoC,
- as well as the associated GPIO driver.
+
+config PINCTRL_QCOM_SDM660
+ bool "Qualcomm SDM630/660 Pinctrl"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the Snapdragon 630/636/660
+ SoCs, as well as the associated GPIO driver.
config PINCTRL_QCOM_SDM845
bool "Qualcomm SDM845 Pinctrl"
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 94cdc6e4a62..6ffc6d48c15 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -9,7 +9,9 @@ obj-$(CONFIG_PINCTRL_QCOM_IPQ9574) += pinctrl-ipq9574.o
obj-$(CONFIG_PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o
obj-$(CONFIG_PINCTRL_QCOM_QCM2290) += pinctrl-qcm2290.o
obj-$(CONFIG_PINCTRL_QCOM_QCS404) += pinctrl-qcs404.o
+obj-$(CONFIG_PINCTRL_QCOM_SA8775P) += pinctrl-sa8775p.o
obj-$(CONFIG_PINCTRL_QCOM_SC7280) += pinctrl-sc7280.o
+obj-$(CONFIG_PINCTRL_QCOM_SDM660) += pinctrl-sdm660.o
obj-$(CONFIG_PINCTRL_QCOM_SDM845) += pinctrl-sdm845.o
obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o
obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
index 24d031947a3..c95db56bc47 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
@@ -15,14 +15,18 @@
#include <asm/gpio.h>
#include <dm/pinctrl.h>
#include <linux/bitops.h>
+#include <linux/bitmap.h>
#include <linux/bug.h>
#include <mach/gpio.h>
#include "pinctrl-qcom.h"
+#define MSM_PINCTRL_MAX_PINS 256
+
struct msm_pinctrl_priv {
phys_addr_t base;
struct msm_pinctrl_data *data;
+ DECLARE_BITMAP(reserved_map, MSM_PINCTRL_MAX_PINS);
};
#define GPIO_CONFIG_REG(priv, x) \
@@ -71,13 +75,60 @@ static const char *msm_get_function_name(struct udevice *dev,
return priv->data->get_function_name(dev, selector);
}
+static int msm_pinctrl_parse_ranges(struct udevice *dev)
+{
+ struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+ ofnode node = dev_ofnode(dev);
+ int ret, count, i;
+ u32 *ranges;
+
+ if (ofnode_read_prop(node, "gpio-reserved-ranges", &count)) {
+ if (count % 2 == 1) {
+ dev_err(dev, "gpio-reserved-ranges must be a multiple of 2\n");
+ return -EINVAL;
+ }
+
+ ranges = malloc(count);
+ if (!ranges)
+ return -ENOMEM;
+
+ ret = ofnode_read_u32_array(node, "gpio-reserved-ranges", ranges, count / 4);
+ if (ret) {
+ dev_err(dev, "failed to read gpio-reserved-ranges array (%d)\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < count / 4; i += 2) {
+ if (ranges[i] >= MSM_PINCTRL_MAX_PINS ||
+ (ranges[i] + ranges[i + 1]) >= MSM_PINCTRL_MAX_PINS) {
+ dev_err(dev, "invalid reserved-range (%d;%d)\n",
+ ranges[i], ranges[i + 1]);
+ return -EINVAL;
+ }
+
+ bitmap_set(priv->reserved_map, ranges[i], ranges[i + 1]);
+ }
+
+ free(ranges);
+ }
+
+ return 0;
+}
+
static int msm_pinctrl_probe(struct udevice *dev)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+ int ret;
priv->base = dev_read_addr(dev);
priv->data = (struct msm_pinctrl_data *)dev_get_driver_data(dev);
+ ret = msm_pinctrl_parse_ranges(dev);
+ if (ret) {
+ printf("Couldn't parse reserved GPIO ranges!\n");
+ return ret;
+ }
+
return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
}
@@ -97,6 +148,9 @@ static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector,
if (func < 0)
return func;
+ if (msm_pinctrl_is_reserved(dev, pin_selector))
+ return -EPERM;
+
/* Always NOP for special pins, assume they're in the correct state */
if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
return 0;
@@ -145,6 +199,9 @@ static int msm_pinconf_set(struct udevice *dev, unsigned int pin_selector,
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+ if (msm_pinctrl_is_reserved(dev, pin_selector))
+ return -EPERM;
+
if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
return msm_pinconf_set_special(priv, pin_selector, param, argument);
@@ -241,3 +298,13 @@ U_BOOT_DRIVER(pinctrl_qcom) = {
.ops = &msm_pinctrl_ops,
.probe = msm_pinctrl_probe,
};
+
+bool msm_pinctrl_is_reserved(struct udevice *dev, unsigned int pin)
+{
+ struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+ if (pin >= MSM_PINCTRL_MAX_PINS)
+ return false;
+
+ return test_bit(pin, priv->reserved_map);
+}
diff --git a/drivers/pinctrl/qcom/pinctrl-sa8775p.c b/drivers/pinctrl/qcom/pinctrl-sa8775p.c
new file mode 100644
index 00000000000..cb2496ff1fb
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sa8775p.c
@@ -0,0 +1,623 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <dm.h>
+
+#include "pinctrl-qcom.h"
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
+
+typedef unsigned int msm_pin_function[10];
+#define SA8775_PIN_OFFSET 0x100000
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)\
+ { \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }
+
+#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, ctl) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = ctl + 0x4, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ }
+
+enum sa8775p_functions {
+ msm_mux_gpio,
+ msm_mux_atest_char,
+ msm_mux_atest_usb2,
+ msm_mux_audio_ref,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async,
+ msm_mux_cci_i2c,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_cci_timer2,
+ msm_mux_cci_timer3,
+ msm_mux_cci_timer4,
+ msm_mux_cci_timer5,
+ msm_mux_cci_timer6,
+ msm_mux_cci_timer7,
+ msm_mux_cci_timer8,
+ msm_mux_cci_timer9,
+ msm_mux_cri_trng,
+ msm_mux_cri_trng0,
+ msm_mux_cri_trng1,
+ msm_mux_dbg_out,
+ msm_mux_ddr_bist,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_pxi1,
+ msm_mux_ddr_pxi2,
+ msm_mux_ddr_pxi3,
+ msm_mux_ddr_pxi4,
+ msm_mux_ddr_pxi5,
+ msm_mux_edp0_hot,
+ msm_mux_edp0_lcd,
+ msm_mux_edp1_hot,
+ msm_mux_edp1_lcd,
+ msm_mux_edp2_hot,
+ msm_mux_edp2_lcd,
+ msm_mux_edp3_hot,
+ msm_mux_edp3_lcd,
+ msm_mux_emac0_mcg0,
+ msm_mux_emac0_mcg1,
+ msm_mux_emac0_mcg2,
+ msm_mux_emac0_mcg3,
+ msm_mux_emac0_mdc,
+ msm_mux_emac0_mdio,
+ msm_mux_emac0_ptp_aux,
+ msm_mux_emac0_ptp_pps,
+ msm_mux_emac1_mcg0,
+ msm_mux_emac1_mcg1,
+ msm_mux_emac1_mcg2,
+ msm_mux_emac1_mcg3,
+ msm_mux_emac1_mdc,
+ msm_mux_emac1_mdio,
+ msm_mux_emac1_ptp_aux,
+ msm_mux_emac1_ptp_pps,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_gcc_gp4,
+ msm_mux_gcc_gp5,
+ msm_mux_hs0_mi2s,
+ msm_mux_hs1_mi2s,
+ msm_mux_hs2_mi2s,
+ msm_mux_ibi_i3c,
+ msm_mux_jitter_bist,
+ msm_mux_mdp0_vsync0,
+ msm_mux_mdp0_vsync1,
+ msm_mux_mdp0_vsync2,
+ msm_mux_mdp0_vsync3,
+ msm_mux_mdp0_vsync4,
+ msm_mux_mdp0_vsync5,
+ msm_mux_mdp0_vsync6,
+ msm_mux_mdp0_vsync7,
+ msm_mux_mdp0_vsync8,
+ msm_mux_mdp1_vsync0,
+ msm_mux_mdp1_vsync1,
+ msm_mux_mdp1_vsync2,
+ msm_mux_mdp1_vsync3,
+ msm_mux_mdp1_vsync4,
+ msm_mux_mdp1_vsync5,
+ msm_mux_mdp1_vsync6,
+ msm_mux_mdp1_vsync7,
+ msm_mux_mdp1_vsync8,
+ msm_mux_mdp_vsync,
+ msm_mux_mi2s1_data0,
+ msm_mux_mi2s1_data1,
+ msm_mux_mi2s1_sck,
+ msm_mux_mi2s1_ws,
+ msm_mux_mi2s2_data0,
+ msm_mux_mi2s2_data1,
+ msm_mux_mi2s2_sck,
+ msm_mux_mi2s2_ws,
+ msm_mux_mi2s_mclk0,
+ msm_mux_mi2s_mclk1,
+ msm_mux_pcie0_clkreq,
+ msm_mux_pcie1_clkreq,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist,
+ msm_mux_pll_clk,
+ msm_mux_prng_rosc0,
+ msm_mux_prng_rosc1,
+ msm_mux_prng_rosc2,
+ msm_mux_prng_rosc3,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_gpio,
+ msm_mux_qup0_se0,
+ msm_mux_qup0_se1,
+ msm_mux_qup0_se2,
+ msm_mux_qup0_se3,
+ msm_mux_qup0_se4,
+ msm_mux_qup0_se5,
+ msm_mux_qup1_se0,
+ msm_mux_qup1_se1,
+ msm_mux_qup1_se2,
+ msm_mux_qup1_se3,
+ msm_mux_qup1_se4,
+ msm_mux_qup1_se5,
+ msm_mux_qup1_se6,
+ msm_mux_qup2_se0,
+ msm_mux_qup2_se1,
+ msm_mux_qup2_se2,
+ msm_mux_qup2_se3,
+ msm_mux_qup2_se4,
+ msm_mux_qup2_se5,
+ msm_mux_qup2_se6,
+ msm_mux_qup3_se0,
+ msm_mux_sail_top,
+ msm_mux_sailss_emac0,
+ msm_mux_sailss_ospi,
+ msm_mux_sgmii_phy,
+ msm_mux_tb_trig,
+ msm_mux_tgu_ch0,
+ msm_mux_tgu_ch1,
+ msm_mux_tgu_ch2,
+ msm_mux_tgu_ch3,
+ msm_mux_tgu_ch4,
+ msm_mux_tgu_ch5,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_tsense_pwm3,
+ msm_mux_tsense_pwm4,
+ msm_mux_usb2phy_ac,
+ msm_mux_vsense_trigger,
+ msm_mux__,
+};
+
+#define MSM_PIN_FUNCTION(fname) \
+ [msm_mux_##fname] = {#fname, msm_mux_##fname}
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ MSM_PIN_FUNCTION(gpio),
+ MSM_PIN_FUNCTION(atest_char),
+ MSM_PIN_FUNCTION(atest_usb2),
+ MSM_PIN_FUNCTION(audio_ref),
+ MSM_PIN_FUNCTION(cam_mclk),
+ MSM_PIN_FUNCTION(cci_async),
+ MSM_PIN_FUNCTION(cci_i2c),
+ MSM_PIN_FUNCTION(cci_timer0),
+ MSM_PIN_FUNCTION(cci_timer1),
+ MSM_PIN_FUNCTION(cci_timer2),
+ MSM_PIN_FUNCTION(cci_timer3),
+ MSM_PIN_FUNCTION(cci_timer4),
+ MSM_PIN_FUNCTION(cci_timer5),
+ MSM_PIN_FUNCTION(cci_timer6),
+ MSM_PIN_FUNCTION(cci_timer7),
+ MSM_PIN_FUNCTION(cci_timer8),
+ MSM_PIN_FUNCTION(cci_timer9),
+ MSM_PIN_FUNCTION(cri_trng),
+ MSM_PIN_FUNCTION(cri_trng0),
+ MSM_PIN_FUNCTION(cri_trng1),
+ MSM_PIN_FUNCTION(dbg_out),
+ MSM_PIN_FUNCTION(ddr_bist),
+ MSM_PIN_FUNCTION(ddr_pxi0),
+ MSM_PIN_FUNCTION(ddr_pxi1),
+ MSM_PIN_FUNCTION(ddr_pxi2),
+ MSM_PIN_FUNCTION(ddr_pxi3),
+ MSM_PIN_FUNCTION(ddr_pxi4),
+ MSM_PIN_FUNCTION(ddr_pxi5),
+ MSM_PIN_FUNCTION(edp0_hot),
+ MSM_PIN_FUNCTION(edp0_lcd),
+ MSM_PIN_FUNCTION(edp1_hot),
+ MSM_PIN_FUNCTION(edp1_lcd),
+ MSM_PIN_FUNCTION(edp2_hot),
+ MSM_PIN_FUNCTION(edp2_lcd),
+ MSM_PIN_FUNCTION(edp3_hot),
+ MSM_PIN_FUNCTION(edp3_lcd),
+ MSM_PIN_FUNCTION(emac0_mcg0),
+ MSM_PIN_FUNCTION(emac0_mcg1),
+ MSM_PIN_FUNCTION(emac0_mcg2),
+ MSM_PIN_FUNCTION(emac0_mcg3),
+ MSM_PIN_FUNCTION(emac0_mdc),
+ MSM_PIN_FUNCTION(emac0_mdio),
+ MSM_PIN_FUNCTION(emac0_ptp_aux),
+ MSM_PIN_FUNCTION(emac0_ptp_pps),
+ MSM_PIN_FUNCTION(emac1_mcg0),
+ MSM_PIN_FUNCTION(emac1_mcg1),
+ MSM_PIN_FUNCTION(emac1_mcg2),
+ MSM_PIN_FUNCTION(emac1_mcg3),
+ MSM_PIN_FUNCTION(emac1_mdc),
+ MSM_PIN_FUNCTION(emac1_mdio),
+ MSM_PIN_FUNCTION(emac1_ptp_aux),
+ MSM_PIN_FUNCTION(emac1_ptp_pps),
+ MSM_PIN_FUNCTION(gcc_gp1),
+ MSM_PIN_FUNCTION(gcc_gp2),
+ MSM_PIN_FUNCTION(gcc_gp3),
+ MSM_PIN_FUNCTION(gcc_gp4),
+ MSM_PIN_FUNCTION(gcc_gp5),
+ MSM_PIN_FUNCTION(hs0_mi2s),
+ MSM_PIN_FUNCTION(hs1_mi2s),
+ MSM_PIN_FUNCTION(hs2_mi2s),
+ MSM_PIN_FUNCTION(ibi_i3c),
+ MSM_PIN_FUNCTION(jitter_bist),
+ MSM_PIN_FUNCTION(mdp0_vsync0),
+ MSM_PIN_FUNCTION(mdp0_vsync1),
+ MSM_PIN_FUNCTION(mdp0_vsync2),
+ MSM_PIN_FUNCTION(mdp0_vsync3),
+ MSM_PIN_FUNCTION(mdp0_vsync4),
+ MSM_PIN_FUNCTION(mdp0_vsync5),
+ MSM_PIN_FUNCTION(mdp0_vsync6),
+ MSM_PIN_FUNCTION(mdp0_vsync7),
+ MSM_PIN_FUNCTION(mdp0_vsync8),
+ MSM_PIN_FUNCTION(mdp1_vsync0),
+ MSM_PIN_FUNCTION(mdp1_vsync1),
+ MSM_PIN_FUNCTION(mdp1_vsync2),
+ MSM_PIN_FUNCTION(mdp1_vsync3),
+ MSM_PIN_FUNCTION(mdp1_vsync4),
+ MSM_PIN_FUNCTION(mdp1_vsync5),
+ MSM_PIN_FUNCTION(mdp1_vsync6),
+ MSM_PIN_FUNCTION(mdp1_vsync7),
+ MSM_PIN_FUNCTION(mdp1_vsync8),
+ MSM_PIN_FUNCTION(mdp_vsync),
+ MSM_PIN_FUNCTION(mi2s1_data0),
+ MSM_PIN_FUNCTION(mi2s1_data1),
+ MSM_PIN_FUNCTION(mi2s1_sck),
+ MSM_PIN_FUNCTION(mi2s1_ws),
+ MSM_PIN_FUNCTION(mi2s2_data0),
+ MSM_PIN_FUNCTION(mi2s2_data1),
+ MSM_PIN_FUNCTION(mi2s2_sck),
+ MSM_PIN_FUNCTION(mi2s2_ws),
+ MSM_PIN_FUNCTION(mi2s_mclk0),
+ MSM_PIN_FUNCTION(mi2s_mclk1),
+ MSM_PIN_FUNCTION(pcie0_clkreq),
+ MSM_PIN_FUNCTION(pcie1_clkreq),
+ MSM_PIN_FUNCTION(phase_flag),
+ MSM_PIN_FUNCTION(pll_bist),
+ MSM_PIN_FUNCTION(pll_clk),
+ MSM_PIN_FUNCTION(prng_rosc0),
+ MSM_PIN_FUNCTION(prng_rosc1),
+ MSM_PIN_FUNCTION(prng_rosc2),
+ MSM_PIN_FUNCTION(prng_rosc3),
+ MSM_PIN_FUNCTION(qdss_cti),
+ MSM_PIN_FUNCTION(qdss_gpio),
+ MSM_PIN_FUNCTION(qup0_se0),
+ MSM_PIN_FUNCTION(qup0_se1),
+ MSM_PIN_FUNCTION(qup0_se2),
+ MSM_PIN_FUNCTION(qup0_se3),
+ MSM_PIN_FUNCTION(qup0_se4),
+ MSM_PIN_FUNCTION(qup0_se5),
+ MSM_PIN_FUNCTION(qup1_se0),
+ MSM_PIN_FUNCTION(qup1_se1),
+ MSM_PIN_FUNCTION(qup1_se2),
+ MSM_PIN_FUNCTION(qup1_se3),
+ MSM_PIN_FUNCTION(qup1_se4),
+ MSM_PIN_FUNCTION(qup1_se5),
+ MSM_PIN_FUNCTION(qup1_se6),
+ MSM_PIN_FUNCTION(qup2_se0),
+ MSM_PIN_FUNCTION(qup2_se1),
+ MSM_PIN_FUNCTION(qup2_se2),
+ MSM_PIN_FUNCTION(qup2_se3),
+ MSM_PIN_FUNCTION(qup2_se4),
+ MSM_PIN_FUNCTION(qup2_se5),
+ MSM_PIN_FUNCTION(qup2_se6),
+ MSM_PIN_FUNCTION(qup3_se0),
+ MSM_PIN_FUNCTION(sail_top),
+ MSM_PIN_FUNCTION(sailss_emac0),
+ MSM_PIN_FUNCTION(sailss_ospi),
+ MSM_PIN_FUNCTION(sgmii_phy),
+ MSM_PIN_FUNCTION(tb_trig),
+ MSM_PIN_FUNCTION(tgu_ch0),
+ MSM_PIN_FUNCTION(tgu_ch1),
+ MSM_PIN_FUNCTION(tgu_ch2),
+ MSM_PIN_FUNCTION(tgu_ch3),
+ MSM_PIN_FUNCTION(tgu_ch4),
+ MSM_PIN_FUNCTION(tgu_ch5),
+ MSM_PIN_FUNCTION(tsense_pwm1),
+ MSM_PIN_FUNCTION(tsense_pwm2),
+ MSM_PIN_FUNCTION(tsense_pwm3),
+ MSM_PIN_FUNCTION(tsense_pwm4),
+ MSM_PIN_FUNCTION(usb2phy_ac),
+ MSM_PIN_FUNCTION(vsense_trigger),
+};
+
+static const msm_pin_function sa8775p_pin_functions[] = {
+ [0] = PINGROUP(0, _, _, _, _, _, _, _, _, _),
+ [1] = PINGROUP(1, pcie0_clkreq, _, _, _, _, _, _, _, _),
+ [2] = PINGROUP(2, _, _, _, _, _, _, _, _, _),
+ [3] = PINGROUP(3, pcie1_clkreq, _, _, _, _, _, _, _, _),
+ [4] = PINGROUP(4, _, _, _, _, _, _, _, _, _),
+ [5] = PINGROUP(5, _, _, _, _, _, _, _, _, _),
+ [6] = PINGROUP(6, emac0_ptp_aux, emac0_ptp_pps, emac1_ptp_aux,
+ emac1_ptp_pps, _, _, _, _, _),
+ [7] = PINGROUP(7, sgmii_phy, _, _, _, _, _, _, _, _),
+ [8] = PINGROUP(8, emac0_mdc, _, _, _, _, _, _, _, _),
+ [9] = PINGROUP(9, emac0_mdio, _, _, _, _, _, _, _, _),
+ [10] = PINGROUP(10, usb2phy_ac, emac0_ptp_aux, emac0_ptp_pps,
+ emac1_ptp_aux, emac1_ptp_pps, _, _, _, _),
+ [11] = PINGROUP(11, usb2phy_ac, emac0_ptp_aux, emac0_ptp_pps,
+ emac1_ptp_aux, emac1_ptp_pps, _, _, _, _),
+ [12] = PINGROUP(12, usb2phy_ac, emac0_ptp_aux, emac0_ptp_pps,
+ emac1_ptp_aux, emac1_ptp_pps, emac0_mcg0, _, _, _),
+ [13] = PINGROUP(13, qup3_se0, emac0_mcg1, _, _, sail_top, _, _, _, _),
+ [14] = PINGROUP(14, qup3_se0, emac0_mcg2, _, _, sail_top, _, _, _, _),
+ [15] = PINGROUP(15, qup3_se0, emac0_mcg3, _, _, sail_top, _, _, _, _),
+ [16] = PINGROUP(16, qup3_se0, emac1_mcg0, _, _, sail_top, _, _, _, _),
+ [17] = PINGROUP(17, qup3_se0, tb_trig, tb_trig, emac1_mcg1, _, _, _, _, _),
+ [18] = PINGROUP(18, qup3_se0, emac1_mcg2, _, _, sailss_ospi, sailss_emac0, _, _, _),
+ [19] = PINGROUP(19, qup3_se0, emac1_mcg3, _, _, sailss_ospi, sailss_emac0, _, _, _),
+ [20] = PINGROUP(20, qup0_se0, emac1_mdc, qdss_gpio, _, _, _, _, _, _),
+ [21] = PINGROUP(21, qup0_se0, emac1_mdio, qdss_gpio, _, _, _, _, _, _),
+ [22] = PINGROUP(22, qup0_se0, qdss_gpio, _, _, _, _, _, _, _),
+ [23] = PINGROUP(23, qup0_se0, qdss_gpio, _, _, _, _, _, _, _),
+ [24] = PINGROUP(24, qup0_se1, qdss_gpio, _, _, _, _, _, _, _),
+ [25] = PINGROUP(25, qup0_se1, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [26] = PINGROUP(26, sgmii_phy, qup0_se1, qdss_cti, phase_flag, _, _, _, _, _),
+ [27] = PINGROUP(27, qup0_se1, qdss_cti, phase_flag, _, atest_char, _, _, _, _),
+ [28] = PINGROUP(28, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [29] = PINGROUP(29, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [30] = PINGROUP(30, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [31] = PINGROUP(31, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [32] = PINGROUP(32, qup0_se4, phase_flag, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, qup0_se4, gcc_gp4, _, ddr_pxi0, _, _, _, _, _),
+ [34] = PINGROUP(34, qup0_se4, gcc_gp5, _, ddr_pxi0, _, _, _, _, _),
+ [35] = PINGROUP(35, qup0_se4, phase_flag, _, _, _, _, _, _, _),
+ [36] = PINGROUP(36, qup0_se2, qup0_se5, phase_flag, tgu_ch2, _, _, _, _, _),
+ [37] = PINGROUP(37, qup0_se2, qup0_se5, phase_flag, tgu_ch3, _, _, _, _, _),
+ [38] = PINGROUP(38, qup0_se5, qup0_se2, qdss_cti, phase_flag, tgu_ch4, _, _, _, _),
+ [39] = PINGROUP(39, qup0_se5, qup0_se2, qdss_cti, phase_flag, tgu_ch5, _, _, _, _),
+ [40] = PINGROUP(40, qup1_se0, qup1_se1, ibi_i3c, mdp1_vsync0, _, _, _, _, _),
+ [41] = PINGROUP(41, qup1_se0, qup1_se1, ibi_i3c, mdp1_vsync1, _, _, _, _, _),
+ [42] = PINGROUP(42, qup1_se1, qup1_se0, ibi_i3c, mdp1_vsync2, gcc_gp5, _, _, _, _),
+ [43] = PINGROUP(43, qup1_se1, qup1_se0, ibi_i3c, mdp1_vsync3, _, _, _, _, _),
+ [44] = PINGROUP(44, qup1_se2, qup1_se3, edp0_lcd, _, _, _, _, _, _),
+ [45] = PINGROUP(45, qup1_se2, qup1_se3, edp1_lcd, _, _, _, _, _, _),
+ [46] = PINGROUP(46, qup1_se3, qup1_se2, mdp1_vsync4, tgu_ch0, _, _, _, _, _),
+ [47] = PINGROUP(47, qup1_se3, qup1_se2, mdp1_vsync5, tgu_ch1, _, _, _, _, _),
+ [48] = PINGROUP(48, qup1_se4, qdss_cti, edp2_lcd, _, _, _, _, _, _),
+ [49] = PINGROUP(49, qup1_se4, qdss_cti, edp3_lcd, _, _, _, _, _, _),
+ [50] = PINGROUP(50, qup1_se4, cci_async, qdss_cti, mdp1_vsync8, _, _, _, _, _),
+ [51] = PINGROUP(51, qup1_se4, qdss_cti, mdp1_vsync6, gcc_gp1, _, _, _, _, _),
+ [52] = PINGROUP(52, qup1_se5, cci_timer4, cci_i2c, mdp1_vsync7, gcc_gp2, _, ddr_pxi1, _, _),
+ [53] = PINGROUP(53, qup1_se5, cci_timer5, cci_i2c, gcc_gp3, _, ddr_pxi1, _, _, _),
+ [54] = PINGROUP(54, qup1_se5, cci_timer6, cci_i2c, _, _, _, _, _, _),
+ [55] = PINGROUP(55, qup1_se5, cci_timer7, cci_i2c, gcc_gp4, _, ddr_pxi2, _, _, _),
+ [56] = PINGROUP(56, qup1_se6, qup1_se6, cci_timer8, cci_i2c, phase_flag, ddr_bist, _, _, _),
+ [57] = PINGROUP(57, qup1_se6, qup1_se6, cci_timer9, cci_i2c,
+ mdp0_vsync0, phase_flag, ddr_bist, _, _),
+ [58] = PINGROUP(58, cci_i2c, mdp0_vsync1, ddr_bist, _, atest_usb2, atest_char, _, _, _),
+ [59] = PINGROUP(59, cci_i2c, mdp0_vsync2, ddr_bist, _, atest_usb2, atest_char, _, _, _),
+ [60] = PINGROUP(60, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [61] = PINGROUP(61, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [62] = PINGROUP(62, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [63] = PINGROUP(63, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [66] = PINGROUP(66, cci_i2c, cci_async, qdss_gpio, _, _, _, _, _, _),
+ [67] = PINGROUP(67, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [68] = PINGROUP(68, cci_timer0, cci_async, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, cci_timer1, cci_async, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, cci_timer2, cci_async, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, cci_timer3, cci_async, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, cam_mclk, _, _, _, _, _, _, _, _),
+ [73] = PINGROUP(73, cam_mclk, _, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, cam_mclk, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, cam_mclk, _, _, _, _, _, _, _, _),
+ [76] = PINGROUP(76, _, _, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, _, _, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, _, _, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, _, _, _, _, _, _, _, _, _),
+ [80] = PINGROUP(80, qup2_se0, ibi_i3c, mdp0_vsync3, _, _, _, _, _, _),
+ [81] = PINGROUP(81, qup2_se0, ibi_i3c, mdp0_vsync4, _, _, _, _, _, _),
+ [82] = PINGROUP(82, qup2_se0, mdp_vsync, gcc_gp1, _, _, _, _, _, _),
+ [83] = PINGROUP(83, qup2_se0, mdp_vsync, gcc_gp2, _, _, _, _, _, _),
+ [84] = PINGROUP(84, qup2_se1, qup2_se5, ibi_i3c, mdp_vsync, gcc_gp3, _, _, _, _),
+ [85] = PINGROUP(85, qup2_se1, qup2_se5, ibi_i3c, _, _, _, _, _, _),
+ [86] = PINGROUP(86, qup2_se2, jitter_bist, atest_usb2, ddr_pxi2, _, _, _, _, _),
+ [87] = PINGROUP(87, qup2_se2, pll_clk, atest_usb2, ddr_pxi3, _, _, _, _, _),
+ [88] = PINGROUP(88, qup2_se2, _, atest_usb2, ddr_pxi3, _, _, _, _, _),
+ [89] = PINGROUP(89, qup2_se2, _, atest_usb2, ddr_pxi4, atest_char, _, _, _, _),
+ [90] = PINGROUP(90, qup2_se2, _, atest_usb2, ddr_pxi4, atest_char, _, _, _, _),
+ [91] = PINGROUP(91, qup2_se3, mdp0_vsync5, _, atest_usb2, _, _, _, _, _),
+ [92] = PINGROUP(92, qup2_se3, mdp0_vsync6, _, atest_usb2, _, _, _, _, _),
+ [93] = PINGROUP(93, qup2_se3, mdp0_vsync7, _, atest_usb2, _, _, _, _, _),
+ [94] = PINGROUP(94, qup2_se3, mdp0_vsync8, _, atest_usb2, _, _, _, _, _),
+ [95] = PINGROUP(95, qup2_se4, qup2_se6, _, atest_usb2, _, _, _, _, _),
+ [96] = PINGROUP(96, qup2_se4, qup2_se6, _, atest_usb2, _, _, _, _, _),
+ [97] = PINGROUP(97, qup2_se6, qup2_se4, cri_trng0, _, atest_usb2, _, _, _, _),
+ [98] = PINGROUP(98, qup2_se6, qup2_se4, phase_flag, cri_trng1, _, _, _, _, _),
+ [99] = PINGROUP(99, qup2_se5, qup2_se1, phase_flag, cri_trng, _, _, _, _, _),
+ [100] = PINGROUP(100, qup2_se5, qup2_se1, _, _, _, _, _, _, _),
+ [101] = PINGROUP(101, edp0_hot, prng_rosc0, tsense_pwm4, _, _, _, _, _, _),
+ [102] = PINGROUP(102, edp1_hot, prng_rosc1, tsense_pwm3, _, _, _, _, _, _),
+ [103] = PINGROUP(103, edp3_hot, prng_rosc2, tsense_pwm2, _, _, _, _, _, _),
+ [104] = PINGROUP(104, edp2_hot, prng_rosc3, tsense_pwm1, _, _, _, _, _, _),
+ [105] = PINGROUP(105, mi2s_mclk0, _, qdss_gpio, atest_usb2, _, _, _, _, _),
+ [106] = PINGROUP(106, mi2s1_sck, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [107] = PINGROUP(107, mi2s1_ws, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [108] = PINGROUP(108, mi2s1_data0, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [109] = PINGROUP(109, mi2s1_data1, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [110] = PINGROUP(110, mi2s2_sck, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [111] = PINGROUP(111, mi2s2_ws, phase_flag, _, qdss_gpio, vsense_trigger, _, _, _, _),
+ [112] = PINGROUP(112, mi2s2_data0, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [113] = PINGROUP(113, mi2s2_data1, audio_ref, phase_flag, _, qdss_gpio, _, _, _, _),
+ [114] = PINGROUP(114, hs0_mi2s, pll_bist, phase_flag, _, qdss_gpio, _, _, _, _),
+ [115] = PINGROUP(115, hs0_mi2s, _, qdss_gpio, _, _, _, _, _, _),
+ [116] = PINGROUP(116, hs0_mi2s, _, qdss_gpio, _, _, _, _, _, _),
+ [117] = PINGROUP(117, hs0_mi2s, mi2s_mclk1, _, qdss_gpio, _, _, _, _, _),
+ [118] = PINGROUP(118, hs1_mi2s, _, qdss_gpio, ddr_pxi5, _, _, _, _, _),
+ [119] = PINGROUP(119, hs1_mi2s, _, qdss_gpio, ddr_pxi5, _, _, _, _, _),
+ [120] = PINGROUP(120, hs1_mi2s, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [121] = PINGROUP(121, hs1_mi2s, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [122] = PINGROUP(122, hs2_mi2s, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [123] = PINGROUP(123, hs2_mi2s, phase_flag, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, hs2_mi2s, phase_flag, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, hs2_mi2s, phase_flag, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, _, _, _, _, _, _, _, _, _),
+ [127] = PINGROUP(127, _, _, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, _, _, _, _, _, _, _, _, _),
+ [129] = PINGROUP(129, _, _, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, _, _, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, _, _, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, _, _, _, _, _, _, _, _, _),
+ [133] = PINGROUP(133, _, _, _, _, _, _, _, _, _),
+ [134] = PINGROUP(134, _, _, _, _, _, _, _, _, _),
+ [135] = PINGROUP(135, _, _, _, _, _, _, _, _, _),
+ [136] = PINGROUP(136, _, _, _, _, _, _, _, _, _),
+ [137] = PINGROUP(137, _, _, _, _, _, _, _, _, _),
+ [138] = PINGROUP(138, _, _, _, _, _, _, _, _, _),
+ [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _),
+ [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _),
+ [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _),
+ [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _),
+ [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _),
+ [144] = PINGROUP(144, dbg_out, _, _, _, _, _, _, _, _),
+ [145] = PINGROUP(145, _, _, _, _, _, _, _, _, _),
+ [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _),
+ [147] = PINGROUP(147, _, _, _, _, _, _, _, _, _),
+ [148] = PINGROUP(148, _, _, _, _, _, _, _, _, _),
+};
+
+static const struct msm_special_pin_data msm_special_pins_data[] = {
+ [0] = UFS_RESET("ufs_reset", 0x1a2000),
+ [1] = SDC_QDSD_PINGROUP("sdc1_rclk", 0x199000, 15, 0),
+ [2] = SDC_QDSD_PINGROUP("sdc1_clk", 0x199000, 13, 6),
+ [3] = SDC_QDSD_PINGROUP("sdc1_cmd", 0x199000, 11, 3),
+ [4] = SDC_QDSD_PINGROUP("sdc1_data", 0x199000, 9, 0),
+};
+
+static const char *sa8775p_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *sa8775p_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ if (selector >= 149 && selector <= 155)
+ snprintf(pin_name, MAX_PIN_NAME_LEN,
+ msm_special_pins_data[selector - 149].name);
+ else
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
+
+ return pin_name;
+}
+
+static int sa8775p_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
+{
+ unsigned int i;
+ const msm_pin_function *func = sa8775p_pin_functions + pin;
+
+ for (i = 0; i < 10; i++)
+ if ((*func)[i] == selector)
+ return i;
+
+ pr_err("Can't find requested function for pin %u pin\n", pin);
+
+ return -EINVAL;
+}
+
+static const unsigned int sa8775p_pin_offsets[] = {
+ [0] = SA8775_PIN_OFFSET, [1] = SA8775_PIN_OFFSET, [2] = SA8775_PIN_OFFSET,
+ [3] = SA8775_PIN_OFFSET, [4] = SA8775_PIN_OFFSET, [5] = SA8775_PIN_OFFSET,
+ [6] = SA8775_PIN_OFFSET, [7] = SA8775_PIN_OFFSET, [8] = SA8775_PIN_OFFSET,
+ [9] = SA8775_PIN_OFFSET, [10] = SA8775_PIN_OFFSET, [11] = SA8775_PIN_OFFSET,
+ [12] = SA8775_PIN_OFFSET, [13] = SA8775_PIN_OFFSET, [14] = SA8775_PIN_OFFSET,
+ [15] = SA8775_PIN_OFFSET, [16] = SA8775_PIN_OFFSET, [17] = SA8775_PIN_OFFSET,
+ [18] = SA8775_PIN_OFFSET, [19] = SA8775_PIN_OFFSET, [20] = SA8775_PIN_OFFSET,
+ [21] = SA8775_PIN_OFFSET, [22] = SA8775_PIN_OFFSET, [23] = SA8775_PIN_OFFSET,
+ [24] = SA8775_PIN_OFFSET, [25] = SA8775_PIN_OFFSET, [26] = SA8775_PIN_OFFSET,
+ [27] = SA8775_PIN_OFFSET, [28] = SA8775_PIN_OFFSET, [29] = SA8775_PIN_OFFSET,
+ [30] = SA8775_PIN_OFFSET, [31] = SA8775_PIN_OFFSET, [32] = SA8775_PIN_OFFSET,
+ [33] = SA8775_PIN_OFFSET, [34] = SA8775_PIN_OFFSET, [35] = SA8775_PIN_OFFSET,
+ [36] = SA8775_PIN_OFFSET, [37] = SA8775_PIN_OFFSET, [38] = SA8775_PIN_OFFSET,
+ [39] = SA8775_PIN_OFFSET, [40] = SA8775_PIN_OFFSET, [41] = SA8775_PIN_OFFSET,
+ [42] = SA8775_PIN_OFFSET, [43] = SA8775_PIN_OFFSET, [44] = SA8775_PIN_OFFSET,
+ [45] = SA8775_PIN_OFFSET, [46] = SA8775_PIN_OFFSET, [47] = SA8775_PIN_OFFSET,
+ [48] = SA8775_PIN_OFFSET, [49] = SA8775_PIN_OFFSET, [50] = SA8775_PIN_OFFSET,
+ [51] = SA8775_PIN_OFFSET, [52] = SA8775_PIN_OFFSET, [53] = SA8775_PIN_OFFSET,
+ [54] = SA8775_PIN_OFFSET, [55] = SA8775_PIN_OFFSET, [56] = SA8775_PIN_OFFSET,
+ [57] = SA8775_PIN_OFFSET, [58] = SA8775_PIN_OFFSET, [59] = SA8775_PIN_OFFSET,
+ [60] = SA8775_PIN_OFFSET, [61] = SA8775_PIN_OFFSET, [62] = SA8775_PIN_OFFSET,
+ [63] = SA8775_PIN_OFFSET, [64] = SA8775_PIN_OFFSET, [65] = SA8775_PIN_OFFSET,
+ [66] = SA8775_PIN_OFFSET, [67] = SA8775_PIN_OFFSET, [68] = SA8775_PIN_OFFSET,
+ [69] = SA8775_PIN_OFFSET, [70] = SA8775_PIN_OFFSET, [71] = SA8775_PIN_OFFSET,
+ [72] = SA8775_PIN_OFFSET, [73] = SA8775_PIN_OFFSET, [74] = SA8775_PIN_OFFSET,
+ [75] = SA8775_PIN_OFFSET, [76] = SA8775_PIN_OFFSET, [77] = SA8775_PIN_OFFSET,
+ [78] = SA8775_PIN_OFFSET, [79] = SA8775_PIN_OFFSET, [80] = SA8775_PIN_OFFSET,
+ [81] = SA8775_PIN_OFFSET, [82] = SA8775_PIN_OFFSET, [83] = SA8775_PIN_OFFSET,
+ [84] = SA8775_PIN_OFFSET, [85] = SA8775_PIN_OFFSET, [86] = SA8775_PIN_OFFSET,
+ [87] = SA8775_PIN_OFFSET, [88] = SA8775_PIN_OFFSET, [89] = SA8775_PIN_OFFSET,
+ [90] = SA8775_PIN_OFFSET, [91] = SA8775_PIN_OFFSET, [92] = SA8775_PIN_OFFSET,
+ [93] = SA8775_PIN_OFFSET, [94] = SA8775_PIN_OFFSET, [95] = SA8775_PIN_OFFSET,
+ [96] = SA8775_PIN_OFFSET, [97] = SA8775_PIN_OFFSET, [98] = SA8775_PIN_OFFSET,
+ [99] = SA8775_PIN_OFFSET, [100] = SA8775_PIN_OFFSET, [101] = SA8775_PIN_OFFSET,
+ [102] = SA8775_PIN_OFFSET, [103] = SA8775_PIN_OFFSET, [104] = SA8775_PIN_OFFSET,
+ [105] = SA8775_PIN_OFFSET, [106] = SA8775_PIN_OFFSET, [107] = SA8775_PIN_OFFSET,
+ [108] = SA8775_PIN_OFFSET, [109] = SA8775_PIN_OFFSET, [110] = SA8775_PIN_OFFSET,
+ [111] = SA8775_PIN_OFFSET, [112] = SA8775_PIN_OFFSET, [113] = SA8775_PIN_OFFSET,
+ [114] = SA8775_PIN_OFFSET, [115] = SA8775_PIN_OFFSET, [116] = SA8775_PIN_OFFSET,
+ [117] = SA8775_PIN_OFFSET, [118] = SA8775_PIN_OFFSET, [119] = SA8775_PIN_OFFSET,
+ [120] = SA8775_PIN_OFFSET, [121] = SA8775_PIN_OFFSET, [122] = SA8775_PIN_OFFSET,
+ [123] = SA8775_PIN_OFFSET, [124] = SA8775_PIN_OFFSET, [125] = SA8775_PIN_OFFSET,
+ [126] = SA8775_PIN_OFFSET, [127] = SA8775_PIN_OFFSET, [128] = SA8775_PIN_OFFSET,
+ [129] = SA8775_PIN_OFFSET, [130] = SA8775_PIN_OFFSET, [131] = SA8775_PIN_OFFSET,
+ [132] = SA8775_PIN_OFFSET, [133] = SA8775_PIN_OFFSET, [134] = SA8775_PIN_OFFSET,
+ [135] = SA8775_PIN_OFFSET, [136] = SA8775_PIN_OFFSET, [137] = SA8775_PIN_OFFSET,
+ [138] = SA8775_PIN_OFFSET, [139] = SA8775_PIN_OFFSET, [140] = SA8775_PIN_OFFSET,
+ [141] = SA8775_PIN_OFFSET, [142] = SA8775_PIN_OFFSET, [143] = SA8775_PIN_OFFSET,
+ [144] = SA8775_PIN_OFFSET, [145] = SA8775_PIN_OFFSET, [146] = SA8775_PIN_OFFSET,
+ [147] = SA8775_PIN_OFFSET, [148] = SA8775_PIN_OFFSET, [148] = SA8775_PIN_OFFSET,
+ [149] = SA8775_PIN_OFFSET, [150] = SA8775_PIN_OFFSET, [151] = SA8775_PIN_OFFSET,
+ [152] = SA8775_PIN_OFFSET, [153] = SA8775_PIN_OFFSET, [154] = SA8775_PIN_OFFSET,
+};
+
+static const struct msm_pinctrl_data sa8775p_data = {
+ .pin_data = {
+ .pin_count = 155,
+ .special_pins_start = 149,
+ .special_pins_data = msm_special_pins_data,
+ .pin_offsets = sa8775p_pin_offsets,
+ },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = sa8775p_get_function_name,
+ .get_function_mux = sa8775p_get_function_mux,
+ .get_pin_name = sa8775p_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ { .compatible = "qcom,sa8775p-tlmm", .data = (ulong)&sa8775p_data },
+ { /* Sentinal */ }
+};
+
+U_BOOT_DRIVER(pinctrl_sa8775p) = {
+ .name = "pinctrl_sa8775p",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660.c b/drivers/pinctrl/qcom/pinctrl-sdm660.c
new file mode 100644
index 00000000000..646d848ffa4
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sdm660.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm SDM630/660 TLMM pinctrl
+ *
+ */
+
+#include <dm.h>
+#include "pinctrl-qcom.h"
+
+#define TLMM_BASE 0x03100000
+#define SOUTH (0x03100000 - TLMM_BASE) /* 0x0 */
+#define CENTER (0x03500000 - TLMM_BASE) /* 0x400000 */
+#define NORTH (0x03900000 - TLMM_BASE) /* 0x800000 */
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
+
+static const struct pinctrl_function sdm660_pinctrl_functions[] = {
+ { "gpio", 0 },
+ { "blsp_uart2", 3 }, /* gpio 4 and 5, used for debug uart */
+};
+
+static const unsigned int sdm660_pin_offsets[] = {
+ [0] = SOUTH,
+ [1] = SOUTH,
+ [2] = SOUTH,
+ [3] = SOUTH,
+ [4] = NORTH,
+ [5] = SOUTH,
+ [6] = SOUTH,
+ [7] = SOUTH,
+ [8] = NORTH,
+ [9] = NORTH,
+ [10] = NORTH,
+ [11] = NORTH,
+ [12] = NORTH,
+ [13] = NORTH,
+ [14] = NORTH,
+ [15] = NORTH,
+ [16] = CENTER,
+ [17] = CENTER,
+ [18] = CENTER,
+ [19] = CENTER,
+ [20] = SOUTH,
+ [21] = SOUTH,
+ [22] = CENTER,
+ [23] = CENTER,
+ [24] = NORTH,
+ [25] = NORTH,
+ [26] = NORTH,
+ [27] = NORTH,
+ [28] = CENTER,
+ [29] = CENTER,
+ [30] = CENTER,
+ [31] = CENTER,
+ [32] = SOUTH,
+ [33] = SOUTH,
+ [34] = SOUTH,
+ [35] = SOUTH,
+ [36] = SOUTH,
+ [37] = SOUTH,
+ [38] = SOUTH,
+ [39] = SOUTH,
+ [40] = SOUTH,
+ [41] = SOUTH,
+ [42] = SOUTH,
+ [43] = SOUTH,
+ [44] = SOUTH,
+ [45] = SOUTH,
+ [46] = SOUTH,
+ [47] = SOUTH,
+ [48] = SOUTH,
+ [49] = SOUTH,
+ [50] = SOUTH,
+ [51] = SOUTH,
+ [52] = SOUTH,
+ [53] = NORTH,
+ [54] = NORTH,
+ [55] = SOUTH,
+ [56] = SOUTH,
+ [57] = SOUTH,
+ [58] = SOUTH,
+ [59] = NORTH,
+ [60] = NORTH,
+ [61] = NORTH,
+ [62] = NORTH,
+ [63] = NORTH,
+ [64] = SOUTH,
+ [65] = SOUTH,
+ [66] = NORTH,
+ [67] = NORTH,
+ [68] = NORTH,
+ [69] = NORTH,
+ [70] = NORTH,
+ [71] = NORTH,
+ [72] = NORTH,
+ [73] = NORTH,
+ [74] = NORTH,
+ [75] = NORTH,
+ [76] = NORTH,
+ [77] = NORTH,
+ [78] = NORTH,
+ [79] = SOUTH,
+ [80] = SOUTH,
+ [81] = CENTER,
+ [82] = CENTER,
+ [83] = SOUTH,
+ [84] = SOUTH,
+ [85] = SOUTH,
+ [86] = SOUTH,
+ [87] = SOUTH,
+ [88] = SOUTH,
+ [89] = SOUTH,
+ [90] = SOUTH,
+ [91] = SOUTH,
+ [92] = SOUTH,
+ [93] = SOUTH,
+ [94] = SOUTH,
+ [95] = SOUTH,
+ [96] = SOUTH,
+ [97] = SOUTH,
+ [98] = SOUTH,
+ [99] = SOUTH,
+ [100] = SOUTH,
+ [101] = SOUTH,
+ [102] = SOUTH,
+ [103] = SOUTH,
+ [104] = SOUTH,
+ [105] = SOUTH,
+ [106] = SOUTH,
+ [107] = SOUTH,
+ [108] = SOUTH,
+ [109] = SOUTH,
+ [110] = SOUTH,
+ [111] = SOUTH,
+ [112] = SOUTH,
+ [113] = SOUTH,
+};
+
+/*
+ * Special pins - eMMC/SD related: [114..120], in total 7 special pins
+ */
+
+#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, \
+ }
+
+/* All SDC pins are in the NORTH tile */
+static const struct msm_special_pin_data sdm660_special_pins_data[] = {
+ SDC_QDSD_PINGROUP("sdc1_clk", NORTH + 0x9a000, 13, 6),
+ SDC_QDSD_PINGROUP("sdc1_cmd", NORTH + 0x9a000, 11, 3),
+ SDC_QDSD_PINGROUP("sdc1_data", NORTH + 0x9a000, 9, 0),
+ SDC_QDSD_PINGROUP("sdc2_clk", NORTH + 0x9b000, 14, 6),
+ SDC_QDSD_PINGROUP("sdc2_cmd", NORTH + 0x9b000, 11, 3),
+ SDC_QDSD_PINGROUP("sdc2_data", NORTH + 0x9b000, 9, 0),
+ SDC_QDSD_PINGROUP("sdc1_rclk", NORTH + 0x9a000, 15, 0),
+};
+
+static const char *sdm660_get_function_name(struct udevice *dev, unsigned int selector)
+{
+ return sdm660_pinctrl_functions[selector].name;
+}
+
+static const char *sdm660_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+ static const char * const special_pins_names[] = {
+ "sdc1_clk", "sdc1_cmd", "sdc1_data",
+ "sdc2_clk", "sdc2_cmd", "sdc2_data",
+ "sdc1_rclk"
+ };
+
+ if (selector >= 114 && selector <= 120)
+ snprintf(pin_name, MAX_PIN_NAME_LEN, special_pins_names[selector - 114]);
+ else
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
+
+ return pin_name;
+}
+
+static int sdm660_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
+{
+ if (selector >= 0 && selector < ARRAY_SIZE(sdm660_pinctrl_functions))
+ return sdm660_pinctrl_functions[selector].val;
+ return -EINVAL;
+}
+
+struct msm_pinctrl_data sdm660_data = {
+ .pin_data = {
+ .pin_offsets = sdm660_pin_offsets,
+ .pin_count = ARRAY_SIZE(sdm660_pin_offsets) + ARRAY_SIZE(sdm660_special_pins_data),
+ .special_pins_start = 114,
+ .special_pins_data = sdm660_special_pins_data,
+ },
+ .functions_count = ARRAY_SIZE(sdm660_pinctrl_functions),
+ .get_function_name = sdm660_get_function_name,
+ .get_function_mux = sdm660_get_function_mux,
+ .get_pin_name = sdm660_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ {
+ .compatible = "qcom,sdm630-pinctrl",
+ .data = (ulong)&sdm660_data
+ },
+ {
+ .compatible = "qcom,sdm660-pinctrl",
+ .data = (ulong)&sdm660_data
+ },
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(pinctrl_ssdm660) = {
+ .name = "pinctrl_sdm660",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 8f102a92c23..bab68317cfa 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -224,6 +224,13 @@ config DM_REGULATOR_QCOM_RPMH
implements get/set api for a limited set of regulators used
by u-boot.
+config DM_REGULATOR_QCOM_USB_VBUS
+ bool "Enable driver model for Qualcomm USB vbus regulator"
+ depends on DM_REGULATOR
+ ---help---
+ Enable support for the Qualcomm USB Vbus regulator. The driver
+ implements get/set api for the regulator to be used by u-boot.
+
config SPL_DM_REGULATOR_GPIO
bool "Enable Driver Model for GPIO REGULATOR in SPL"
depends on DM_REGULATOR_GPIO && SPL_GPIO
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index 4382d4b3ab9..054a93e129a 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_$(XPL_)DM_REGULATOR_COMMON) += regulator_common.o
obj-$(CONFIG_$(XPL_)DM_REGULATOR_FIXED) += fixed.o
obj-$(CONFIG_$(XPL_)DM_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_DM_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
+obj-$(CONFIG_DM_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus_regulator.o
obj-$(CONFIG_$(PHASE_)REGULATOR_RK8XX) += rk8xx.o
obj-$(CONFIG_DM_REGULATOR_S2MPS11) += s2mps11_regulator.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c
index cd2b1a654c1..954deca5ed7 100644
--- a/drivers/power/regulator/qcom-rpmh-regulator.c
+++ b/drivers/power/regulator/qcom-rpmh-regulator.c
@@ -466,6 +466,25 @@ static const struct rpmh_vreg_hw_data pmic5_nldo515 = {
.n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
};
+static const struct rpmh_vreg_hw_data pmic5_ftsmps527 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+ .n_voltages = 215,
+ .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_pldo515_mv = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(1800000, 0, 187, 8000),
+ .n_voltages = 188,
+ .hpm_min_load_uA = 10000,
+ .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, \
@@ -558,6 +577,28 @@ static const struct rpmh_vreg_init_data pmc8380_vreg_data[] = {
{}
};
+static const struct rpmh_vreg_init_data pmm8654au_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps527, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps527, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps527, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps527, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps527, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps527, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps527, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps527, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps527, "vdd-s9"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo515, "vdd-l6-l7"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l6-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo515_mv, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"),
+ {}
+};
+
/* probe an individual regulator */
static int rpmh_regulator_probe(struct udevice *dev)
{
@@ -688,6 +729,10 @@ static const struct udevice_id rpmh_regulator_ids[] = {
.compatible = "qcom,pmc8380-rpmh-regulators",
.data = (ulong)pmc8380_vreg_data,
},
+ {
+ .compatible = "qcom,pmm8654au-rpmh-regulators",
+ .data = (ulong)pmm8654au_vreg_data,
+ },
{ /* sentinal */ },
};
diff --git a/drivers/power/regulator/qcom_usb_vbus_regulator.c b/drivers/power/regulator/qcom_usb_vbus_regulator.c
new file mode 100644
index 00000000000..2d58ef5e111
--- /dev/null
+++ b/drivers/power/regulator/qcom_usb_vbus_regulator.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Linaro Limited
+ */
+#define pr_fmt(fmt) "qcom_usb_vbus: " fmt
+
+#include <bitfield.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+#include <linux/printk.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#define CMD_OTG 0x50
+#define OTG_EN BIT(0)
+// The 0 bit in this register's bit field is undocumented
+#define OTG_CFG 0x56
+#define OTG_EN_SRC_CFG BIT(1)
+
+struct qcom_usb_vbus_priv {
+ phys_addr_t base;
+};
+
+static int qcom_usb_vbus_regulator_of_to_plat(struct udevice *dev)
+{
+ struct qcom_usb_vbus_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qcom_usb_vbus_regulator_get_enable(struct udevice *dev)
+{
+ struct qcom_usb_vbus_priv *priv = dev_get_priv(dev);
+ int otg_en_reg = priv->base + CMD_OTG;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, otg_en_reg);
+ if (ret < 0)
+ log_err("failed to read usb vbus: %d\n", ret);
+ else
+ ret &= OTG_EN;
+
+ return ret;
+}
+
+static int qcom_usb_vbus_regulator_set_enable(struct udevice *dev, bool enable)
+{
+ struct qcom_usb_vbus_priv *priv = dev_get_priv(dev);
+ int otg_en_reg = priv->base + CMD_OTG;
+ int ret;
+
+ if (enable) {
+ ret = pmic_clrsetbits(dev->parent, otg_en_reg, 0, OTG_EN);
+ if (ret < 0) {
+ log_err("error enabling: %d\n", ret);
+ return ret;
+ }
+ } else {
+ ret = pmic_clrsetbits(dev->parent, otg_en_reg, OTG_EN, 0);
+ if (ret < 0) {
+ log_err("error disabling: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int qcom_usb_vbus_regulator_probe(struct udevice *dev)
+{
+ struct qcom_usb_vbus_priv *priv = dev_get_priv(dev);
+ int otg_cfg_reg = priv->base + OTG_CFG;
+ int ret;
+
+ /* Disable HW logic for VBUS enable */
+ ret = pmic_clrsetbits(dev->parent, otg_cfg_reg, OTG_EN_SRC_CFG, 0);
+ if (ret < 0) {
+ log_err("error setting EN_SRC_CFG: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dm_regulator_ops qcom_usb_vbus_regulator_ops = {
+ .get_enable = qcom_usb_vbus_regulator_get_enable,
+ .set_enable = qcom_usb_vbus_regulator_set_enable,
+};
+
+static const struct udevice_id qcom_usb_vbus_regulator_ids[] = {
+ { .compatible = "qcom,pm8150b-vbus-reg"},
+ { },
+};
+
+U_BOOT_DRIVER(qcom_usb_vbus_regulator) = {
+ .name = "qcom-usb-vbus-regulator",
+ .id = UCLASS_REGULATOR,
+ .of_match = qcom_usb_vbus_regulator_ids,
+ .of_to_plat = qcom_usb_vbus_regulator_of_to_plat,
+ .ops = &qcom_usb_vbus_regulator_ops,
+ .probe = qcom_usb_vbus_regulator_probe,
+ .priv_auto = sizeof(struct qcom_usb_vbus_priv),
+};
diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c
index 5cc5a9e654c..faae54e9fef 100644
--- a/drivers/spmi/spmi-msm.c
+++ b/drivers/spmi/spmi-msm.c
@@ -24,6 +24,9 @@ DECLARE_GLOBAL_DATA_PTR;
#define PMIC_ARB_VERSION_V5_MIN 0x50000000
#define PMIC_ARB_VERSION_V7_MIN 0x70000000
+#define PMIC_ARB_FEATURES 0x0004
+#define PMIC_ARB_FEATURES_PERIPH_MASK GENMASK(10, 0)
+
#define APID_MAP_OFFSET_V1_V2_V3 (0x800)
#define APID_MAP_OFFSET_V5 (0x900)
#define APID_MAP_OFFSET_V7 (0x2000)
@@ -60,6 +63,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define SPMI_MAX_PERIPH 256
#define SPMI_CHANNEL_READ_ONLY BIT(31)
+#define SPMI_CHANNEL_VALID BIT(30)
#define SPMI_CHANNEL_MASK 0xffff
enum arb_ver {
@@ -114,6 +118,8 @@ static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
return -EIO;
if (pid >= SPMI_MAX_PERIPH)
return -EIO;
+ if (!(priv->channel_map[usid][pid] & SPMI_CHANNEL_VALID))
+ return -EINVAL;
if (priv->channel_map[usid][pid] & SPMI_CHANNEL_READ_ONLY)
return -EPERM;
@@ -183,6 +189,8 @@ static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off)
return -EIO;
if (pid >= SPMI_MAX_PERIPH)
return -EIO;
+ if (!(priv->channel_map[usid][pid] & SPMI_CHANNEL_VALID))
+ return -EINVAL;
channel = priv->channel_map[usid][pid] & SPMI_CHANNEL_MASK;
@@ -246,6 +254,32 @@ static struct dm_spmi_ops msm_spmi_ops = {
.write = msm_spmi_write,
};
+/*
+ * In order to allow multiple EEs to write to a single PPID in arbiter
+ * version 5 and 7, there is more than one APID mapped to each PPID.
+ * The owner field for each of these mappings specifies the EE which is
+ * allowed to write to the APID.
+ */
+static void msm_spmi_channel_map_v5(struct msm_spmi_priv *priv, unsigned int i,
+ uint8_t slave_id, uint8_t pid)
+{
+ /* Mark channels read-only when from different owner */
+ uint32_t cnfg = readl(priv->spmi_cnfg + ARB_CHANNEL_OFFSET(i));
+ uint8_t owner = SPMI_OWNERSHIP_PERIPH2OWNER(cnfg);
+ bool prev_valid = priv->channel_map[slave_id][pid] & SPMI_CHANNEL_VALID;
+ uint32_t prev_read_only = priv->channel_map[slave_id][pid] & SPMI_CHANNEL_READ_ONLY;
+
+ if (!prev_valid) {
+ /* First PPID mapping */
+ priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID;
+ if (owner != priv->owner)
+ priv->channel_map[slave_id][pid] |= SPMI_CHANNEL_READ_ONLY;
+ } else if ((owner == priv->owner) && prev_read_only) {
+ /* Read only and we found one we own, switch */
+ priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID;
+ }
+}
+
static int msm_spmi_probe(struct udevice *dev)
{
struct msm_spmi_priv *priv = dev_get_priv(dev);
@@ -271,13 +305,17 @@ static int msm_spmi_probe(struct udevice *dev)
} else if (hw_ver < PMIC_ARB_VERSION_V7_MIN) {
priv->arb_ver = V5;
priv->arb_chnl = core_addr + APID_MAP_OFFSET_V5;
- priv->max_channels = SPMI_MAX_CHANNELS_V5;
+ priv->max_channels = min_t(u32, readl(core_addr + PMIC_ARB_FEATURES) &
+ PMIC_ARB_FEATURES_PERIPH_MASK,
+ SPMI_MAX_CHANNELS_V5);
priv->spmi_cnfg = dev_read_addr_name(dev, "cnfg");
} else {
/* TOFIX: handle second bus */
priv->arb_ver = V7;
priv->arb_chnl = core_addr + APID_MAP_OFFSET_V7;
- priv->max_channels = SPMI_MAX_CHANNELS_V7;
+ priv->max_channels = min_t(u32, readl(core_addr + PMIC_ARB_FEATURES) &
+ PMIC_ARB_FEATURES_PERIPH_MASK,
+ SPMI_MAX_CHANNELS_V7);
priv->spmi_cnfg = dev_read_addr_name(dev, "cnfg");
}
@@ -297,15 +335,16 @@ static int msm_spmi_probe(struct udevice *dev)
uint8_t slave_id = (periph & 0xf0000) >> 16;
uint8_t pid = (periph & 0xff00) >> 8;
- priv->channel_map[slave_id][pid] = i;
-
- /* Mark channels read-only when from different owner */
- if (priv->arb_ver == V5 || priv->arb_ver == V7) {
- uint32_t cnfg = readl(priv->spmi_cnfg + ARB_CHANNEL_OFFSET(i));
- uint8_t owner = SPMI_OWNERSHIP_PERIPH2OWNER(cnfg);
+ switch (priv->arb_ver) {
+ case V2:
+ case V3:
+ priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID;
+ break;
- if (owner != priv->owner)
- priv->channel_map[slave_id][pid] |= SPMI_CHANNEL_READ_ONLY;
+ case V5:
+ case V7:
+ msm_spmi_channel_map_v5(priv, i, slave_id, pid);
+ break;
}
}
return 0;
diff --git a/include/configs/dragonboard410c.h b/include/configs/dragonboard410c.h
index 00102cd5c4f..c31c6c57c1a 100644
--- a/include/configs/dragonboard410c.h
+++ b/include/configs/dragonboard410c.h
@@ -18,15 +18,4 @@
#define PHYS_SDRAM_1_SIZE SZ_1G
#define CFG_SYS_SDRAM_BASE PHYS_SDRAM_1
-/* Environment */
-#define BOOT_TARGET_DEVICES(func) \
- func(USB, usb, 0) \
- func(MMC, mmc, 1) \
- func(MMC, mmc, 0) \
- func(DHCP, dhcp, na)
-
-#include <config_distro_bootcmd.h>
-
-#define CFG_EXTRA_ENV_SETTINGS BOOTENV
-
#endif