diff options
37 files changed, 1629 insertions, 99 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9a22c7f6cea..8795eac0dc7 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1125,6 +1125,7 @@ config ARCH_SNAPDRAGON select LINUX_KERNEL_IMAGE_HEADER if !ENABLE_ARM_SOC_BOOT0_HOOK select SYSRESET select SYSRESET_PSCI + select ANDROID_BOOT_IMAGE_IGNORE_BLOB_ADDR imply OF_UPSTREAM imply CMD_DM imply DM_USB_GADGET diff --git a/arch/arm/dts/ipq5424-rdp466-u-boot.dtsi b/arch/arm/dts/ipq5424-rdp466-u-boot.dtsi new file mode 100644 index 00000000000..9e4af4d9f72 --- /dev/null +++ b/arch/arm/dts/ipq5424-rdp466-u-boot.dtsi @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IPQ5424 RDP466 board device tree source + * + * Copyright (c) 2025 The Linux Foundation. All rights reserved. + */ + +/ { + /* Will be removed when SMEM parsing is updated */ + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x20000000>; + }; + +}; + + &sdhc { + sdhci-caps-mask = <0x0 0x04000000>; + sdhci-caps = <0x0 0x04000000>; /* SDHCI_CAN_VDD_180 */ + mmc-ddr-1_8v; + mmc-hs200-1_8v; + max-frequency = <192000000>; + bus-width = <4>; + pinctrl-0 = <&sdc_default_state>; + pinctrl-names = "default"; + non-removable; + + /* + * This reset is needed to clear out the settings done by + * previous boot loader. Without this the SDHCI_RESET_ALL + * reset done sdhci_init() times out. + */ + resets = <&gcc GCC_SDCC_BCR>; + + status = "okay"; + }; + diff --git a/arch/arm/dts/qcs615-ride-u-boot.dtsi b/arch/arm/dts/qcs615-ride-u-boot.dtsi new file mode 100644 index 00000000000..68fffc70fcb --- /dev/null +++ b/arch/arm/dts/qcs615-ride-u-boot.dtsi @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/ { + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x7a00000>, + <0x0 0x89600000 0x0 0x30100000>, + <0x0 0xc0000000 0x0 0xc0000000>, + <0x1 0x80000000 0x1 0x00000000>; + }; +}; diff --git a/arch/arm/dts/qcs8300-ride-u-boot.dtsi b/arch/arm/dts/qcs8300-ride-u-boot.dtsi new file mode 100644 index 00000000000..8c353ace71e --- /dev/null +++ b/arch/arm/dts/qcs8300-ride-u-boot.dtsi @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/ { + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x11a80000>, + <0x0 0xc0000000 0x0 0x10000000>, + <0x0 0xd3100000 0x0 0x26b00000>, + <0xe 0x80000000 0x1 0x00000000>, + <0xa 0x80000000 0x1 0x80000000>, + <0x0 0xb0800000 0x0 0x0f200000>, + <0x0 0xd0100000 0x0 0x01800000>, + <0x0 0x91b00000 0x0 0x1e500000>; + }; +}; + diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c index 5547d6d054f..8f7fc19cadc 100644 --- a/arch/arm/mach-snapdragon/board.c +++ b/arch/arm/mach-snapdragon/board.c @@ -37,6 +37,8 @@ DECLARE_GLOBAL_DATA_PTR; +enum qcom_boot_source qcom_boot_source __section(".data") = 0; + static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } }; struct mm_region *mem_map = rbx_mem_map; @@ -238,6 +240,12 @@ int board_fdt_blob_setup(void **fdtp) if (ret < 0) panic("No valid memory ranges found!\n"); + /* If we have an external FDT, it can only have come from the Android bootloader. */ + if (external_valid) + qcom_boot_source = QCOM_BOOT_SOURCE_ANDROID; + else + qcom_boot_source = QCOM_BOOT_SOURCE_XBL; + debug("ram_base = %#011lx, ram_size = %#011llx\n", gd->ram_base, gd->ram_size); @@ -481,6 +489,23 @@ static void configure_env(void) qcom_set_serialno(); } +void qcom_show_boot_source(void) +{ + const char *name = "UNKNOWN"; + + switch (qcom_boot_source) { + case QCOM_BOOT_SOURCE_ANDROID: + name = "ABL"; + break; + case QCOM_BOOT_SOURCE_XBL: + name = "XBL"; + break; + } + + log_info("U-Boot loaded from %s\n", name); + env_set("boot_source", name); +} + void __weak qcom_late_init(void) { } @@ -508,8 +533,12 @@ int board_late_init(void) status |= env_set_hex("ramdisk_addr_r", addr_alloc(SZ_128M)); status |= env_set_hex("kernel_comp_addr_r", addr_alloc(KERNEL_COMP_SIZE)); status |= env_set_hex("kernel_comp_size", KERNEL_COMP_SIZE); - if (IS_ENABLED(CONFIG_FASTBOOT)) - status |= env_set_hex("fastboot_addr_r", addr_alloc(FASTBOOT_BUF_SIZE)); + if (IS_ENABLED(CONFIG_FASTBOOT)) { + addr = addr_alloc(FASTBOOT_BUF_SIZE); + status |= env_set_hex("fastboot_addr_r", addr); + /* override loadaddr for memory rich soc */ + status |= env_set_hex("loadaddr", addr); + } status |= env_set_hex("scriptaddr", addr_alloc(SZ_4M)); status |= env_set_hex("pxefile_addr_r", addr_alloc(SZ_4M)); addr = addr_alloc(SZ_2M); @@ -524,6 +553,7 @@ int board_late_init(void) configure_env(); qcom_late_init(); + qcom_show_boot_source(); /* Configure the dfu_string for capsule updates */ qcom_configure_capsule_updates(); diff --git a/arch/arm/mach-snapdragon/capsule_update.c b/arch/arm/mach-snapdragon/capsule_update.c index bf75a9a1b24..4dced4961b6 100644 --- a/arch/arm/mach-snapdragon/capsule_update.c +++ b/arch/arm/mach-snapdragon/capsule_update.c @@ -20,22 +20,19 @@ #include "qcom-priv.h" /* - * NOTE: for now this implementation only supports the rb3gen2. Supporting other - * boards that boot in different ways (e.g. chainloaded from ABL) will require - * additional complexity to properly create the dfu string and fw_images array. - */ - -/* - * To handle different variants like chainloaded U-Boot here we'll need to - * build the fw_images array dynamically at runtime. It looks like - * mach-rockchip is a good example for how to do this. - * Detecting which image types a board uses is TBD, hence for now we only - * support the one new board that runs U-Boot as its primary bootloader. + * To handle different variants like chainloaded U-Boot here we need to + * build the fw_images array dynamically at runtime. These are the possible + * implementations: + * + * - Devices with U-Boot on the uefi_a/b partition + * - Devices with U-Boot on the boot (a/b) partition + * - Devices with U-Boot on the xbl (a/b) partition + * + * Which partition actually has U-Boot on it is determined based on the + * qcom_boot_source variable and additional logic in find_target_partition(). */ struct efi_fw_image fw_images[] = { { - /* U-Boot flashed to the uefi_X partition (e.g. rb3gen2) */ - .fw_name = u"UBOOT_UEFI_PARTITION", .image_index = 1, }, }; @@ -47,6 +44,12 @@ struct efi_capsule_update_info update_info = { .images = fw_images, }; +enum target_part_type { + TARGET_PART_UEFI = 1, + TARGET_PART_XBL, + TARGET_PART_BOOT, +}; + /* LSB first */ struct part_slot_status { u16: 2; @@ -57,35 +60,202 @@ struct part_slot_status { u16 tries_remaining : 4; }; -static int find_boot_partition(const char *partname, struct blk_desc *blk_dev, char *name) +enum ab_slot { + SLOT_NONE, + SLOT_A, + SLOT_B, +}; + +static enum ab_slot get_part_slot(const char *partname) +{ + int len = strlen(partname); + + if (partname[len - 2] != '_') + return SLOT_NONE; + if (partname[len - 1] == 'a') + return SLOT_A; + if (partname[len - 1] == 'b') + return SLOT_B; + + return SLOT_NONE; +} + +/* + * Determine which partition U-Boot is flashed to based on the boot source (ABL/XBL), + * the slot status, and prioritizing the uefi partition over xbl if found. + */ +static int find_target_partition(int *devnum, enum uclass_id *uclass, + enum target_part_type *target_part_type) { int ret; - int partnum; + int partnum, uefi_partnum = -1, xbl_partnum = -1; struct disk_partition info; struct part_slot_status *slot_status; + struct udevice *dev = NULL; + struct blk_desc *desc = NULL, *xbl_desc = NULL; + uchar ptn_name[32] = { 0 }; + bool have_ufs = false; + + /* + * Check to see if we have UFS storage, if so U-Boot MUST be on it and we can skip + * all non-UFS block devices + */ + uclass_foreach_dev_probe(UCLASS_UFS, dev) { + have_ufs = true; + break; + } - for (partnum = 1;; partnum++) { - ret = part_get_info(blk_dev, partnum, &info); - if (ret) - return ret; + uclass_foreach_dev_probe(UCLASS_BLK, dev) { + if (device_get_uclass_id(dev) != UCLASS_BLK) + continue; - slot_status = (struct part_slot_status *)&info.type_flags; - log_io("%16s: Active: %1d, Successful: %1d, Unbootable: %1d, Tries left: %1d\n", - info.name, slot_status->active, - slot_status->successful, slot_status->unbootable, - slot_status->tries_remaining); + /* If we have a UFS then don't look at any other block devices */ + if (have_ufs) { + if (device_get_uclass_id(dev->parent->parent) != UCLASS_UFS) + continue; /* - * FIXME: eventually we'll want to find the active/inactive variant of the partition - * but on the rb3gen2 these values might all be 0 + * If we don't have UFS, then U-Boot must be on the eMMC which is always the first + * MMC device. */ - if (!strncmp(info.name, partname, strlen(partname))) { - log_debug("Found active %s partition: '%s'!\n", partname, info.name); - strlcpy(name, info.name, sizeof(info.name)); - return partnum; + } else if (dev->parent->seq_ > 0) { + continue; } + + desc = dev_get_uclass_plat(dev); + if (!desc || desc->part_type == PART_TYPE_UNKNOWN) + continue; + for (partnum = 1;; partnum++) { + ret = part_get_info(desc, partnum, &info); + if (ret) + break; + + slot_status = (struct part_slot_status *)&info.type_flags; + + /* + * Qualcomm Linux devices have a "uefi" partition, it's A/B but the + * flags might not be set so we assume the A partition unless the B + * partition is active. + */ + if (!strncmp(info.name, "uefi", strlen("uefi"))) { + /* + * If U-Boot was chainloaded somehow we can't be flashed to + * the uefi partition + */ + if (qcom_boot_source != QCOM_BOOT_SOURCE_XBL) + continue; + + *target_part_type = TARGET_PART_UEFI; + /* + * Found an active UEFI partition, this is where U-Boot is + * flashed. + */ + if (slot_status->active) + goto found; + + /* Prefer A slot if it's not marked active */ + if (get_part_slot(info.name) == SLOT_A) { + /* + * If we found the A slot after the B slot (both + * inactive) then we assume U-Boot is on the A slot. + */ + if (uefi_partnum >= 0) + goto found; + + /* Didn't find the B slot yet */ + uefi_partnum = partnum; + strlcpy(ptn_name, info.name, 32); + } else { + /* + * Found inactive B slot after inactive A slot, return + * the A slot + */ + if (uefi_partnum >= 0) { + partnum = uefi_partnum; + goto found; + } + + /* + * Didn't find the A slot yet. Record that we found the + * B slot + */ + uefi_partnum = partnum; + strlcpy(ptn_name, info.name, 32); + } + /* xbl and aboot are effectively the same */ + } else if ((!strncmp(info.name, "xbl", strlen("xbl")) && + strlen(info.name) == 5) || + !strncmp(info.name, "aboot", strlen("aboot"))) { + /* + * If U-Boot was booted via ABL, we can't be flashed to the + * XBL partition + */ + if (qcom_boot_source != QCOM_BOOT_SOURCE_XBL) + continue; + + /* + * ignore xbl partition if we have uefi partitions, U-Boot will + * always be on the UEFI partition in this case. + */ + if (*target_part_type == TARGET_PART_UEFI) + continue; + + /* Either non-A/B or find the active XBL partition */ + if (slot_status->active || !get_part_slot(info.name)) { + /* + * No quick return since we might find a uefi partition + * later + */ + xbl_partnum = partnum; + *target_part_type = TARGET_PART_XBL; + xbl_desc = desc; + strlcpy(ptn_name, info.name, 32); + } + + /* + * No fast return since we might also have a uefi partition which + * will take priority. + */ + } else if (!strncmp(info.name, "boot", strlen("boot"))) { + /* We can only be flashed to boot if we were chainloaded */ + if (qcom_boot_source != QCOM_BOOT_SOURCE_ANDROID) + continue; + + /* + * Either non-A/B or find the active partition. We can return + * immediately here since we've narrowed it down to a single option + */ + if (slot_status->active || !get_part_slot(info.name)) { + *target_part_type = TARGET_PART_BOOT; + goto found; + } + } + } + } + + /* + * Now we've exhausted all options, if we didn't find a uefi partition + * then we are indeed flashed to the xbl partition. + */ + if (*target_part_type == TARGET_PART_XBL) { + partnum = xbl_partnum; + desc = xbl_desc; + goto found; } + /* Found no candidate partitions */ return -1; + +found: + if (desc) { + *devnum = desc->devnum; + *uclass = desc->uclass_id; + } + + /* info won't match for XBL hence the copy. */ + log_info("Capsule update target: %s (disk %d:%d)\n", + *target_part_type == TARGET_PART_BOOT ? info.name : ptn_name, + *devnum, partnum); + return partnum; } /** @@ -101,12 +271,10 @@ static int find_boot_partition(const char *partname, struct blk_desc *blk_dev, c */ void qcom_configure_capsule_updates(void) { - struct blk_desc *desc; int ret = 0, partnum = -1, devnum; static char dfu_string[32] = { 0 }; - char name[32]; /* GPT partition name */ - char *partname = "uefi_a"; - struct udevice *dev = NULL; + enum target_part_type target_part_type = 0; + enum uclass_id dev_uclass; if (IS_ENABLED(CONFIG_SCSI)) { /* Scan for SCSI devices */ @@ -117,26 +285,30 @@ void qcom_configure_capsule_updates(void) } } - uclass_foreach_dev_probe(UCLASS_BLK, dev) { - if (device_get_uclass_id(dev) != UCLASS_BLK) - continue; - - desc = dev_get_uclass_plat(dev); - if (!desc || desc->part_type == PART_TYPE_UNKNOWN) - continue; - devnum = desc->devnum; - partnum = find_boot_partition(partname, desc, - name); - if (partnum >= 0) - break; - } - + partnum = find_target_partition(&devnum, &dev_uclass, &target_part_type); if (partnum < 0) { log_err("Failed to find boot partition\n"); return; } - switch (desc->uclass_id) { + /* + * Set the fw_name based on the partition type. This causes the GUID to be different + * so we will never accidentally flash a U-Boot image intended for XBL to the boot + * partition. + */ + switch (target_part_type) { + case TARGET_PART_UEFI: + fw_images[0].fw_name = u"UBOOT_UEFI_PARTITION"; + break; + case TARGET_PART_XBL: + fw_images[0].fw_name = u"UBOOT_XBL_PARTITION"; + break; + case TARGET_PART_BOOT: + fw_images[0].fw_name = u"UBOOT_BOOT_PARTITION"; + break; + } + + switch (dev_uclass) { case UCLASS_SCSI: snprintf(dfu_string, 32, "scsi %d=u-boot.bin part %d", devnum, partnum); break; @@ -144,10 +316,10 @@ void qcom_configure_capsule_updates(void) snprintf(dfu_string, 32, "mmc 0=u-boot.bin part %d %d", devnum, partnum); break; default: - debug("Unsupported storage uclass: %d\n", desc->uclass_id); + debug("Unsupported storage uclass: %d\n", dev_uclass); return; } - log_debug("boot partition is %s, DFU string: '%s'\n", name, dfu_string); + log_debug("DFU string: '%s'\n", dfu_string); update_info.dfu_string = dfu_string; } diff --git a/arch/arm/mach-snapdragon/of_fixup.c b/arch/arm/mach-snapdragon/of_fixup.c index b398c6b7b9f..328c7812f30 100644 --- a/arch/arm/mach-snapdragon/of_fixup.c +++ b/arch/arm/mach-snapdragon/of_fixup.c @@ -99,19 +99,6 @@ static int fixup_qcom_dwc3(struct device_node *root, struct device_node *glue_np return ret; } - /* - * The RB1/2 boards only have a single USB controller and it's muxed between the type-C port - * and a USB hub. Since we can't do OTG in U-Boot properly we prefer to put it into host mode. - */ - if (of_device_is_compatible(root, "qcom,qrb4210-rb2", NULL, NULL) || - of_device_is_compatible(root, "qcom,qrb2210-rb1", NULL, NULL)) { - ret = of_write_prop(dwc3, "dr_mode", sizeof("host"), "host"); - if (ret) { - log_err("Failed to set 'dr_mode' property: %d\n", ret); - return ret; - } - } - return 0; } diff --git a/arch/arm/mach-snapdragon/qcom-priv.h b/arch/arm/mach-snapdragon/qcom-priv.h index 4f398e2ba37..b8bf574e8bb 100644 --- a/arch/arm/mach-snapdragon/qcom-priv.h +++ b/arch/arm/mach-snapdragon/qcom-priv.h @@ -3,6 +3,20 @@ #ifndef __QCOM_PRIV_H__ #define __QCOM_PRIV_H__ +/** + * enum qcom_boot_source - Track where we got loaded from. + * Used for capsule update logic. + * + * @QCOM_BOOT_SOURCE_ANDROID: chainloaded (typically from ABL) + * @QCOM_BOOT_SOURCE_XBL: flashed to the XBL or UEFI partition + */ +enum qcom_boot_source { + QCOM_BOOT_SOURCE_ANDROID = 1, + QCOM_BOOT_SOURCE_XBL, +}; + +extern enum qcom_boot_source qcom_boot_source; + #if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) void qcom_configure_capsule_updates(void); #else diff --git a/board/qualcomm/MAINTAINERS b/board/qualcomm/MAINTAINERS new file mode 100644 index 00000000000..3767a2a7949 --- /dev/null +++ b/board/qualcomm/MAINTAINERS @@ -0,0 +1,24 @@ +# This MAINTAINERS file is for folks with an interest in a particular platform +# or board under ARM SNAPDRAGON + +QUALCOMM DRAGONWING QCS615 +M: Aswin Murugan <aswin.murugan@oss.qualcomm.com> +S: Maintained +N: qcs615 + +# RB3 Gen 2 and similar boards +QUALCOMM DRAGONWING QCS6490 +M: Casey Connolly <casey.connolly@linaro.org> +S: Maintained +N: qcs6490 +N: sc7280 + +QUALCOMM DRAGONWING QCS8300 +M: Balaji Selvanathan <balaji.selvanathan@oss.qualcomm.com> +S: Maintained +N: qcs8300 + +QUALCOMM DRAGONWING QCS9100 +M: Varadarajan Narayanan <quic_varada@quicinc.com> +S: Maintained +N: qcs9100 diff --git a/boot/Kconfig b/boot/Kconfig index 1f5ecb60c77..a671d78e570 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -11,6 +11,17 @@ config ANDROID_BOOT_IMAGE This enables support for booting images which use the Android image format header. +config ANDROID_BOOT_IMAGE_IGNORE_BLOB_ADDR + bool "Android Boot Image ignore addr" + default n + help + This ignore kernel/ramdisk load addr specified in androidboot header. + + There is a concern on exposing the whole memory to image loading is + dangerous. Also, since it's not always possible to change the load + addr by repacking the boot.img (mainly due to AVB signature mismatch), + we need a way to use kernel_addr_r and ramdisk_addr_r. + config TIMESTAMP bool "Show image date and time when displaying image information" default y if CMD_DATE diff --git a/boot/image-android.c b/boot/image-android.c index 459cdb8456c..14cf611cee5 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -268,7 +268,8 @@ static ulong android_image_get_kernel_addr(struct andr_image_data *img_data, * * Otherwise, we will return the actual value set by the user. */ - if (img_data->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR) { + if (img_data->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR || + IS_ENABLED(CONFIG_ANDROID_BOOT_IMAGE_IGNORE_BLOB_ADDR)) { if (comp == IH_COMP_NONE) return img_data->kernel_ptr; return env_get_ulong("kernel_addr_r", 16, 0); @@ -464,7 +465,8 @@ int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img, */ if (img_data.header_version > 2) { /* Ramdisk can't be used in-place, copy it to ramdisk_addr_r */ - if (img_data.ramdisk_addr == ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR) { + if (img_data.ramdisk_addr == ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR || + IS_ENABLED(CONFIG_ANDROID_BOOT_IMAGE_IGNORE_BLOB_ADDR)) { ramdisk_ptr = env_get_ulong("ramdisk_addr_r", 16, 0); if (!ramdisk_ptr) { printf("Invalid ramdisk_addr_r to copy ramdisk into\n"); @@ -489,7 +491,8 @@ int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img, /* Ramdisk can be used in-place, use current ptr */ if (img_data.ramdisk_addr == 0 || img_data.ramdisk_addr == ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR || - img_data.ramdisk_addr == img_data.kernel_addr) { + img_data.ramdisk_addr == img_data.kernel_addr || + IS_ENABLED(CONFIG_ANDROID_BOOT_IMAGE_IGNORE_BLOB_ADDR)) { *rd_data = img_data.ramdisk_ptr; } else { ramdisk_ptr = img_data.ramdisk_addr; diff --git a/configs/qcm6490_defconfig b/configs/qcm6490_defconfig index ba26924da16..5ddc5ab3ef8 100644 --- a/configs/qcm6490_defconfig +++ b/configs/qcm6490_defconfig @@ -19,9 +19,3 @@ CONFIG_TEXT_BASE=0x9fc00000 CONFIG_REMAKE_ELF=y CONFIG_DEFAULT_DEVICE_TREE="qcom/qcs6490-rb3gen2" - -# Enable capsule updates -CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y -CONFIG_EFI_CAPSULE_ON_DISK=y -CONFIG_EFI_IGNORE_OSINDICATIONS=y -CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig index 5eb027ba27b..87466d23d14 100644 --- a/configs/qcom_defconfig +++ b/configs/qcom_defconfig @@ -6,6 +6,9 @@ CONFIG_ARCH_SNAPDRAGON=y CONFIG_NR_DRAM_BANKS=24 CONFIG_DEFAULT_DEVICE_TREE="qcom/sdm845-db845c" CONFIG_SYS_LOAD_ADDR=0xA0000000 +CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y +CONFIG_EFI_CAPSULE_ON_DISK=y +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y CONFIG_BUTTON_CMD=y CONFIG_FIT=y CONFIG_FIT_VERBOSE=y @@ -51,6 +54,8 @@ CONFIG_CLK_QCOM_APQ8016=y CONFIG_CLK_QCOM_APQ8096=y CONFIG_CLK_QCOM_QCM2290=y CONFIG_CLK_QCOM_QCS404=y +CONFIG_CLK_QCOM_QCS615=y +CONFIG_CLK_QCOM_QCS8300=y CONFIG_CLK_QCOM_SA8775P=y CONFIG_CLK_QCOM_SDM845=y CONFIG_CLK_QCOM_SM6115=y @@ -143,3 +148,5 @@ CONFIG_VIDEO_FONT_16X32=y CONFIG_SYS_WHITE_ON_BLACK=y CONFIG_NO_FB_CLEAR=y CONFIG_VIDEO_SIMPLE=y +CONFIG_WDT_QCOM=y +CONFIG_WDT=y diff --git a/configs/qcom_ipq5424_mmc_defconfig b/configs/qcom_ipq5424_mmc_defconfig new file mode 100644 index 00000000000..0dd46680b0f --- /dev/null +++ b/configs/qcom_ipq5424_mmc_defconfig @@ -0,0 +1,83 @@ +CONFIG_ARM=y +CONFIG_SKIP_LOWLEVEL_INIT=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_SYS_INIT_SP_BSS_OFFSET=1572864 +CONFIG_ARCH_SNAPDRAGON=y +CONFIG_NR_DRAM_BANKS=24 +CONFIG_DEFAULT_DEVICE_TREE="qcom/ipq5424-rdp466" +CONFIG_SYS_LOAD_ADDR=0x50000000 +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +# CONFIG_EFI_LOADER is not set +# CONFIG_EFI_BINARY_EXEC is not set +# CONFIG_EFI_VARIABLE_FILE_STORE is not set +# CONFIG_PXE_UTILS is not set +# CONFIG_BOOTSTD is not set +# CONFIG_BOOTMETH_VBE is not set +CONFIG_BOOTDELAY=2 +CONFIG_OF_BOARD_SETUP=y +CONFIG_USE_PREBOOT=y +CONFIG_LOG_MAX_LEVEL=9 +CONFIG_LOG_DEFAULT_LEVEL=4 +# CONFIG_DISPLAY_CPUINFO is not set +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_CMD_MMC=y +CONFIG_CMD_USB=y +CONFIG_CMD_PART=y +CONFIG_OF_LIVE=y +CONFIG_USE_DEFAULT_ENV_FILE=y +CONFIG_DEFAULT_ENV_FILE="board/qualcomm/default.env" +CONFIG_CLK=y +CONFIG_CLK_QCOM_IPQ5424=y +CONFIG_DFU_MMC=y +CONFIG_DFU_SCSI=y +CONFIG_SYS_DFU_DATA_BUF_SIZE=0x200000 +CONFIG_MSM_GPIO=y +CONFIG_PINCTRL=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_QCOM_IPQ5424=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_ADMA=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_HS200_SUPPORT=y +CONFIG_DM_MDIO=y +CONFIG_DM_ETH_PHY=y +CONFIG_DWC_ETH_QOS=y +CONFIG_DWC_ETH_QOS_QCOM=y +CONFIG_RGMII=y +CONFIG_PHY=y +CONFIG_PHY_QCOM_QMP_UFS=y +CONFIG_PHY_QCOM_QUSB2=y +CONFIG_SCSI=y +CONFIG_MSM_SERIAL=y +CONFIG_MSM_GENI_SERIAL=y +CONFIG_SOC_QCOM=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_DEBUG_UART_BASE=0x1a84000 +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_CLOCK=14745600 +CONFIG_TEXT_BASE=0x8a380000 +CONFIG_REMAKE_ELF=y +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_BOOTSTD_FULL=y +CONFIG_SYS_CBSIZE=1024 +CONFIG_SYS_PBSIZE=1024 +CONFIG_OF_LIVE=y +CONFIG_MSM_SERIAL=y +CONFIG_DM_EVENT=y +CONFIG_ENV_IS_IN_MMC=y +CONFIG_ENV_SIZE=0x40000 +CONFIG_ENV_OFFSET=0 +CONFIG_PARTITIONS=y +CONFIG_PARTITION_UUIDS=y +CONFIG_MTD=y +CONFIG_MTD_PARTS=y +CONFIG_HUSH_PARSER=y +CONFIG_PARTITIONS=y +CONFIG_EFI_PARTITION=y +# CONFIG_I2C is not set +# CONFIG_INPUT is not set +# CONFIG_SCSI is not set +# CONFIG_SPMI is not set diff --git a/configs/qcom_qcs615_defconfig b/configs/qcom_qcs615_defconfig new file mode 100644 index 00000000000..2468267b955 --- /dev/null +++ b/configs/qcom_qcs615_defconfig @@ -0,0 +1,22 @@ +# Configuration for building U-Boot to be flashed +# to the uefi partition of QCS615 dev boards with +# the "Linux Embedded" partition layout (which have +# a dedicated "uefi" partition for edk2/U-Boot) + +#include "qcom_defconfig" + +# Otherwise buildman thinks this isn't an ARM platform +CONFIG_ARM=y + +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_DEBUG_UART_BASE=0x880000 +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_CLOCK=14745600 + +CONFIG_DEFAULT_DEVICE_TREE="qcom/qcs615-ride" + +CONFIG_REMAKE_ELF=y + +# Address where U-Boot will be loaded +CONFIG_TEXT_BASE=0x9fc00000 diff --git a/configs/qcom_qcs8300_defconfig b/configs/qcom_qcs8300_defconfig new file mode 100644 index 00000000000..5fffcddc16e --- /dev/null +++ b/configs/qcom_qcs8300_defconfig @@ -0,0 +1,21 @@ +# Configuration for building U-Boot to be flashed +# to the uefi partition of QCS8300 dev boards with +# the "Linux Embedded" partition layout (which have +# a dedicated "uefi_a" partition for edk2/U-Boot) + +#include "qcom_defconfig" + +# Otherwise buildman thinks this isn't an ARM platform +CONFIG_ARM=y + +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_DEBUG_UART_BASE=0x99C000 +CONFIG_DEBUG_UART_MSM_GENI=y +CONFIG_DEBUG_UART_CLOCK=14745600 + +# Address where U-Boot will be loaded +CONFIG_TEXT_BASE=0xaf000000 +CONFIG_REMAKE_ELF=y + +CONFIG_DEFAULT_DEVICE_TREE="qcom/qcs8300-ride" diff --git a/doc/board/qualcomm/board.rst b/doc/board/qualcomm/board.rst index 003d59a18eb..642c5095261 100644 --- a/doc/board/qualcomm/board.rst +++ b/doc/board/qualcomm/board.rst @@ -23,10 +23,7 @@ Installation ------------ Build ^^^^^ - - $ ./tools/buildman/buildman -o .output qcom - -This will build ``.output/u-boot-nodtb.bin`` using the ``qcom_defconfig``. +We will build ``u-boot-nodtb.bin`` from the u-boot source tree. Generate FIT image (optional) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,19 +78,20 @@ Steps: - Build u-boot -As above:: +Use the following commands:: - ./tools/buildman/buildman -o .output qcom + make CROSS_COMPILE=aarch64-linux-gnu- O=.output qcom_defconfig + make CROSS_COMPILE=aarch64-linux-gnu- O=.output -j$(nproc) 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) + make CROSS_COMPILE=aarch64-linux-gnu- 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) + make CROSS_COMPILE=aarch64-linux-gnu- O=.output -j$(nproc) - gzip u-boot:: @@ -119,6 +117,13 @@ Or with no FIT image:: mkbootimg --kernel u-boot-nodtb.bin.gz-dtb \ --output boot.img --pagesize 4096 --base 0x80000000 +Other devices with boot image version 2 can be built like this example:: + + mkbootimg --pagesize 4096 --header_version 2 \ + --kernel_offset 0x00008000 --kernel u-boot-nodtb.bin.gz \ + --dtb_offset 0x01f00000 --dtb dts/upstream/src/arm64/qcom/qcm6490-fairphone-fp5.dtb \ + --output boot.img + - Flash boot.img using fastboot and erase dtbo to avoid conflicts with our DTB: .. code-block:: bash diff --git a/doc/board/qualcomm/dragonwing.rst b/doc/board/qualcomm/dragonwing.rst new file mode 100644 index 00000000000..d4899415309 --- /dev/null +++ b/doc/board/qualcomm/dragonwing.rst @@ -0,0 +1,49 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. sectionauthor:: Balaji Selvanathan <balaji.selvanathan@oss.qualcomm.com> + +Qualcomm DragonWing +======================================== + +Qualcomm DragonWing are industrial-grade boards that provides various series +of processors such as IQ6 (QCS615), IQ8 (QCS8300) and IQ9 (QCS9100). +These SoCs are used for factory/industry based applications. +More information can be found on the `Qualcomm's IQ6 product page`_, +`Qualcomm's IQ8 product page`_ and `Qualcomm's IQ9 product page`_. + +.. _Qualcomm's IQ6 product page: https://docs.qualcomm.com/bundle/publicresource/87-83838-1_REV_A_Qualcomm_IQ6_Series_Product_Brief.pdf +.. _Qualcomm's IQ8 product page: https://docs.qualcomm.com/bundle/publicresource/87-83839-1_REV_A_Qualcomm_IQ8_Series_Product_Brief________.pdf +.. _Qualcomm's IQ9 product page: https://docs.qualcomm.com/bundle/publicresource/87-83840-1_REV_A_Qualcomm_IQ9_Series_Product_Brief.pdf + +Installation +------------ +First, setup ``CROSS_COMPILE`` for aarch64. Then, build U-Boot for ``QCS615``, ``QCS8300`` or ``QCS9100``:: + + $ export CROSS_COMPILE=<aarch64 toolchain prefix> + $ make qcom_qcs8300_defconfig + $ make -j8 u-boot.mbn + +Although the board does not have secure boot set up by default, +the firmware still expects firmware ELF images to be "signed". The signature +does not provide any security in this case, but it provides the firmware with +some required metadata. + +To "sign" ``u-boot.elf`` you can use e.g. `qtestsign`_:: + + $ qtestsign -v6 aboot -o u-boot.mbn u-boot.elf + +Then flash the resulting ``u-boot.mbn`` to the ``uefi_a`` partition +on your device with ``fastboot flash uefi_a u-boot.mbn``. + +U-Boot should be running after a reboot (``fastboot reboot``). + +Note that fastboot is not yet supported in U-Boot on Dragonwing boards, as a result, to flash +back the original firmware, or new versoins of the U-Boot, EDL mode must be used. + +A tool like bkerler's `edl`_ can be used for flashing with the firehose loader (for example, for QCS9100 +the firehose loader can be obtained from `dragonwing IQ9 bootbinaries`.) :: + +$ edl.py --loader /path/to/prog_firehose_ddr.elf w uefi_a u-boot.mbn + +.. _qtestsign: https://github.com/msm8916-mainline/qtestsign +.. _edl: https://github.com/bkerler/edl +.. _dragonwing IQ9 bootbinaries: https://artifacts.codelinaro.org/ui/native/qli-ci/flashable-binaries/qimpsdk/qcs9075-rb8-core-kit diff --git a/doc/board/qualcomm/index.rst b/doc/board/qualcomm/index.rst index e2fcbfa19c2..ccf834208e9 100644 --- a/doc/board/qualcomm/index.rst +++ b/doc/board/qualcomm/index.rst @@ -8,6 +8,7 @@ Qualcomm dragonboard410c rb3gen2 + dragonwing board phones debugging diff --git a/doc/board/qualcomm/rdp.rst b/doc/board/qualcomm/rdp.rst index fd14f1d9829..99cf8eba57c 100644 --- a/doc/board/qualcomm/rdp.rst +++ b/doc/board/qualcomm/rdp.rst @@ -21,13 +21,16 @@ First, setup ``CROSS_COMPILE`` for aarch64. Then, build U-Boot for ``IPQ9574``:: This will build ``u-boot.elf`` in the configured output directory. -Although the RDPs do not have secure boot set up by default, the firmware still -expects firmware ELF images to be "signed". The signature does not provide any -security in this case, but it provides the firmware with some required metadata. +The firmware expects the ELF images to be in MBN format. The `elftombn.py` tool +can be used to convert the ELF images to MBN format. -To "sign" ``u-boot.elf`` you can use e.g. `qtestsign`_:: + IPQ9574: (MBN version 6) - $ qtestsign -v6 aboot -o u-boot.mbn u-boot.elf + $ python elftombn.py -f u-boot.elf -o u-boot.mbn -v6 + + IPQ5424: (MBN version 7) + + $ python elftombn.py -f u-boot.elf -o u-boot.mbn -v7 Then install the resulting ``u-boot.mbn`` to the ``0:APPSBL`` partition on your device with:: @@ -51,5 +54,5 @@ U-Boot should be running after a reboot (``reset``). Note that the support added is very basic. Restoring the original U-Boot on boards with older version of the software requires a debugger. -.. _qtestsign: https://github.com/msm8916-mainline/qtestsign +.. _elftombn.py: https://git.codelinaro.org/clo/qsdk/oss/system/tools/meta/-/tree/NHSS.QSDK.13.0.5.r2/scripts?ref_type=heads .. _edl: https://github.com/bkerler/edl diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 3ea01f3c969..34e41461e72 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -31,6 +31,14 @@ config CLK_QCOM_IPQ4019 on the Snapdragon IPQ4019 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. +config CLK_QCOM_IPQ5424 + bool "Qualcomm IPQ5424 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Qualcomm IPQ5424 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + config CLK_QCOM_IPQ9574 bool "Qualcomm IPQ9574 GCC" select CLK_QCOM @@ -55,6 +63,22 @@ config CLK_QCOM_QCS404 on the Snapdragon QCS404 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. +config CLK_QCOM_QCS615 + bool "Qualcomm QCS615 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon QCS615 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + +config CLK_QCOM_QCS8300 + bool "Qualcomm QCS8300 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon QCS8300 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + config CLK_QCOM_SA8775P bool "Qualcomm SA8775 GCC" select CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index e13fc8c1071..b3d95b0faa3 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -7,9 +7,12 @@ obj-$(CONFIG_CLK_QCOM_SDM845) += clock-sdm845.o obj-$(CONFIG_CLK_QCOM_APQ8016) += clock-apq8016.o obj-$(CONFIG_CLK_QCOM_APQ8096) += clock-apq8096.o obj-$(CONFIG_CLK_QCOM_IPQ4019) += clock-ipq4019.o +obj-$(CONFIG_CLK_QCOM_IPQ5424) += clock-ipq5424.o obj-$(CONFIG_CLK_QCOM_IPQ9574) += clock-ipq9574.o obj-$(CONFIG_CLK_QCOM_QCM2290) += clock-qcm2290.o obj-$(CONFIG_CLK_QCOM_QCS404) += clock-qcs404.o +obj-$(CONFIG_CLK_QCOM_QCS8300) += clock-qcs8300.o +obj-$(CONFIG_CLK_QCOM_QCS615) += clock-qcs615.o obj-$(CONFIG_CLK_QCOM_SA8775P) += clock-sa8775p.o obj-$(CONFIG_CLK_QCOM_SC7280) += clock-sc7280.o obj-$(CONFIG_CLK_QCOM_SM6115) += clock-sm6115.o diff --git a/drivers/clk/qcom/clock-ipq5424.c b/drivers/clk/qcom/clock-ipq5424.c new file mode 100644 index 00000000000..40823a30ead --- /dev/null +++ b/drivers/clk/qcom/clock-ipq5424.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock drivers for Qualcomm ipq5424 + * + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <linux/bug.h> +#include <linux/bitops.h> +#include <dt-bindings/clock/qcom,ipq5424-gcc.h> +#include <dt-bindings/reset/qcom,ipq5424-gcc.h> + +#include "clock-qcom.h" + +#define GCC_IM_SLEEP_CBCR 0x1834020u + +static ulong ipq5424_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case GCC_QUPV3_UART1_CLK: + clk_rcg_set_rate_mnd(priv->base, priv->data->clks[clk->id].reg, + 0, 144, 15625, CFG_CLK_SRC_GPLL0, 16); + return rate; + case GCC_SDCC1_APPS_CLK: + clk_rcg_set_rate_mnd(priv->base, priv->data->clks[clk->id].reg, + 5, 0, 0, CFG_CLK_SRC_GPLL2_MAIN, 16); + return rate; + } + return 0; +} + +static const struct gate_clk ipq5424_clks[] = { + GATE_CLK(GCC_QUPV3_UART1_CLK, 0x302c, BIT(0)), + GATE_CLK(GCC_SDCC1_AHB_CLK, 0x3303c, BIT(0)), + GATE_CLK(GCC_SDCC1_APPS_CLK, 0x33004, BIT(1)), + GATE_CLK(GCC_IM_SLEEP_CLK, 0x34020, BIT(0)), +}; + +static int ipq5424_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id >= ARRAY_SIZE(ipq5424_clks) || !ipq5424_clks[clk->id].reg) + return -EINVAL; + + qcom_gate_clk_en(priv, clk->id); + + return 0; +} + +static const struct qcom_reset_map ipq5424_gcc_resets[] = { + [GCC_SDCC_BCR] = { 0x33000 }, +}; + +static struct msm_clk_data ipq5424_gcc_data = { + .resets = ipq5424_gcc_resets, + .num_resets = ARRAY_SIZE(ipq5424_gcc_resets), + .clks = ipq5424_clks, + .num_clks = ARRAY_SIZE(ipq5424_clks), + + .enable = ipq5424_enable, + .set_rate = ipq5424_set_rate, +}; + +static const struct udevice_id gcc_ipq5424_of_match[] = { + { + .compatible = "qcom,ipq5424-gcc", + .data = (ulong)&ipq5424_gcc_data, + }, + { } +}; + +static int ipq5424_clk_probe(struct udevice *dev) +{ + /* Enable the sleep clock needed for the MMC block reset */ + writel(BIT(0), GCC_IM_SLEEP_CBCR); + + return 0; +} + +U_BOOT_DRIVER(gcc_ipq5424) = { + .name = "gcc_ipq5424", + .id = UCLASS_NOP, + .of_match = gcc_ipq5424_of_match, + .probe = ipq5424_clk_probe, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h index 1b60882dae4..3a4550d8536 100644 --- a/drivers/clk/qcom/clock-qcom.h +++ b/drivers/clk/qcom/clock-qcom.h @@ -13,6 +13,7 @@ #define CFG_CLK_SRC_GPLL0 (1 << 8) #define CFG_CLK_SRC_GPLL0_AUX2 (2 << 8) #define CFG_CLK_SRC_GPLL2 (2 << 8) +#define CFG_CLK_SRC_GPLL2_MAIN (2 << 8) #define CFG_CLK_SRC_GPLL9 (2 << 8) #define CFG_CLK_SRC_GPLL0_ODD (3 << 8) #define CFG_CLK_SRC_GPLL6 (4 << 8) diff --git a/drivers/clk/qcom/clock-qcs615.c b/drivers/clk/qcom/clock-qcs615.c new file mode 100644 index 00000000000..4700baba8c9 --- /dev/null +++ b/drivers/clk/qcom/clock-qcs615.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock drivers for Qualcomm qcs615 + * + * (C) Copyright 2024 Linaro Ltd. + */ + +#include <linux/types.h> +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <linux/bug.h> +#include <linux/bitops.h> +#include <dt-bindings/clock/qcom,qcs615-gcc.h> +#include "clock-qcom.h" + +#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf034 +#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf01c +#define USB3_PRIM_PHY_AUX_CMD_RCGR 0xf060 + +#define GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT BIT(10) +#define GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT BIT(11) +#define GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT BIT(12) +#define GCC_QUPV3_WRAP0_S3_CLK_ENA_BIT BIT(13) +#define GCC_QUPV3_WRAP0_S4_CLK_ENA_BIT BIT(14) +#define GCC_QUPV3_WRAP0_S5_CLK_ENA_BIT BIT(15) + +#define GCC_QUPV3_WRAP1_S0_CLK_ENA_BIT BIT(22) +#define GCC_QUPV3_WRAP1_S1_CLK_ENA_BIT BIT(23) +#define GCC_QUPV3_WRAP1_S2_CLK_ENA_BIT BIT(24) +#define GCC_QUPV3_WRAP1_S3_CLK_ENA_BIT BIT(25) +#define GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT BIT(26) +#define GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT BIT(27) + +static ulong qcs615_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id < priv->data->num_clks) + debug("%s: %s, requested rate=%ld\n", __func__, + priv->data->clks[clk->id].name, rate); + + switch (clk->id) { + case GCC_USB30_PRIM_MOCK_UTMI_CLK: + WARN(rate != 19200000, "Unexpected rate for USB30_PRIM_MOCK_UTMI_CLK: %lu\n", rate); + clk_rcg_set_rate(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO); + return rate; + case GCC_USB30_PRIM_MASTER_CLK: + WARN(rate != 200000000, "Unexpected rate for USB30_PRIM_MASTER_CLK: %lu\n", rate); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, + 5, 0, 0, CFG_CLK_SRC_GPLL0, 8); + clk_rcg_set_rate(priv->base, USB3_PRIM_PHY_AUX_CMD_RCGR, 0, 0); + return rate; + default: + return 0; + } +} + +static const struct gate_clk qcs615_clks[] = { + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0xf078, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0xf010, BIT(0)), + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0xf07c, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0xf014, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0xf018, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0xf050, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0xf054, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0xf058, BIT(0)), + GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x5200c, GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x5200c, GCC_QUPV3_WRAP0_S3_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x5200c, GCC_QUPV3_WRAP0_S4_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x5200c, GCC_QUPV3_WRAP0_S5_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S0_CLK, 0x5200c, GCC_QUPV3_WRAP1_S0_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x5200c, GCC_QUPV3_WRAP1_S1_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S2_CLK, 0x5200c, GCC_QUPV3_WRAP1_S2_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x5200c, GCC_QUPV3_WRAP1_S3_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT), + GATE_CLK(GCC_DISP_HF_AXI_CLK, 0xb038, BIT(0)), + GATE_CLK(GCC_DISP_AHB_CLK, 0xb032, BIT(0)) +}; + +static int qcs615_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (priv->data->num_clks < clk->id) { + debug("%s: unknown clk id %lu\n", __func__, clk->id); + return 0; + } + + debug("%s: clk %ld: %s\n", __func__, clk->id, qcs615_clks[clk->id].name); + + switch (clk->id) { + case GCC_AGGRE_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 qcs615_gcc_resets[] = { + [GCC_EMAC_BCR] = { 0x6000 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0xd000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0xd004 }, + [GCC_USB30_PRIM_BCR] = { 0xf000 }, + [GCC_USB2_PHY_SEC_BCR] = { 0x50018 }, + [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50020 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x5001c }, + [GCC_PCIE_0_BCR] = { 0x6b000 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB20_SEC_BCR] = { 0xa6000 }, + [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = { 0x50008 }, + [GCC_USB3_PHY_PRIM_SP0_BCR] = { 0x50000 }, + [GCC_SDCC1_BCR] = { 0x12000 }, + [GCC_SDCC2_BCR] = { 0x14000 } +}; + +static const struct qcom_power_map qcs615_gdscs[] = { + [UFS_PHY_GDSC] = { 0x77004 }, + [USB30_PRIM_GDSC] = { 0xf004 }, +}; + +static struct msm_clk_data sa8775_gcc_data = { + .resets = qcs615_gcc_resets, + .num_resets = ARRAY_SIZE(qcs615_gcc_resets), + .clks = qcs615_clks, + .num_clks = ARRAY_SIZE(qcs615_clks), + + .power_domains = qcs615_gdscs, + .num_power_domains = ARRAY_SIZE(qcs615_gdscs), + + .enable = qcs615_enable, + .set_rate = qcs615_set_rate, +}; + +static const struct udevice_id gcc_qcs615_of_match[] = { + { + .compatible = "qcom,qcs615-gcc", + .data = (ulong)&sa8775_gcc_data, + }, + { } +}; + +U_BOOT_DRIVER(gcc_qcs615) = { + .name = "gcc_qcs615", + .id = UCLASS_NOP, + .of_match = gcc_qcs615_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; diff --git a/drivers/clk/qcom/clock-qcs8300.c b/drivers/clk/qcom/clock-qcs8300.c new file mode 100644 index 00000000000..cd8aecdf788 --- /dev/null +++ b/drivers/clk/qcom/clock-qcs8300.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024-2025, Qualcomm Innovation Center, Inc. All rights reserved. + * + */ + +#include <linux/types.h> +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <linux/bug.h> +#include <linux/bitops.h> +#include <dt-bindings/clock/qcom,qcs8300-gcc.h> +#include "clock-qcom.h" + +#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf038 +#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf020 + +static ulong qcs8300_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id < priv->data->num_clks) + debug("%s: %s, requested rate=%ld\n", + __func__, priv->data->clks[clk->id].name, rate); + + switch (clk->id) { + case GCC_USB30_PRIM_MOCK_UTMI_CLK: + WARN(rate != 19200000, "Unexpected rate for USB30_PRIM_MOCK_UTMI_CLK: %lu\n", rate); + clk_rcg_set_rate(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO); + return rate; + case GCC_USB30_PRIM_MASTER_CLK: + WARN(rate != 200000000, "Unexpected rate for USB30_PRIM_MASTER_CLK: %lu\n", rate); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, + 1, 0, 0, CFG_CLK_SRC_GPLL0_ODD, 8); + clk_rcg_set_rate(priv->base, 0xf064, 0, 0); + return rate; + default: + return 0; + } +} + +static const struct gate_clk qcs8300_clks[] = { + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x1b088, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x1b018, BIT(0)), + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x1b084, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x1b020, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x1b024, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x1b05c, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x1b060, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x83020, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x83018, BIT(0)), + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x830d4, BIT(0)), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x83064, BIT(0)), +}; + +static int qcs8300_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (priv->data->num_clks < clk->id) { + debug("%s: unknown clk id %lu\n", __func__, clk->id); + return 0; + } + + debug("%s: clk %ld: %s\n", __func__, clk->id, qcs8300_clks[clk->id].name); + + switch (clk->id) { + case GCC_AGGRE_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 qcs8300_gcc_resets[] = { + [GCC_EMAC0_BCR] = { 0xb6000 }, + [GCC_PCIE_0_BCR] = { 0xa9000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0xbf000 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0xbf008 }, + [GCC_PCIE_0_PHY_BCR] = { 0xa9144 }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0xbf00c }, + [GCC_PCIE_1_BCR] = { 0x77000 }, + [GCC_PCIE_1_LINK_DOWN_BCR] = { 0xae084 }, + [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0xae090 }, + [GCC_PCIE_1_PHY_BCR] = { 0xae08c }, + [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0xae094 }, + [GCC_SDCC1_BCR] = { 0x20000 }, + [GCC_UFS_PHY_BCR] = { 0x83000 }, + [GCC_USB20_PRIM_BCR] = { 0x1c000 }, + [GCC_USB2_PHY_PRIM_BCR] = { 0x5c01c }, + [GCC_USB2_PHY_SEC_BCR] = { 0x5c020 }, + [GCC_USB30_PRIM_BCR] = { 0x1b000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x5c008 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x5c000 }, + [GCC_USB3_PHY_TERT_BCR] = { 0x5c024 }, + [GCC_USB3_UNIPHY_MP0_BCR] = { 0x5c00c }, + [GCC_USB3_UNIPHY_MP1_BCR] = { 0x5c010 }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x5c004 }, + [GCC_USB3UNIPHY_PHY_MP0_BCR] = { 0x5c014 }, + [GCC_USB3UNIPHY_PHY_MP1_BCR] = { 0x5c018 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x76000 }, + [GCC_VIDEO_BCR] = { 0x34000 }, +}; + +static const struct qcom_power_map qcs8300_gdscs[] = { + [GCC_UFS_PHY_GDSC] = { 0x83004 }, + [GCC_USB30_PRIM_GDSC] = { 0x1B004 }, +}; + +static struct msm_clk_data qcs8300_gcc_data = { + .resets = qcs8300_gcc_resets, + .num_resets = ARRAY_SIZE(qcs8300_gcc_resets), + .clks = qcs8300_clks, + .num_clks = ARRAY_SIZE(qcs8300_clks), + + .power_domains = qcs8300_gdscs, + .num_power_domains = ARRAY_SIZE(qcs8300_gdscs), + + .enable = qcs8300_enable, + .set_rate = qcs8300_set_rate, +}; + +static const struct udevice_id gcc_qcs8300_of_match[] = { + { + .compatible = "qcom,qcs8300-gcc", + .data = (ulong)&qcs8300_gcc_data, + }, + { } +}; + +U_BOOT_DRIVER(gcc_qcs8300) = { + .name = "gcc_qcs8300", + .id = UCLASS_NOP, + .of_match = gcc_qcs8300_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c index 9aff8a847ad..47e0ca5f0e5 100644 --- a/drivers/clk/qcom/clock-sc7280.c +++ b/drivers/clk/qcom/clock-sc7280.c @@ -205,7 +205,7 @@ static const char *const sc7280_rcg_names[] = { "GCC_PCIE_1_AUX_CLK_SRC", }; -static struct msm_clk_data qcs404_gcc_data = { +static struct msm_clk_data sc7280_gcc_data = { .resets = sc7280_gcc_resets, .num_resets = ARRAY_SIZE(sc7280_gcc_resets), .clks = sc7280_clks, @@ -225,7 +225,7 @@ static struct msm_clk_data qcs404_gcc_data = { static const struct udevice_id gcc_sc7280_of_match[] = { { .compatible = "qcom,gcc-sc7280", - .data = (ulong)&qcs404_gcc_data, + .data = (ulong)&sc7280_gcc_data, }, { } }; diff --git a/drivers/clk/qcom/clock-sm8250.c b/drivers/clk/qcom/clock-sm8250.c index 26396847d85..cc481258d22 100644 --- a/drivers/clk/qcom/clock-sm8250.c +++ b/drivers/clk/qcom/clock-sm8250.c @@ -360,7 +360,7 @@ static const char *const sm8250_rcg_names[] = { "GCC_PCIE_2_AUX_CMD_RCGR", }; -static struct msm_clk_data qcs404_gcc_data = { +static struct msm_clk_data sm8250_gcc_data = { .resets = sm8250_gcc_resets, .num_resets = ARRAY_SIZE(sm8250_gcc_resets), .clks = sm8250_clks, @@ -381,7 +381,7 @@ static struct msm_clk_data qcs404_gcc_data = { static const struct udevice_id gcc_sm8250_of_match[] = { { .compatible = "qcom,gcc-sm8250", - .data = (ulong)&qcs404_gcc_data, + .data = (ulong)&sm8250_gcc_data, }, {} }; diff --git a/drivers/dfu/dfu_scsi.c b/drivers/dfu/dfu_scsi.c index 7ec34a8f7e3..d99b05d23ac 100644 --- a/drivers/dfu/dfu_scsi.c +++ b/drivers/dfu/dfu_scsi.c @@ -342,11 +342,6 @@ int dfu_fill_entity_scsi(struct dfu_entity *dfu, char *devstr, char **argv, int return -EINVAL; } - if (scsi_scan(false)) { - pr_err("Couldn't init scsi device.\n"); - return -ENODEV; - } - ret = find_scsi_device(dfu->data.scsi.lun, &scsi); if (ret < 0) { pr_err("Couldn't find scsi device no. %d.\n", dfu->data.scsi.lun); diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c index 6783fc756f4..7de332c66ae 100644 --- a/drivers/gpio/msm_gpio.c +++ b/drivers/gpio/msm_gpio.c @@ -202,7 +202,7 @@ static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio) 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); + return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) & BIT(GPIO_IN)); } static int msm_gpio_get_function_special(struct msm_gpio_bank *priv, diff --git a/drivers/phy/qcom/phy-qcom-qmp-ufs.c b/drivers/phy/qcom/phy-qcom-qmp-ufs.c index 449b9767778..f3c606847fb 100644 --- a/drivers/phy/qcom/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qcom/phy-qcom-qmp-ufs.c @@ -86,6 +86,12 @@ enum qphy_reg_layout { 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, @@ -715,6 +721,98 @@ static const struct qmp_ufs_init_tbl sc7280_ufsphy_hs_g4_rx[] = { QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x0f), }; +static const struct qmp_ufs_init_tbl sm6115_ufsphy_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE1, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE1, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00), +}; + +static const struct qmp_ufs_init_tbl sm6115_ufsphy_hs_b_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x44), +}; + +static const struct qmp_ufs_init_tbl sm6115_ufsphy_tx[] = { + QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), + QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06), +}; + +static const struct qmp_ufs_init_tbl sm6115_ufsphy_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_INTERFACE_MODE, 0x40), + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_TERM_BW, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xff), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xff), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5b), +}; + +static const struct qmp_ufs_init_tbl sm6115_ufsphy_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_PWM_GEAR_BAND, 0x15), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_SIGDET_CTRL2, 0x6d), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_MIN_STALL_NOCONFIG_TIME_CAP, 0x28), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_SYM_RESYNC_CTRL, 0x03), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_LARGE_AMP_POST_EMP_LVL, 0x12), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_SMALL_AMP_POST_EMP_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_MIN_HIBERN8_TIME, 0x9a), /* 8 us */ +}; + struct qmp_ufs_offsets { u16 serdes; u16 pcs; @@ -1079,6 +1177,34 @@ static const struct qmp_ufs_cfg sa8775p_ufsphy_cfg = { .regs = ufsphy_v5_regs_layout, }; +static const struct qmp_ufs_cfg sm6115_ufsphy_cfg = { + .lanes = 1, + + .offsets = &qmp_ufs_offsets, + + .tbls = { + .serdes = sm6115_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sm6115_ufsphy_serdes), + .tx = sm6115_ufsphy_tx, + .tx_num = ARRAY_SIZE(sm6115_ufsphy_tx), + .rx = sm6115_ufsphy_rx, + .rx_num = ARRAY_SIZE(sm6115_ufsphy_rx), + .pcs = sm6115_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sm6115_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sm6115_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sm6115_ufsphy_hs_b_serdes), + }, + .clk_list = sdm845_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .vreg_list = qmp_ufs_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_ufs_vreg_l), + .regs = ufsphy_v2_regs_layout, + + .no_pcs_sw_reset = true, +}; + static void qmp_ufs_configure_lane(void __iomem *base, const struct qmp_ufs_init_tbl tbl[], int num, @@ -1469,9 +1595,11 @@ static const struct udevice_id qmp_ufs_ids[] = { { .compatible = "qcom,sdm845-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg }, { .compatible = "qcom,sm8150-qmp-ufs-phy", .data = (ulong)&sm8150_ufsphy_cfg }, { .compatible = "qcom,sm8250-qmp-ufs-phy", .data = (ulong)&sm8250_ufsphy_cfg }, + { .compatible = "qcom,qcs8300-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg }, { .compatible = "qcom,sm8550-qmp-ufs-phy", .data = (ulong)&sm8550_ufsphy_cfg }, { .compatible = "qcom,sm8650-qmp-ufs-phy", .data = (ulong)&sm8650_ufsphy_cfg }, { .compatible = "qcom,sc7280-qmp-ufs-phy", .data = (ulong)&sc7280_ufsphy_cfg, }, + { .compatible = "qcom,qcs615-qmp-ufs-phy", .data = (ulong)&sm6115_ufsphy_cfg, }, { } }; diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index e567cb113a3..21f81b66099 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -27,6 +27,13 @@ config PINCTRL_QCOM_IPQ4019 Say Y here to enable support for pinctrl on the IPQ4019 SoC, as well as the associated GPIO driver. +config PINCTRL_QCOM_IPQ5424 + bool "Qualcomm IPQ5424 Pinctrl" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the IPQ5424 SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_IPQ9574 bool "Qualcomm IPQ9574 Pinctrl" select PINCTRL_QCOM diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 6ffc6d48c15..6cb53838e71 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PINCTRL_QCOM) += pinctrl-qcom.o obj-$(CONFIG_PINCTRL_QCOM_APQ8016) += pinctrl-apq8016.o obj-$(CONFIG_PINCTRL_QCOM_IPQ4019) += pinctrl-ipq4019.o +obj-$(CONFIG_PINCTRL_QCOM_IPQ5424) += pinctrl-ipq5424.o obj-$(CONFIG_PINCTRL_QCOM_IPQ9574) += pinctrl-ipq9574.o obj-$(CONFIG_PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o obj-$(CONFIG_PINCTRL_QCOM_QCM2290) += pinctrl-qcm2290.o diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5424.c b/drivers/pinctrl/qcom/pinctrl-ipq5424.c new file mode 100644 index 00000000000..cde990a32ef --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-ipq5424.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016-2018,2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <dm.h> + +#include "pinctrl-qcom.h" + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +enum ipq5424_functions { + msm_mux_atest_char, + msm_mux_atest_char0, + msm_mux_atest_char1, + msm_mux_atest_char2, + msm_mux_atest_char3, + msm_mux_atest_tic, + msm_mux_audio_pri, + msm_mux_audio_pri0, + msm_mux_audio_pri1, + msm_mux_audio_sec, + msm_mux_audio_sec0, + msm_mux_audio_sec1, + msm_mux_core_voltage, + msm_mux_cri_trng0, + msm_mux_cri_trng1, + msm_mux_cri_trng2, + msm_mux_cri_trng3, + msm_mux_cxc_clk, + msm_mux_cxc_data, + msm_mux_dbg_out, + msm_mux_gcc_plltest, + msm_mux_gcc_tlmm, + msm_mux_gpio, + msm_mux_i2c0_scl, + msm_mux_i2c0_sda, + msm_mux_i2c1_scl, + msm_mux_i2c1_sda, + msm_mux_i2c11, + msm_mux_mac0, + msm_mux_mac1, + msm_mux_mdc_mst, + msm_mux_mdc_slv, + msm_mux_mdio_mst, + msm_mux_mdio_slv, + msm_mux_pcie0_clk, + msm_mux_pcie0_wake, + msm_mux_pcie1_clk, + msm_mux_pcie1_wake, + msm_mux_pcie2_clk, + msm_mux_pcie2_wake, + msm_mux_pcie3_clk, + msm_mux_pcie3_wake, + msm_mux_pll_test, + msm_mux_prng_rosc0, + msm_mux_prng_rosc1, + msm_mux_prng_rosc2, + msm_mux_prng_rosc3, + msm_mux_PTA0_0, + msm_mux_PTA0_1, + msm_mux_PTA0_2, + msm_mux_PTA10, + msm_mux_PTA11, + msm_mux_pwm0, + msm_mux_pwm1, + msm_mux_pwm2, + msm_mux_qdss_cti_trig_in_a0, + msm_mux_qdss_cti_trig_out_a0, + msm_mux_qdss_cti_trig_in_a1, + msm_mux_qdss_cti_trig_out_a1, + msm_mux_qdss_cti_trig_in_b0, + msm_mux_qdss_cti_trig_out_b0, + msm_mux_qdss_cti_trig_in_b1, + msm_mux_qdss_cti_trig_out_b1, + msm_mux_qdss_traceclk_a, + msm_mux_qdss_tracectl_a, + msm_mux_qdss_tracedata_a, + msm_mux_qspi_clk, + msm_mux_qspi_cs, + msm_mux_qspi_data, + msm_mux_resout, + msm_mux_rx0, + msm_mux_rx1, + msm_mux_rx2, + msm_mux_sdc_clk, + msm_mux_sdc_cmd, + msm_mux_sdc_data, + msm_mux_spi0_clk, + msm_mux_spi0_cs, + msm_mux_spi0_miso, + msm_mux_spi0_mosi, + msm_mux_spi1, + msm_mux_spi10, + msm_mux_spi11, + msm_mux_tsens_max, + msm_mux_uart0, + msm_mux_uart1, + msm_mux_wci_txd, + msm_mux_wci_rxd, + msm_mux_wsi_clk, + msm_mux_wsi_data, + msm_mux__, +}; + +#define MSM_PIN_FUNCTION(fname) \ + [msm_mux_##fname] = {#fname, msm_mux_##fname} + +static const struct pinctrl_function ipq5424_functions[] = { + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(atest_char0), + MSM_PIN_FUNCTION(atest_char1), + MSM_PIN_FUNCTION(atest_char2), + MSM_PIN_FUNCTION(atest_char3), + MSM_PIN_FUNCTION(atest_tic), + MSM_PIN_FUNCTION(audio_pri), + MSM_PIN_FUNCTION(audio_pri0), + MSM_PIN_FUNCTION(audio_pri1), + MSM_PIN_FUNCTION(audio_sec), + MSM_PIN_FUNCTION(audio_sec0), + MSM_PIN_FUNCTION(audio_sec1), + MSM_PIN_FUNCTION(core_voltage), + MSM_PIN_FUNCTION(cri_trng0), + MSM_PIN_FUNCTION(cri_trng1), + MSM_PIN_FUNCTION(cri_trng2), + MSM_PIN_FUNCTION(cri_trng3), + MSM_PIN_FUNCTION(cxc_clk), + MSM_PIN_FUNCTION(cxc_data), + MSM_PIN_FUNCTION(dbg_out), + MSM_PIN_FUNCTION(gcc_plltest), + MSM_PIN_FUNCTION(gcc_tlmm), + MSM_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(i2c0_scl), + MSM_PIN_FUNCTION(i2c0_sda), + MSM_PIN_FUNCTION(i2c1_scl), + MSM_PIN_FUNCTION(i2c1_sda), + MSM_PIN_FUNCTION(i2c11), + MSM_PIN_FUNCTION(mac0), + MSM_PIN_FUNCTION(mac1), + MSM_PIN_FUNCTION(mdc_mst), + MSM_PIN_FUNCTION(mdc_slv), + MSM_PIN_FUNCTION(mdio_mst), + MSM_PIN_FUNCTION(mdio_slv), + MSM_PIN_FUNCTION(pcie0_clk), + MSM_PIN_FUNCTION(pcie0_wake), + MSM_PIN_FUNCTION(pcie1_clk), + MSM_PIN_FUNCTION(pcie1_wake), + MSM_PIN_FUNCTION(pcie2_clk), + MSM_PIN_FUNCTION(pcie2_wake), + MSM_PIN_FUNCTION(pcie3_clk), + MSM_PIN_FUNCTION(pcie3_wake), + MSM_PIN_FUNCTION(pll_test), + MSM_PIN_FUNCTION(prng_rosc0), + MSM_PIN_FUNCTION(prng_rosc1), + MSM_PIN_FUNCTION(prng_rosc2), + MSM_PIN_FUNCTION(prng_rosc3), + MSM_PIN_FUNCTION(PTA0_0), + MSM_PIN_FUNCTION(PTA0_1), + MSM_PIN_FUNCTION(PTA0_2), + MSM_PIN_FUNCTION(PTA10), + MSM_PIN_FUNCTION(PTA11), + MSM_PIN_FUNCTION(pwm0), + MSM_PIN_FUNCTION(pwm1), + MSM_PIN_FUNCTION(pwm2), + MSM_PIN_FUNCTION(qdss_cti_trig_in_a0), + MSM_PIN_FUNCTION(qdss_cti_trig_out_a0), + MSM_PIN_FUNCTION(qdss_cti_trig_in_a1), + MSM_PIN_FUNCTION(qdss_cti_trig_out_a1), + MSM_PIN_FUNCTION(qdss_cti_trig_in_b0), + MSM_PIN_FUNCTION(qdss_cti_trig_out_b0), + MSM_PIN_FUNCTION(qdss_cti_trig_in_b1), + MSM_PIN_FUNCTION(qdss_cti_trig_out_b1), + MSM_PIN_FUNCTION(qdss_traceclk_a), + MSM_PIN_FUNCTION(qdss_tracectl_a), + MSM_PIN_FUNCTION(qdss_tracedata_a), + MSM_PIN_FUNCTION(qspi_clk), + MSM_PIN_FUNCTION(qspi_cs), + MSM_PIN_FUNCTION(qspi_data), + MSM_PIN_FUNCTION(resout), + MSM_PIN_FUNCTION(rx0), + MSM_PIN_FUNCTION(rx1), + MSM_PIN_FUNCTION(rx2), + MSM_PIN_FUNCTION(sdc_clk), + MSM_PIN_FUNCTION(sdc_cmd), + MSM_PIN_FUNCTION(sdc_data), + MSM_PIN_FUNCTION(spi0_clk), + MSM_PIN_FUNCTION(spi0_cs), + MSM_PIN_FUNCTION(spi0_miso), + MSM_PIN_FUNCTION(spi0_mosi), + MSM_PIN_FUNCTION(spi1), + MSM_PIN_FUNCTION(spi10), + MSM_PIN_FUNCTION(spi11), + MSM_PIN_FUNCTION(tsens_max), + MSM_PIN_FUNCTION(uart0), + MSM_PIN_FUNCTION(uart1), + MSM_PIN_FUNCTION(wci_txd), + MSM_PIN_FUNCTION(wci_rxd), + MSM_PIN_FUNCTION(wsi_clk), + MSM_PIN_FUNCTION(wsi_data), +}; + +typedef unsigned int msm_pin_function[10]; + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)\ + [id] = { 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, \ + } + +static const msm_pin_function ipq5424_pin_functions[] = { + PINGROUP(0, sdc_data, qspi_data, pwm2, wci_txd, wci_rxd, _, _, _, _), + PINGROUP(1, sdc_data, qspi_data, pwm2, wci_txd, wci_rxd, _, _, _, _), + PINGROUP(2, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(3, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(4, sdc_cmd, qspi_cs, _, _, _, _, _, _, _), + PINGROUP(5, sdc_clk, qspi_clk, _, _, _, _, _, _, _), + PINGROUP(6, spi0_clk, pwm1, _, cri_trng0, qdss_tracedata_a, _, _, _, _), + PINGROUP(7, spi0_cs, pwm1, _, cri_trng1, qdss_tracedata_a, _, _, _, _), + PINGROUP(8, spi0_miso, pwm1, wci_txd, wci_rxd, _, cri_trng2, qdss_tracedata_a, _, _), + PINGROUP(9, spi0_mosi, pwm1, _, cri_trng3, qdss_tracedata_a, _, _, _, _), + PINGROUP(10, uart0, pwm0, spi11, _, wci_txd, wci_rxd, _, qdss_tracedata_a, _), + PINGROUP(11, uart0, pwm0, spi1, _, wci_txd, wci_rxd, _, qdss_tracedata_a, _), + PINGROUP(12, uart0, pwm0, spi11, _, prng_rosc0, qdss_tracedata_a, _, _, _), + PINGROUP(13, uart0, pwm0, spi11, _, prng_rosc1, qdss_tracedata_a, _, _, _), + PINGROUP(14, i2c0_scl, tsens_max, _, prng_rosc2, qdss_tracedata_a, _, _, _, _), + PINGROUP(15, i2c0_sda, _, prng_rosc3, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(16, core_voltage, i2c1_scl, _, _, _, _, _, _, _), + PINGROUP(17, core_voltage, i2c1_sda, _, _, _, _, _, _, _), + PINGROUP(18, _, _, _, _, _, _, _, _, _), + PINGROUP(19, _, _, _, _, _, _, _, _, _), + PINGROUP(20, mdc_slv, atest_char0, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(21, mdio_slv, atest_char1, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(22, mdc_mst, atest_char2, _, _, _, _, _, _, _), + PINGROUP(23, mdio_mst, atest_char3, _, _, _, _, _, _, _), + PINGROUP(24, pcie0_clk, PTA10, mac0, _, wsi_clk, _, atest_char, qdss_cti_trig_out_a0, _), + PINGROUP(25, _, _, _, _, _, _, _, _, _), + PINGROUP(26, pcie0_wake, PTA10, mac0, _, wsi_data, _, qdss_cti_trig_in_a0, _, _), + PINGROUP(27, pcie1_clk, i2c11, PTA10, wsi_clk, qdss_cti_trig_out_a1, _, _, _, _), + PINGROUP(28, _, _, _, _, _, _, _, _, _), + PINGROUP(29, pcie1_wake, i2c11, wsi_data, qdss_cti_trig_in_a1, _, _, _, _, _), + PINGROUP(30, pcie2_clk, PTA11, mac1, qdss_cti_trig_out_b0, _, _, _, _, _), + PINGROUP(31, _, _, _, _, _, _, _, _, _), + PINGROUP(32, pcie2_wake, PTA11, mac1, audio_pri0, audio_pri0, qdss_cti_trig_in_b0, _, _, _), + PINGROUP(33, pcie3_clk, PTA11, audio_pri1, audio_pri1, qdss_cti_trig_out_b1, _, _, _, _), + PINGROUP(34, _, _, _, _, _, _, _, _, _), + PINGROUP(35, pcie3_wake, audio_sec1, audio_sec1, qdss_cti_trig_in_b1, _, _, _, _, _), + PINGROUP(36, audio_pri, spi1, audio_sec0, audio_sec0, qdss_tracedata_a, _, _, _, _), + PINGROUP(37, audio_pri, spi1, rx2, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(38, audio_pri, spi1, pll_test, rx1, qdss_tracedata_a, _, _, _, _), + PINGROUP(39, audio_pri, rx0, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(40, PTA0_0, wci_txd, wci_rxd, _, atest_tic, _, _, _, _), + PINGROUP(41, PTA0_1, wci_txd, wci_rxd, cxc_data, _, _, _, _, _), + PINGROUP(42, PTA0_2, cxc_clk, _, _, _, _, _, _, _), + PINGROUP(43, uart1, gcc_plltest, _, _, _, _, _, _, _), + PINGROUP(44, uart1, gcc_tlmm, _, _, _, _, _, _, _), + PINGROUP(45, spi10, rx2, audio_sec, gcc_plltest, _, qdss_traceclk_a, _, _, _), + PINGROUP(46, spi1, rx1, audio_sec, dbg_out, qdss_tracectl_a, _, _, _, _), + PINGROUP(47, spi10, rx0, audio_sec, _, _, _, _, _, _), + PINGROUP(48, spi10, audio_sec, _, _, _, _, _, _, _), + PINGROUP(49, resout, _, _, _, _, _, _, _, _), +}; + +static const char *ipq5424_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return ipq5424_functions[selector].name; +} + +static const char *ipq5424_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + return pin_name; +} + +static int ipq5424_get_function_mux(unsigned int pin, unsigned int selector) +{ + unsigned int i; + const msm_pin_function *func = ipq5424_pin_functions + pin; + + for (i = 0; i < 10; i++) + if ((*func)[i] == selector) + return i; + + debug("Can't find requested function for pin:selector %u:%u\n", + pin, selector); + + return -EINVAL; +} + +static const struct msm_pinctrl_data ipq5424_data = { + .pin_data = { + .pin_count = 49, + }, + .functions_count = ARRAY_SIZE(ipq5424_functions), + .get_function_name = ipq5424_get_function_name, + .get_function_mux = ipq5424_get_function_mux, + .get_pin_name = ipq5424_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,ipq5424-tlmm", .data = (ulong)&ipq5424_data }, + { /* Sentinal */ } +}; + +U_BOOT_DRIVER(pinctrl_ipq5424) = { + .name = "pinctrl_ipq5424", + .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/watchdog/Kconfig b/drivers/watchdog/Kconfig index a0f2948335f..45eb9b4d3f9 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -29,6 +29,7 @@ config WATCHDOG_TIMEOUT_MSECS int "Watchdog timeout in msec" default 128000 if ARCH_MX31 || ARCH_MX5 || ARCH_MX6 default 128000 if ARCH_MX7 || ARCH_VF610 + default 30000 if ARCH_SNAPDRAGON default 30000 if ARCH_SOCFPGA default 16000 if ARCH_SUNXI default 5376 if ULP_WATCHDOG @@ -335,6 +336,14 @@ config WDT_K3_RTI_FW_FILE endif +config WDT_QCOM + bool "Qualcomm watchdog timer support" + depends on WDT && ARCH_SNAPDRAGON + imply WATCHDOG + help + Select this to enable Qualcomm watchdog timer, which can be found on + some Qualcomm chips. + config WDT_RENESAS bool "Renesas watchdog timer support" depends on WDT && R8A779F0 diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index c4467d6e126..d52d17e1c90 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -55,3 +55,4 @@ obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o obj-$(CONFIG_WDT_ADI) += adi_wdt.o +obj-$(CONFIG_WDT_QCOM) += qcom-wdt.o diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c new file mode 100644 index 00000000000..adbb5aacdc3 --- /dev/null +++ b/drivers/watchdog/qcom-wdt.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) Linaro Ltd. 2024 + * + * Authors: + * Casey Connolly <casey.connolly@linaro.org> + * Paul Sajna <hello@paulsajna.com> + * + * Derived from linux/drivers/watchdog/qcom-wdt.c + */ + +#include <dm.h> +#include <dm/device_compat.h> +#include <wdt.h> +#include <clk.h> + +#include <asm/io.h> + +enum wdt_reg { + WDT_RST, + WDT_EN, + WDT_STS, + WDT_BARK_TIME, + WDT_BITE_TIME, +}; + +struct qcom_wdt_match_data { + const u32 *offset; +}; + +struct qcom_wdt { + void __iomem *base; + ulong clk_rate; + const u32 *layout; +}; + +static const u32 reg_offset_data_kpss[] = { + [WDT_RST] = 0x4, + [WDT_EN] = 0x8, + [WDT_STS] = 0xC, + [WDT_BARK_TIME] = 0x10, + [WDT_BITE_TIME] = 0x14, +}; + +static const struct qcom_wdt_match_data match_data_kpss = { + .offset = reg_offset_data_kpss, +}; + +static void __iomem *wdt_addr(struct qcom_wdt *wdt, enum wdt_reg reg) +{ + return wdt->base + wdt->layout[reg]; +} + +int qcom_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct qcom_wdt *wdt = dev_get_priv(dev); + ulong bark_timeout_s = ((timeout_ms - 1) * wdt->clk_rate) / 1000; + ulong bite_timeout_s = (timeout_ms * wdt->clk_rate) / 1000; + + writel(0, wdt_addr(wdt, WDT_EN)); + writel(BIT(0), wdt_addr(wdt, WDT_RST)); + writel(bark_timeout_s, wdt_addr(wdt, WDT_BARK_TIME)); + writel(bite_timeout_s, wdt_addr(wdt, WDT_BITE_TIME)); + writel(BIT(0), wdt_addr(wdt, WDT_EN)); + if (readl(wdt_addr(wdt, WDT_EN)) != 1) { + dev_err(dev, "Failed to enable Qualcomm watchdog!\n"); + return -EIO; + } + return 0; +} + +int qcom_wdt_stop(struct udevice *dev) +{ + struct qcom_wdt *wdt = dev_get_priv(dev); + + writel(0, wdt_addr(wdt, WDT_EN)); + if (readl(wdt_addr(wdt, WDT_EN))) { + dev_err(dev, "Failed to disable Qualcomm watchdog!\n"); + return -EIO; + } + + return 0; +} + +int qcom_wdt_reset(struct udevice *dev) +{ + struct qcom_wdt *wdt = dev_get_priv(dev); + + writel(1, wdt_addr(wdt, WDT_RST)); + return 0; +} + +static int qcom_wdt_probe(struct udevice *dev) +{ + struct clk clk; + long rate; + int ret; + + struct qcom_wdt *wdt = dev_get_priv(dev); + struct qcom_wdt_match_data *data = (void *)dev_get_driver_data(dev); + + wdt->base = dev_read_addr_ptr(dev); + wdt->layout = data->offset; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + rate = clk_get_rate(&clk); + if (rate <= 0) + return rate < 0 ? (int)rate : -EINVAL; + + wdt->clk_rate = (ulong)rate; + + return 0; +} + +static const struct wdt_ops qcom_wdt_ops = { + .start = qcom_wdt_start, + .stop = qcom_wdt_stop, + .reset = qcom_wdt_reset, +}; + +static const struct udevice_id qcom_wdt_ids[] = { + { .compatible = "qcom,kpss-wdt", .data = (ulong)&match_data_kpss }, + {} +}; + +U_BOOT_DRIVER(qcom_wdt) = { + .name = "qcom_wdt", + .id = UCLASS_WDT, + .of_match = qcom_wdt_ids, + .ops = &qcom_wdt_ops, + .probe = qcom_wdt_probe, + .priv_auto = sizeof(struct qcom_wdt), +}; |