ipq806x: 5:15: copy config and patch from 5.10

Copy config and patch from kernel 5.10 to kernel 5.15

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
This commit is contained in:
Ansuel Smith 2021-11-04 21:56:41 +01:00 committed by Daniel Golle
parent 26e7c22757
commit 3064e76c94
44 changed files with 6995 additions and 0 deletions

View File

@ -0,0 +1,506 @@
CONFIG_ALIGNMENT_TRAP=y
# CONFIG_APQ_GCC_8084 is not set
# CONFIG_APQ_MMCC_8084 is not set
CONFIG_AR8216_PHY=y
CONFIG_ARCH_32BIT_OFF_T=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
# CONFIG_ARCH_IPQ40XX is not set
CONFIG_ARCH_KEEP_MEMBLOCK=y
# CONFIG_ARCH_MDM9615 is not set
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_ARCH_MSM8960=y
CONFIG_ARCH_MSM8974=y
CONFIG_ARCH_MSM8X60=y
CONFIG_ARCH_MULTIPLATFORM=y
CONFIG_ARCH_MULTI_V6_V7=y
CONFIG_ARCH_MULTI_V7=y
CONFIG_ARCH_NR_GPIO=0
CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARM=y
CONFIG_ARM_AMBA=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ARCH_TIMER=y
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE=y
CONFIG_ARM_CPUIDLE=y
CONFIG_ARM_CPU_SUSPEND=y
# CONFIG_ARM_CPU_TOPOLOGY is not set
CONFIG_ARM_GIC=y
CONFIG_ARM_HAS_SG_CHAIN=y
CONFIG_ARM_L1_CACHE_SHIFT=6
CONFIG_ARM_L1_CACHE_SHIFT_6=y
CONFIG_ARM_MODULE_PLTS=y
CONFIG_ARM_PATCH_IDIV=y
CONFIG_ARM_PATCH_PHYS_VIRT=y
# CONFIG_ARM_QCOM_CPUFREQ_HW is not set
CONFIG_ARM_QCOM_CPUFREQ_KRAIT=y
CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y
CONFIG_ARM_QCOM_SPM_CPUIDLE=y
# CONFIG_ARM_SMMU is not set
CONFIG_ARM_THUMB=y
CONFIG_ARM_UNWIND=y
CONFIG_ARM_VIRT_EXT=y
CONFIG_AT803X_PHY=y
CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_MQ_PCI=y
CONFIG_BOUNCE=y
# CONFIG_CACHE_L2X0 is not set
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLKSRC_QCOM=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMDLINE_OVERRIDE=y
CONFIG_COMMON_CLK=y
CONFIG_COMMON_CLK_QCOM=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_CPUFREQ_DT=y
CONFIG_CPUFREQ_DT_PLATDEV=y
CONFIG_CPU_32v6K=y
CONFIG_CPU_32v7=y
CONFIG_CPU_ABRT_EV7=y
CONFIG_CPU_CACHE_V7=y
CONFIG_CPU_CACHE_VIPT=y
CONFIG_CPU_COPY_V6=y
CONFIG_CPU_CP15=y
CONFIG_CPU_CP15_MMU=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
CONFIG_CPU_FREQ_GOV_COMMON=y
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_HAS_ASID=y
CONFIG_CPU_IDLE=y
CONFIG_CPU_IDLE_GOV_LADDER=y
CONFIG_CPU_IDLE_GOV_MENU=y
CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y
CONFIG_CPU_PABRT_V7=y
CONFIG_CPU_PM=y
CONFIG_CPU_RMAP=y
CONFIG_CPU_SPECTRE=y
CONFIG_CPU_THERMAL=y
CONFIG_CPU_THUMB_CAPABLE=y
CONFIG_CPU_TLB_V7=y
CONFIG_CPU_V7=y
CONFIG_CRC16=y
# CONFIG_CRC32_SARWATE is not set
CONFIG_CRC32_SLICEBY8=y
CONFIG_CRYPTO_ACOMP2=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_DEV_QCOM_RNG=y
CONFIG_CRYPTO_DRBG=y
CONFIG_CRYPTO_DRBG_HMAC=y
CONFIG_CRYPTO_DRBG_MENU=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_HASH_INFO=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_JITTERENTROPY=y
CONFIG_CRYPTO_LIB_SHA256=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_NULL2=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_ZSTD=y
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_DEBUG_GPIO=y
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
# CONFIG_DEVFREQ_GOV_PASSIVE is not set
# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set
# CONFIG_DEVFREQ_GOV_POWERSAVE is not set
# CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND is not set
# CONFIG_DEVFREQ_GOV_USERSPACE is not set
# CONFIG_DEVFREQ_THERMAL is not set
CONFIG_DMADEVICES=y
CONFIG_DMA_ENGINE=y
CONFIG_DMA_OF=y
CONFIG_DMA_OPS=y
CONFIG_DMA_REMAP=y
CONFIG_DMA_VIRTUAL_CHANNELS=y
CONFIG_DTC=y
CONFIG_DT_IDLE_STATES=y
# CONFIG_DWMAC_GENERIC is not set
CONFIG_DWMAC_IPQ806X=y
# CONFIG_DWMAC_QCOM_ETHQOS is not set
CONFIG_DYNAMIC_DEBUG=y
CONFIG_EDAC_ATOMIC_SCRUB=y
CONFIG_EDAC_SUPPORT=y
CONFIG_ETHERNET_PACKET_MANGLE=y
CONFIG_FIXED_PHY=y
CONFIG_FIX_EARLYCON_MEM=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_EARLY_IOREMAP=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_PINCONF=y
CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_VDSO_32=y
CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_GRO_CELLS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HAVE_SMP=y
CONFIG_HIGHMEM=y
# CONFIG_HIGHPTE is not set
CONFIG_HWMON=y
CONFIG_HWSPINLOCK=y
CONFIG_HWSPINLOCK_QCOM=y
CONFIG_HW_RANDOM=y
CONFIG_HZ=100
CONFIG_HZ_100=y
CONFIG_HZ_FIXED=0
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
# CONFIG_I2C_QCOM_CCI is not set
CONFIG_I2C_QUP=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_IOMMU_DEBUGFS is not set
# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set
# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
CONFIG_IOMMU_SUPPORT=y
# CONFIG_IPQ_APSS_PLL is not set
# CONFIG_IPQ_GCC_4019 is not set
# CONFIG_IPQ_GCC_6018 is not set
CONFIG_IPQ_GCC_806X=y
# CONFIG_IPQ_GCC_8074 is not set
# CONFIG_IPQ_LCC_806X is not set
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_WORK=y
CONFIG_KPSS_XCC=y
CONFIG_KRAITCC=y
CONFIG_KRAIT_CLOCKS=y
CONFIG_KRAIT_L2_ACCESSORS=y
CONFIG_LIBFDT=y
CONFIG_LLD_VERSION=0
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_MDIO_BITBANG=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_GPIO=y
CONFIG_MDIO_IPQ8064=y
# CONFIG_MDM_GCC_9615 is not set
# CONFIG_MDM_LCC_9615 is not set
CONFIG_MEMFD_CREATE=y
# CONFIG_MFD_HI6421_SPMI is not set
CONFIG_MFD_QCOM_RPM=y
# CONFIG_MFD_SPMI_PMIC is not set
CONFIG_MFD_SYSCON=y
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
CONFIG_MIGRATION=y
CONFIG_MMC=y
CONFIG_MMC_ARMMMCI=y
CONFIG_MMC_BLOCK=y
CONFIG_MMC_BLOCK_MINORS=16
CONFIG_MMC_CQHCI=y
CONFIG_MMC_QCOM_DML=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_IO_ACCESSORS=y
CONFIG_MMC_SDHCI_MSM=y
# CONFIG_MMC_SDHCI_PCI is not set
CONFIG_MMC_SDHCI_PLTFM=y
# CONFIG_MMC_TIFM_SD is not set
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MSM_GCC_8660=y
# CONFIG_MSM_GCC_8916 is not set
# CONFIG_MSM_GCC_8939 is not set
# CONFIG_MSM_GCC_8960 is not set
# CONFIG_MSM_GCC_8974 is not set
# CONFIG_MSM_GCC_8994 is not set
# CONFIG_MSM_GCC_8996 is not set
# CONFIG_MSM_GCC_8998 is not set
# CONFIG_MSM_GPUCC_8998 is not set
# CONFIG_MSM_IOMMU is not set
# CONFIG_MSM_LCC_8960 is not set
# CONFIG_MSM_MMCC_8960 is not set
# CONFIG_MSM_MMCC_8974 is not set
# CONFIG_MSM_MMCC_8996 is not set
# CONFIG_MSM_MMCC_8998 is not set
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_NAND_CORE=y
CONFIG_MTD_NAND_ECC=y
CONFIG_MTD_NAND_ECC_SW_HAMMING=y
CONFIG_MTD_NAND_QCOM=y
CONFIG_MTD_QCOMSMEM_PARTS=y
CONFIG_MTD_RAW_NAND=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_FIT_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
CONFIG_MTD_UBI_BLOCK=y
CONFIG_MTD_UBI_WL_THRESHOLD=4096
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEON=y
CONFIG_NET_DEVLINK=y
CONFIG_NET_DSA=y
CONFIG_NET_DSA_QCA8K=y
CONFIG_NET_DSA_TAG_QCA=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_PTP_CLASSIFY=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NLS=y
CONFIG_NO_HZ=y
CONFIG_NO_HZ_COMMON=y
CONFIG_NO_HZ_IDLE=y
CONFIG_NR_CPUS=2
CONFIG_NVMEM=y
# CONFIG_NVMEM_SPMI_SDAM is not set
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_KOBJ=y
CONFIG_OF_MDIO=y
CONFIG_OF_NET=y
CONFIG_OLD_SIGACTION=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_PADATA=y
CONFIG_PAGE_OFFSET=0xC0000000
CONFIG_PAGE_POOL=y
CONFIG_PCI=y
CONFIG_PCIEAER=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIE_DW=y
CONFIG_PCIE_DW_HOST=y
CONFIG_PCIE_QCOM=y
CONFIG_PCI_DEBUG=y
CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DOMAINS_GENERIC=y
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PCS_XPCS=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PHYLINK=y
# CONFIG_PHY_QCOM_APQ8064_SATA is not set
# CONFIG_PHY_QCOM_IPQ4019_USB is not set
CONFIG_PHY_QCOM_IPQ806X_SATA=y
# CONFIG_PHY_QCOM_IPQ806X_USB is not set
# CONFIG_PHY_QCOM_PCIE2 is not set
# CONFIG_PHY_QCOM_QMP is not set
# CONFIG_PHY_QCOM_QUSB2 is not set
# CONFIG_PHY_QCOM_USB_HS_28NM is not set
# CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2 is not set
# CONFIG_PHY_QCOM_USB_SS is not set
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_APQ8064 is not set
# CONFIG_PINCTRL_APQ8084 is not set
# CONFIG_PINCTRL_IPQ4019 is not set
# CONFIG_PINCTRL_IPQ6018 is not set
CONFIG_PINCTRL_IPQ8064=y
# CONFIG_PINCTRL_IPQ8074 is not set
# CONFIG_PINCTRL_MDM9615 is not set
CONFIG_PINCTRL_MSM=y
# CONFIG_PINCTRL_MSM8226 is not set
# CONFIG_PINCTRL_MSM8660 is not set
# CONFIG_PINCTRL_MSM8916 is not set
# CONFIG_PINCTRL_MSM8960 is not set
# CONFIG_PINCTRL_MSM8976 is not set
# CONFIG_PINCTRL_MSM8994 is not set
# CONFIG_PINCTRL_MSM8996 is not set
# CONFIG_PINCTRL_MSM8998 is not set
# CONFIG_PINCTRL_QCOM_SPMI_PMIC is not set
# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set
# CONFIG_PINCTRL_QCS404 is not set
# CONFIG_PINCTRL_SC7180 is not set
# CONFIG_PINCTRL_SDM660 is not set
# CONFIG_PINCTRL_SDM845 is not set
# CONFIG_PINCTRL_SM8150 is not set
# CONFIG_PINCTRL_SM8250 is not set
CONFIG_PM_DEVFREQ=y
# CONFIG_PM_DEVFREQ_EVENT is not set
CONFIG_PM_OPP=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_MSM=y
CONFIG_POWER_SUPPLY=y
CONFIG_PPS=y
CONFIG_PRINTK_TIME=y
CONFIG_PTP_1588_CLOCK=y
# CONFIG_QCOM_A53PLL is not set
CONFIG_QCOM_ADM=y
CONFIG_QCOM_BAM_DMA=y
CONFIG_QCOM_CLK_RPM=y
# CONFIG_QCOM_COMMAND_DB is not set
# CONFIG_QCOM_CPR is not set
# CONFIG_QCOM_EBI2 is not set
# CONFIG_QCOM_GENI_SE is not set
CONFIG_QCOM_GSBI=y
CONFIG_QCOM_HFPLL=y
# CONFIG_QCOM_IOMMU is not set
# CONFIG_QCOM_LLCC is not set
# CONFIG_QCOM_OCMEM is not set
# CONFIG_QCOM_PDC is not set
CONFIG_QCOM_QFPROM=y
# CONFIG_QCOM_RMTFS_MEM is not set
CONFIG_QCOM_RPMCC=y
# CONFIG_QCOM_RPMH is not set
CONFIG_QCOM_SCM=y
# CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is not set
CONFIG_QCOM_SMEM=y
# CONFIG_QCOM_SMSM is not set
# CONFIG_QCOM_SOCINFO is not set
CONFIG_QCOM_TCSR=y
CONFIG_QCOM_TSENS=y
CONFIG_QCOM_WDT=y
# CONFIG_QCS_GCC_404 is not set
# CONFIG_QCS_Q6SSTOP_404 is not set
# CONFIG_QCS_TURING_404 is not set
CONFIG_RAS=y
CONFIG_RATIONAL=y
CONFIG_REGMAP=y
CONFIG_REGMAP_MMIO=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
# CONFIG_REGULATOR_QCOM_LABIBB is not set
CONFIG_REGULATOR_QCOM_RPM=y
# CONFIG_REGULATOR_QCOM_SPMI is not set
# CONFIG_REGULATOR_QCOM_USB_VBUS is not set
# CONFIG_REGULATOR_VQMMC_IPQ4019 is not set
CONFIG_RESET_CONTROLLER=y
# CONFIG_RESET_QCOM_AOSS is not set
# CONFIG_RESET_QCOM_PDC is not set
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_I2C_AND_SPI=y
CONFIG_RTC_MC146818_LIB=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
# CONFIG_SC_DISPCC_7180 is not set
# CONFIG_SC_GCC_7180 is not set
# CONFIG_SC_GPUCC_7180 is not set
# CONFIG_SC_LPASS_CORECC_7180 is not set
# CONFIG_SC_MSS_7180 is not set
# CONFIG_SC_VIDEOCC_7180 is not set
# CONFIG_SDM_CAMCC_845 is not set
# CONFIG_SDM_DISPCC_845 is not set
# CONFIG_SDM_GCC_660 is not set
# CONFIG_SDM_GCC_845 is not set
# CONFIG_SDM_GPUCC_845 is not set
# CONFIG_SDM_LPASSCC_845 is not set
# CONFIG_SDM_VIDEOCC_845 is not set
CONFIG_SERIAL_8250_FSL=y
CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_SGL_ALLOC=y
CONFIG_SMP=y
CONFIG_SMP_ON_UP=y
# CONFIG_SM_GCC_8150 is not set
# CONFIG_SM_GCC_8250 is not set
# CONFIG_SM_GPUCC_8150 is not set
# CONFIG_SM_GPUCC_8250 is not set
# CONFIG_SM_VIDEOCC_8150 is not set
# CONFIG_SM_VIDEOCC_8250 is not set
CONFIG_SPARSE_IRQ=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SPI_QUP=y
CONFIG_SPMI=y
# CONFIG_SPMI_HISI3670 is not set
CONFIG_SPMI_MSM_PMIC_ARB=y
# CONFIG_SPMI_PMIC_CLKDIV is not set
CONFIG_SRCU=y
CONFIG_STMMAC_ETH=y
CONFIG_STMMAC_PLATFORM=y
# CONFIG_STMMAC_SELFTESTS is not set
CONFIG_SWCONFIG=y
CONFIG_SWCONFIG_LEDS=y
CONFIG_SWPHY=y
CONFIG_SWP_EMULATE=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_THERMAL=y
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
CONFIG_THERMAL_GOV_STEP_WISE=y
CONFIG_THERMAL_HWMON=y
CONFIG_THERMAL_OF=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TREE_RCU=y
CONFIG_TREE_SRCU=y
CONFIG_UBIFS_FS=y
CONFIG_UBIFS_FS_ADVANCED_COMPR=y
CONFIG_UBIFS_FS_LZO=y
CONFIG_UBIFS_FS_ZLIB=y
CONFIG_UBIFS_FS_ZSTD=y
# CONFIG_UCLAMP_TASK is not set
CONFIG_UEVENT_HELPER_PATH=""
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
CONFIG_UNWINDER_ARM=y
CONFIG_USB=y
CONFIG_USB_COMMON=y
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_VFP=y
CONFIG_VFPv3=y
CONFIG_WATCHDOG_CORE=y
CONFIG_XPS=y
CONFIG_XXHASH=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_BCJ=y
CONFIG_ZBOOT_ROM_BSS=0
CONFIG_ZBOOT_ROM_TEXT=0
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZSTD_COMPRESS=y
CONFIG_ZSTD_DECOMPRESS=y

View File

@ -0,0 +1,71 @@
From 28d0ed88f536dd639adf1b0c7c08e04be3c8f294 Mon Sep 17 00:00:00 2001
From: Thomas Pedersen <twp@codeaurora.org>
Date: Mon, 16 May 2016 17:58:50 -0700
Subject: [PATCH 01/69] dtbindings: qcom_adm: Fix channel specifiers
Original patch from Andy Gross.
This patch removes the crci information from the dma
channel property. At least one client device requires
using more than one CRCI value for a channel. This does
not match the current binding and the crci information
needs to be removed.
Instead, the client device will provide this information
via other means.
Signed-off-by: Andy Gross <agross@codeaurora.org>
Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
---
Documentation/devicetree/bindings/dma/qcom_adm.txt | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
--- a/Documentation/devicetree/bindings/dma/qcom_adm.txt
+++ b/Documentation/devicetree/bindings/dma/qcom_adm.txt
@@ -4,8 +4,7 @@ Required properties:
- compatible: must contain "qcom,adm" for IPQ/APQ8064 and MSM8960
- reg: Address range for DMA registers
- interrupts: Should contain one interrupt shared by all channels
-- #dma-cells: must be <2>. First cell denotes the channel number. Second cell
- denotes CRCI (client rate control interface) flow control assignment.
+- #dma-cells: must be <1>. First cell denotes the channel number.
- clocks: Should contain the core clock and interface clock.
- clock-names: Must contain "core" for the core clock and "iface" for the
interface clock.
@@ -22,7 +21,7 @@ Example:
compatible = "qcom,adm";
reg = <0x18300000 0x100000>;
interrupts = <0 170 0>;
- #dma-cells = <2>;
+ #dma-cells = <1>;
clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>;
clock-names = "core", "iface";
@@ -35,15 +34,12 @@ Example:
qcom,ee = <0>;
};
-DMA clients must use the format descripted in the dma.txt file, using a three
+DMA clients must use the format descripted in the dma.txt file, using a two
cell specifier for each channel.
-Each dmas request consists of 3 cells:
+Each dmas request consists of two cells:
1. phandle pointing to the DMA controller
2. channel number
- 3. CRCI assignment, if applicable. If no CRCI flow control is required, use 0.
- The CRCI is used for flow control. It identifies the peripheral device that
- is the source/destination for the transferred data.
Example:
@@ -55,7 +51,7 @@ Example:
cs-gpios = <&qcom_pinmux 20 0>;
- dmas = <&adm_dma 6 9>,
- <&adm_dma 5 10>;
+ dmas = <&adm_dma 6>,
+ <&adm_dma 5>;
dma-names = "rx", "tx";
};

View File

@ -0,0 +1,29 @@
From 48051ece78136e4235a2415a52797db56f8a4478 Mon Sep 17 00:00:00 2001
From: Mathieu Olivari <mathieu@codeaurora.org>
Date: Tue, 21 Apr 2015 19:09:07 -0700
Subject: [PATCH 33/69] ARM: qcom: automatically select PCI_DOMAINS if PCI is
enabled
If multiple PCIe devices are present in the system, the kernel will
panic at boot time when trying to scan the PCI buses. This happens on
IPQ806x based platforms, which has 3 PCIe ports.
Enabling this option allows the kernel to assign the pci-domains
according to the device-tree content. This allows multiple PCIe
controllers to coexist in the system.
Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
---
arch/arm/mach-qcom/Kconfig | 1 +
1 file changed, 1 insertion(+)
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -7,6 +7,7 @@ menuconfig ARCH_QCOM
select ARM_AMBA
select PINCTRL
select QCOM_SCM if SMP
+ select PCI_DOMAINS if PCI
help
Support for Qualcomm's devicetree based systems.

View File

@ -0,0 +1,62 @@
From fa71139b55e114aa8c3c4823ff8ee7d49ee810d4 Mon Sep 17 00:00:00 2001
From: Mathieu Olivari <mathieu@codeaurora.org>
Date: Wed, 29 Apr 2015 15:21:46 -0700
Subject: [PATCH 60/69] HACK: arch: arm: force ZRELADDR on arch-qcom
ARCH_QCOM is using the ARCH_MULTIPLATFORM option, as now recommended
on most ARM architectures. This automatically calculate ZRELADDR by
masking PHYS_OFFSET with 0xf8000000.
However, on IPQ806x, the first ~20MB of RAM is reserved for the hardware
network accelerators, and the bootloader removes this section from the
layout passed from the ATAGS (when used).
For newer bootloader, when DT is used, this is not a problem, we just
reserve this memory in the device tree. But if the bootloader doesn't
have DT support, then ATAGS have to be used. In this case, the ARM
decompressor will position the kernel in this low mem, which will not be
in the RAM section mapped by the bootloader, which means the kernel will
freeze in the middle of the boot process trying to map the memory.
As a work around, this patch allows disabling AUTO_ZRELADDR when
ARCH_QCOM is selected. It makes the zImage usage possible on bootloaders
which don't support device-tree, which is the case on certain early
IPQ806x based designs.
Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
---
arch/arm/Kconfig | 2 +-
arch/arm/Makefile | 2 ++
arch/arm/mach-qcom/Makefile.boot | 1 +
3 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/mach-qcom/Makefile.boot
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -322,7 +322,7 @@ config ARCH_MULTIPLATFORM
select ARCH_SELECT_MEMORY_MODEL
select ARM_HAS_SG_CHAIN
select ARM_PATCH_PHYS_VIRT
- select AUTO_ZRELADDR
+ select AUTO_ZRELADDR if !ARCH_QCOM
select TIMER_OF
select COMMON_CLK
select GENERIC_CLOCKEVENTS
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -251,9 +251,11 @@ MACHINE := arch/arm/mach-$(word 1,$(mac
else
MACHINE :=
endif
+ifeq ($(CONFIG_ARCH_QCOM),)
ifeq ($(CONFIG_ARCH_MULTIPLATFORM),y)
MACHINE :=
endif
+endif
machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y))
platdirs := $(patsubst %,arch/arm/plat-%/,$(sort $(plat-y)))
--- /dev/null
+++ b/arch/arm/mach-qcom/Makefile.boot
@@ -0,0 +1 @@
+zreladdr-y+= 0x42208000

View File

@ -0,0 +1,21 @@
From 4d8e29642661397a339ac3485f212c6360445421 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 9 Mar 2017 09:33:32 +0100
Subject: [PATCH 65/69] arm: override compiler flags
Signed-off-by: John Crispin <john@phrozen.org>
---
arch/arm/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -61,7 +61,7 @@ KBUILD_CFLAGS += $(call cc-option,-fno-i
# macro, but instead defines a whole series of macros which makes
# testing for a specific architecture or later rather impossible.
arch-$(CONFIG_CPU_32v7M) =-D__LINUX_ARM_ARCH__=7 -march=armv7-m
-arch-$(CONFIG_CPU_32v7) =-D__LINUX_ARM_ARCH__=7 -march=armv7-a
+arch-$(CONFIG_CPU_32v7) =-D__LINUX_ARM_ARCH__=7 -mcpu=cortex-a15
arch-$(CONFIG_CPU_32v6) =-D__LINUX_ARM_ARCH__=6 -march=armv6
# Only override the compiler option if ARMv6. The ARMv6K extensions are
# always available in ARMv7

View File

@ -0,0 +1,210 @@
From 71270226b14733a4b1f2cde58ea9265caa50b38d Mon Sep 17 00:00:00 2001
From: Adrian Panella <ianchi74@outlook.com>
Date: Thu, 9 Mar 2017 09:37:17 +0100
Subject: [PATCH 67/69] generic: Mangle bootloader's kernel arguments
The command-line arguments provided by the boot loader will be
appended to a new device tree property: bootloader-args.
If there is a property "append-rootblock" in DT under /chosen
and a root= option in bootloaders command line it will be parsed
and added to DT bootargs with the form: <append-rootblock>XX.
Only command line ATAG will be processed, the rest of the ATAGs
sent by bootloader will be ignored.
This is usefull in dual boot systems, to get the current root partition
without afecting the rest of the system.
Signed-off-by: Adrian Panella <ianchi74@outlook.com>
---
arch/arm/Kconfig | 11 +++++
arch/arm/boot/compressed/atags_to_fdt.c | 72 ++++++++++++++++++++++++++++++++-
init/main.c | 16 ++++++++
3 files changed, 98 insertions(+), 1 deletion(-)
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1781,6 +1781,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN
The command-line arguments provided by the boot loader will be
appended to the the device tree bootargs property.
+config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE
+ bool "Append rootblock parsing bootloader's kernel arguments"
+ help
+ The command-line arguments provided by the boot loader will be
+ appended to a new device tree property: bootloader-args.
+ If there is a property "append-rootblock" in DT under /chosen
+ and a root= option in bootloaders command line it will be parsed
+ and added to DT bootargs with the form: <append-rootblock>XX.
+ Only command line ATAG will be processed, the rest of the ATAGs
+ sent by bootloader will be ignored.
+
endchoice
config CMDLINE
--- a/arch/arm/boot/compressed/atags_to_fdt.c
+++ b/arch/arm/boot/compressed/atags_to_fdt.c
@@ -5,6 +5,8 @@
#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND)
#define do_extend_cmdline 1
+#elif defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
+#define do_extend_cmdline 1
#else
#define do_extend_cmdline 0
#endif
@@ -69,6 +71,80 @@ static uint32_t get_cell_size(const void
return cell_size;
}
+#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
+/**
+ * taken from arch/x86/boot/string.c
+ * local_strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+static char *local_strstr(const char *s1, const char *s2)
+{
+ size_t l1, l2;
+
+ l2 = strlen(s2);
+ if (!l2)
+ return (char *)s1;
+ l1 = strlen(s1);
+ while (l1 >= l2) {
+ l1--;
+ if (!memcmp(s1, s2, l2))
+ return (char *)s1;
+ s1++;
+ }
+ return NULL;
+}
+
+static char *append_rootblock(char *dest, const char *str, int len, void *fdt)
+{
+ char *ptr, *end, *tmp;
+ char *root="root=";
+ char *find_rootblock;
+ int i, l;
+ const char *rootblock;
+
+ find_rootblock = getprop(fdt, "/chosen", "find-rootblock", &l);
+ if(!find_rootblock)
+ find_rootblock = root;
+
+ //ARM doesn't have __HAVE_ARCH_STRSTR, so it was copied from x86
+ ptr = local_strstr(str, find_rootblock);
+
+ if(!ptr)
+ return dest;
+
+ end = strchr(ptr, ' ');
+ end = end ? (end - 1) : (strchr(ptr, 0) - 1);
+
+ // Some boards ubi.mtd=XX,ZZZZ, so let's check for '," too.
+ tmp = strchr(ptr, ',');
+
+ if(tmp)
+ end = end < tmp ? end : tmp - 1;
+
+ //find partition number (assumes format root=/dev/mtdXX | /dev/mtdblockXX | yy:XX | ubi.mtd=XX,ZZZZ )
+ for( i = 0; end >= ptr && *end >= '0' && *end <= '9'; end--, i++);
+ ptr = end + 1;
+
+ /* if append-rootblock property is set use it to append to command line */
+ rootblock = getprop(fdt, "/chosen", "append-rootblock", &l);
+ if(rootblock != NULL) {
+ if(*dest != ' ') {
+ *dest = ' ';
+ dest++;
+ len++;
+ }
+ if (len + l + i <= COMMAND_LINE_SIZE) {
+ memcpy(dest, rootblock, l);
+ dest += l - 1;
+ memcpy(dest, ptr, i);
+ dest += i;
+ }
+ }
+ return dest;
+}
+#endif
+
static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
{
char cmdline[COMMAND_LINE_SIZE];
@@ -88,12 +164,21 @@ static void merge_fdt_bootargs(void *fdt
/* and append the ATAG_CMDLINE */
if (fdt_cmdline) {
+
+#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
+ //save original bootloader args
+ //and append ubi.mtd with root partition number to current cmdline
+ setprop_string(fdt, "/chosen", "bootloader-args", fdt_cmdline);
+ ptr = append_rootblock(ptr, fdt_cmdline, len, fdt);
+
+#else
len = strlen(fdt_cmdline);
if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) {
*ptr++ = ' ';
memcpy(ptr, fdt_cmdline, len);
ptr += len;
}
+#endif
}
*ptr = '\0';
@@ -168,7 +253,9 @@ int atags_to_fdt(void *atag_list, void *
else
setprop_string(fdt, "/chosen", "bootargs",
atag->u.cmdline.cmdline);
- } else if (atag->hdr.tag == ATAG_MEM) {
+ }
+#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE
+ else if (atag->hdr.tag == ATAG_MEM) {
if (memcount >= sizeof(mem_reg_property)/4)
continue;
if (!atag->u.mem.size)
@@ -212,6 +299,10 @@ int atags_to_fdt(void *atag_list, void *
setprop(fdt, "/memory", "reg", mem_reg_property,
4 * memcount * memsize);
}
+#else
+
+ }
+#endif
return fdt_pack(fdt);
}
--- a/init/main.c
+++ b/init/main.c
@@ -110,6 +110,10 @@
#include <kunit/test.h>
+#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
+#include <linux/of.h>
+#endif
+
static int kernel_init(void *);
extern void init_IRQ(void);
@@ -906,6 +910,18 @@ asmlinkage __visible void __init __no_sa
pr_notice("Kernel command line: %s\n", saved_command_line);
/* parameters may set static keys */
jump_label_init();
+
+#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
+ //Show bootloader's original command line for reference
+ if(of_chosen) {
+ const char *prop = of_get_property(of_chosen, "bootloader-args", NULL);
+ if(prop)
+ pr_notice("Bootloader command line (ignored): %s\n", prop);
+ else
+ pr_notice("Bootloader command line not present\n");
+ }
+#endif
+
parse_early_param();
after_dashes = parse_args("Booting kernel",
static_command_line, __start___param,

View File

@ -0,0 +1,42 @@
From 8f68331e14dff9a101f2d0e1d6bec84a031f27ee Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 9 Mar 2017 11:03:18 +0100
Subject: [PATCH 69/69] arm: boot: add dts files
Signed-off-by: John Crispin <john@phrozen.org>
---
arch/arm/boot/dts/Makefile | 8 ++++++++
1 file changed, 8 insertions(+)
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -907,8 +907,29 @@ dtb-$(CONFIG_ARCH_QCOM) += \
qcom-ipq4019-ap.dk04.1-c3.dtb \
qcom-ipq4019-ap.dk07.1-c1.dtb \
qcom-ipq4019-ap.dk07.1-c2.dtb \
+ qcom-ipq8062-wg2600hp3.dtb \
qcom-ipq8064-ap148.dtb \
qcom-ipq8064-rb3011.dtb \
+ qcom-ipq8064-c2600.dtb \
+ qcom-ipq8064-d7800.dtb \
+ qcom-ipq8064-db149.dtb \
+ qcom-ipq8064-ap161.dtb \
+ qcom-ipq8064-ea7500-v1.dtb \
+ qcom-ipq8064-ea8500.dtb \
+ qcom-ipq8064-g10.dtb \
+ qcom-ipq8064-r7500.dtb \
+ qcom-ipq8064-r7500v2.dtb \
+ qcom-ipq8064-unifi-ac-hd.dtb \
+ qcom-ipq8064-wg2600hp.dtb \
+ qcom-ipq8064-wpq864.dtb \
+ qcom-ipq8064-wxr-2533dhp.dtb \
+ qcom-ipq8065-nbg6817.dtb \
+ qcom-ipq8065-r7800.dtb \
+ qcom-ipq8065-rt4230w-rev6.dtb \
+ qcom-ipq8065-xr500.dtb \
+ qcom-ipq8068-ecw5410.dtb \
+ qcom-ipq8068-mr42.dtb \
+ qcom-ipq8068-mr52.dtb \
qcom-msm8660-surf.dtb \
qcom-msm8960-cdp.dtb \
qcom-msm8974-fairphone-fp2.dtb \

View File

@ -0,0 +1,10 @@
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -1275,6 +1275,7 @@ static const struct of_device_id qcom_sc
SCM_HAS_BUS_CLK)
},
{ .compatible = "qcom,scm-ipq4019" },
+ { .compatible = "qcom,scm-ipq806x" },
{ .compatible = "qcom,scm-msm8660", .data = (void *) SCM_HAS_CORE_CLK },
{ .compatible = "qcom,scm-msm8960", .data = (void *) SCM_HAS_CORE_CLK },
{ .compatible = "qcom,scm-msm8916", .data = (void *)(SCM_HAS_CORE_CLK |

View File

@ -0,0 +1,220 @@
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -20,7 +20,7 @@
#address-cells = <1>;
#size-cells = <0>;
- cpu@0 {
+ cpu0: cpu@0 {
compatible = "qcom,krait";
enable-method = "qcom,kpss-acc-v1";
device_type = "cpu";
@@ -30,7 +30,7 @@
qcom,saw = <&saw0>;
};
- cpu@1 {
+ cpu1: cpu@1 {
compatible = "qcom,krait";
enable-method = "qcom,kpss-acc-v1";
device_type = "cpu";
@@ -67,7 +67,7 @@
no-map;
};
- smem@41000000 {
+ smem: smem@41000000 {
reg = <0x41000000 0x200000>;
no-map;
};
@@ -128,6 +128,7 @@
gpio-ranges = <&qcom_pinmux 0 0 69>;
#gpio-cells = <2>;
interrupt-controller;
+ #address-cells = <0>;
#interrupt-cells = <2>;
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
@@ -155,6 +156,7 @@
function = "pcie3_rst";
drive-strength = <12>;
bias-disable;
+ output-low;
};
};
@@ -190,6 +192,7 @@
intc: interrupt-controller@2000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
+ #address-cells = <0>;
#interrupt-cells = <3>;
reg = <0x02000000 0x1000>,
<0x02002000 0x1000>;
@@ -219,21 +222,23 @@
acc0: clock-controller@2088000 {
compatible = "qcom,kpss-acc-v1";
reg = <0x02088000 0x1000>, <0x02008000 0x1000>;
+ clock-output-names = "acpu0_aux";
};
acc1: clock-controller@2098000 {
compatible = "qcom,kpss-acc-v1";
reg = <0x02098000 0x1000>, <0x02008000 0x1000>;
+ clock-output-names = "acpu1_aux";
};
saw0: regulator@2089000 {
- compatible = "qcom,saw2";
+ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon";
reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
regulator;
};
saw1: regulator@2099000 {
- compatible = "qcom,saw2";
+ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon";
reg = <0x02099000 0x1000>, <0x02009000 0x1000>;
regulator;
};
@@ -251,7 +256,7 @@
syscon-tcsr = <&tcsr>;
- serial@12490000 {
+ gsbi2_serial: serial@12490000 {
compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
reg = <0x12490000 0x1000>,
<0x12480000 0x1000>;
@@ -261,7 +266,7 @@
status = "disabled";
};
- i2c@124a0000 {
+ gsbi2_i2c: i2c@124a0000 {
compatible = "qcom,i2c-qup-v1.1.1";
reg = <0x124a0000 0x1000>;
interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>;
@@ -326,7 +331,7 @@
syscon-tcsr = <&tcsr>;
- serial@1a240000 {
+ gsbi5_serial: serial@1a240000 {
compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
reg = <0x1a240000 0x1000>,
<0x1a200000 0x1000>;
@@ -397,7 +402,7 @@
status = "disabled";
};
- sata@29000000 {
+ sata: sata@29000000 {
compatible = "qcom,ipq806x-ahci", "generic-ahci";
reg = <0x29000000 0x180>;
@@ -430,13 +435,35 @@
reg = <0x00700000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
+
+ tsens_calib: calib@400 {
+ reg = <0x400 0xb>;
+ };
+ tsens_backup: backup@410 {
+ reg = <0x410 0xb>;
+ };
+ speedbin_efuse: speedbin@0c0 {
+ reg = <0x0c0 0x4>;
+ };
};
gcc: clock-controller@900000 {
- compatible = "qcom,gcc-ipq8064";
+ compatible = "qcom,gcc-ipq8064", "syscon";
reg = <0x00900000 0x4000>;
#clock-cells = <1>;
#reset-cells = <1>;
+ #power-domain-cells = <1>;
+
+ tsens: thermal-sensor@900000 {
+ compatible = "qcom,ipq8064-tsens";
+
+ nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
+ interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "uplow";
+ #thermal-sensor-cells = <1>;
+ #qcom,sensors = <11>;
+ };
};
tcsr: syscon@1a400000 {
@@ -622,7 +649,7 @@
gmac0: ethernet@37000000 {
device_type = "network";
- compatible = "qcom,ipq806x-gmac";
+ compatible = "qcom,ipq806x-gmac", "snps,dwmac";
reg = <0x37000000 0x200000>;
interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
@@ -645,7 +672,7 @@
gmac1: ethernet@37200000 {
device_type = "network";
- compatible = "qcom,ipq806x-gmac";
+ compatible = "qcom,ipq806x-gmac", "snps,dwmac";
reg = <0x37200000 0x200000>;
interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
@@ -668,7 +695,7 @@
gmac2: ethernet@37400000 {
device_type = "network";
- compatible = "qcom,ipq806x-gmac";
+ compatible = "qcom,ipq806x-gmac", "snps,dwmac";
reg = <0x37400000 0x200000>;
interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
@@ -691,7 +718,7 @@
gmac3: ethernet@37600000 {
device_type = "network";
- compatible = "qcom,ipq806x-gmac";
+ compatible = "qcom,ipq806x-gmac", "snps,dwmac";
reg = <0x37600000 0x200000>;
interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
@@ -740,13 +767,13 @@
qcom,ee = <0>;
};
- amba {
- compatible = "simple-bus";
+ amba: amba {
+ compatible = "arm,amba-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
- sdcc@12400000 {
+ sdcc1: sdcc@12400000 {
status = "disabled";
compatible = "arm,pl18x", "arm,primecell";
arm,primecell-periphid = <0x00051180>;
@@ -760,13 +787,12 @@
non-removable;
cap-sd-highspeed;
cap-mmc-highspeed;
- mmc-ddr-1_8v;
vmmc-supply = <&vsdcc_fixed>;
dmas = <&sdcc1bam 2>, <&sdcc1bam 1>;
dma-names = "tx", "rx";
};
- sdcc@12180000 {
+ sdcc3: sdcc@12180000 {
compatible = "arm,pl18x", "arm,primecell";
arm,primecell-periphid = <0x00051180>;
status = "disabled";

View File

@ -0,0 +1,846 @@
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -8,6 +8,8 @@
#include <dt-bindings/reset/qcom,gcc-ipq806x.h>
#include <dt-bindings/soc/qcom,gsbi.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/mfd/qcom-rpm.h>
+#include <dt-bindings/clock/qcom,rpmcc.h>
/ {
#address-cells = <1>;
@@ -28,6 +30,16 @@
next-level-cache = <&L2>;
qcom,acc = <&acc0>;
qcom,saw = <&saw0>;
+ clocks = <&kraitcc 0>, <&kraitcc 4>;
+ clock-names = "cpu", "l2";
+ clock-latency = <100000>;
+ cpu-supply = <&smb208_s2a>;
+ operating-points-v2 = <&opp_table0>;
+ voltage-tolerance = <5>;
+ cooling-min-state = <0>;
+ cooling-max-state = <10>;
+ #cooling-cells = <2>;
+ cpu-idle-states = <&CPU_SPC>;
};
cpu1: cpu@1 {
@@ -38,14 +50,350 @@
next-level-cache = <&L2>;
qcom,acc = <&acc1>;
qcom,saw = <&saw1>;
+ clocks = <&kraitcc 1>, <&kraitcc 4>;
+ clock-names = "cpu", "l2";
+ clock-latency = <100000>;
+ cpu-supply = <&smb208_s2b>;
+ operating-points-v2 = <&opp_table0>;
+ voltage-tolerance = <5>;
+ cooling-min-state = <0>;
+ cooling-max-state = <10>;
+ #cooling-cells = <2>;
+ cpu-idle-states = <&CPU_SPC>;
+ };
+
+ idle-states {
+ CPU_SPC: spc {
+ compatible = "qcom,idle-state-spc";
+ status = "disabled";
+ entry-latency-us = <400>;
+ exit-latency-us = <900>;
+ min-residency-us = <3000>;
+ };
};
+ };
- L2: l2-cache {
- compatible = "cache";
- cache-level = <2>;
+ opp_table_l2: opp_table_l2 {
+ compatible = "operating-points-v2";
+
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ opp-microvolt = <1100000>;
+ clock-latency-ns = <100000>;
+ opp-level = <0>;
+ };
+
+ opp-1000000000 {
+ opp-hz = /bits/ 64 <1000000000>;
+ opp-microvolt = <1100000>;
+ clock-latency-ns = <100000>;
+ opp-level = <1>;
+ };
+
+ opp-1200000000 {
+ opp-hz = /bits/ 64 <1200000000>;
+ opp-microvolt = <1150000>;
+ clock-latency-ns = <100000>;
+ opp-level = <2>;
+ };
+ };
+
+ opp_table0: opp_table0 {
+ compatible = "operating-points-v2-kryo-cpu";
+ nvmem-cells = <&speedbin_efuse>;
+
+ /*
+ * Voltage thresholds are <target min max>
+ */
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1000000 950000 1050000>;
+ opp-microvolt-speed0-pvs1-v0 = <925000 878750 971250>;
+ opp-microvolt-speed0-pvs2-v0 = <875000 831250 918750>;
+ opp-microvolt-speed0-pvs3-v0 = <800000 760000 840000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <0>;
+ };
+
+ opp-600000000 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1050000 997500 1102500>;
+ opp-microvolt-speed0-pvs1-v0 = <975000 926250 1023750>;
+ opp-microvolt-speed0-pvs2-v0 = <925000 878750 971250>;
+ opp-microvolt-speed0-pvs3-v0 = <850000 807500 892500>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <1>;
+ };
+
+ opp-800000000 {
+ opp-hz = /bits/ 64 <800000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1100000 1045000 1155000>;
+ opp-microvolt-speed0-pvs1-v0 = <1025000 973750 1076250>;
+ opp-microvolt-speed0-pvs2-v0 = <995000 945250 1044750>;
+ opp-microvolt-speed0-pvs3-v0 = <900000 855000 945000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <1>;
+ };
+
+ opp-1000000000 {
+ opp-hz = /bits/ 64 <1000000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1150000 1092500 1207500>;
+ opp-microvolt-speed0-pvs1-v0 = <1075000 1021250 1128750>;
+ opp-microvolt-speed0-pvs2-v0 = <1025000 973750 1076250>;
+ opp-microvolt-speed0-pvs3-v0 = <950000 902500 997500>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <1>;
+ };
+
+ opp-1200000000 {
+ opp-hz = /bits/ 64 <1200000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1200000 1140000 1260000>;
+ opp-microvolt-speed0-pvs1-v0 = <1125000 1068750 1181250>;
+ opp-microvolt-speed0-pvs2-v0 = <1075000 1021250 1128750>;
+ opp-microvolt-speed0-pvs3-v0 = <1000000 950000 1050000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <2>;
+ };
+
+ opp-1400000000 {
+ opp-hz = /bits/ 64 <1400000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1250000 1187500 1312500>;
+ opp-microvolt-speed0-pvs1-v0 = <1175000 1116250 1233750>;
+ opp-microvolt-speed0-pvs2-v0 = <1125000 1068750 1181250>;
+ opp-microvolt-speed0-pvs3-v0 = <1050000 997500 1102500>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <2>;
};
};
+ thermal-zones {
+ tsens_tz_sensor0 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens 0>;
+
+ trips {
+ cpu-critical {
+ temperature = <105000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+
+ cpu-hot {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ tsens_tz_sensor1 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens 1>;
+
+ trips {
+ cpu-critical {
+ temperature = <105000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+
+ cpu-hot {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ tsens_tz_sensor2 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens 2>;
+
+ trips {
+ cpu-critical {
+ temperature = <105000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+
+ cpu-hot {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ tsens_tz_sensor3 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens 3>;
+
+ trips {
+ cpu-critical {
+ temperature = <105000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+
+ cpu-hot {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ tsens_tz_sensor4 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens 4>;
+
+ trips {
+ cpu-critical {
+ temperature = <105000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+
+ cpu-hot {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ tsens_tz_sensor5 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens 5>;
+
+ trips {
+ cpu-critical {
+ temperature = <105000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+
+ cpu-hot {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ tsens_tz_sensor6 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens 6>;
+
+ trips {
+ cpu-critical {
+ temperature = <105000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+
+ cpu-hot {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ tsens_tz_sensor7 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens 7>;
+
+ trips {
+ cpu-critical {
+ temperature = <105000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+
+ cpu-hot {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ tsens_tz_sensor8 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens 8>;
+
+ trips {
+ cpu-critical {
+ temperature = <105000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+
+ cpu-hot {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ tsens_tz_sensor9 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens 9>;
+
+ trips {
+ cpu-critical {
+ temperature = <105000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+
+ cpu-hot {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+
+ tsens_tz_sensor10 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens 10>;
+
+ trips {
+ cpu-critical {
+ temperature = <105000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+
+ cpu-hot {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ };
+ };
+ };
+
memory {
device_type = "memory";
reg = <0x0 0x0>;
@@ -93,6 +441,15 @@
};
};
+ fab-scaling {
+ compatible = "qcom,fab-scaling";
+ clocks = <&rpmcc RPM_APPS_FABRIC_A_CLK>, <&rpmcc RPM_EBI1_A_CLK>;
+ clock-names = "apps-fab-clk", "ddr-fab-clk";
+ fab_freq_high = <533000000>;
+ fab_freq_nominal = <400000000>;
+ cpu_freq_threshold = <1000000000>;
+ };
+
firmware {
scm {
compatible = "qcom,scm-ipq806x", "qcom,scm";
@@ -120,6 +477,78 @@
reg-names = "lpass-lpaif";
};
+ L2: l2-cache {
+ compatible = "qcom,krait-cache", "cache";
+ cache-level = <2>;
+ qcom,saw = <&saw_l2>;
+
+ clocks = <&kraitcc 4>;
+ clock-names = "l2";
+ l2-supply = <&smb208_s1a>;
+ operating-points-v2 = <&opp_table_l2>;
+ };
+
+ rpm: rpm@108000 {
+ compatible = "qcom,rpm-ipq8064";
+ reg = <0x108000 0x1000>;
+ qcom,ipc = <&l2cc 0x8 2>;
+
+ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ack", "err", "wakeup";
+
+ clocks = <&gcc RPM_MSG_RAM_H_CLK>;
+ clock-names = "ram";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rpmcc: clock-controller {
+ compatible = "qcom,rpmcc-ipq806x", "qcom,rpmcc";
+ #clock-cells = <1>;
+ };
+
+ regulators {
+ compatible = "qcom,rpm-smb208-regulators";
+
+ smb208_s1a: s1a {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1150000>;
+
+ qcom,switch-mode-frequency = <1200000>;
+ };
+
+ smb208_s1b: s1b {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1150000>;
+
+ qcom,switch-mode-frequency = <1200000>;
+ };
+
+ smb208_s2a: s2a {
+ regulator-min-microvolt = < 800000>;
+ regulator-max-microvolt = <1250000>;
+
+ qcom,switch-mode-frequency = <1200000>;
+ };
+
+ smb208_s2b: s2b {
+ regulator-min-microvolt = < 800000>;
+ regulator-max-microvolt = <1250000>;
+
+ qcom,switch-mode-frequency = <1200000>;
+ };
+ };
+ };
+
+ rng@1a500000 {
+ compatible = "qcom,prng";
+ reg = <0x1a500000 0x200>;
+ clocks = <&gcc PRNG_CLK>;
+ clock-names = "core";
+ };
+
qcom_pinmux: pinmux@800000 {
compatible = "qcom,ipq8064-pinctrl";
reg = <0x800000 0x4000>;
@@ -160,6 +589,15 @@
};
};
+ i2c4_pins: i2c4_pinmux {
+ mux {
+ pins = "gpio12", "gpio13";
+ function = "gsbi4";
+ drive-strength = <12>;
+ bias-disable;
+ };
+ };
+
spi_pins: spi_pins {
mux {
pins = "gpio18", "gpio19", "gpio21";
@@ -169,6 +607,53 @@
};
};
+ nand_pins: nand_pins {
+ disable {
+ pins = "gpio34", "gpio35", "gpio36",
+ "gpio37", "gpio38";
+ function = "nand";
+ drive-strength = <10>;
+ bias-disable;
+ };
+
+ pullups {
+ pins = "gpio39";
+ function = "nand";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+
+ hold {
+ pins = "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45",
+ "gpio46", "gpio47";
+ function = "nand";
+ drive-strength = <10>;
+ bias-bus-hold;
+ };
+ };
+
+ mdio0_pins: mdio0_pins {
+ mux {
+ pins = "gpio0", "gpio1";
+ function = "mdio";
+ drive-strength = <8>;
+ bias-disable;
+ };
+ };
+
+ rgmii2_pins: rgmii2_pins {
+ mux {
+ pins = "gpio27", "gpio28", "gpio29",
+ "gpio30", "gpio31", "gpio32",
+ "gpio51", "gpio52", "gpio59",
+ "gpio60", "gpio61", "gpio62";
+ function = "rgmii2";
+ drive-strength = <8>;
+ bias-disable;
+ };
+ };
+
leds_pins: leds_pins {
mux {
pins = "gpio7", "gpio8", "gpio9",
@@ -231,6 +716,17 @@
clock-output-names = "acpu1_aux";
};
+ l2cc: clock-controller@2011000 {
+ compatible = "qcom,kpss-gcc", "syscon";
+ reg = <0x2011000 0x1000>;
+ clock-output-names = "acpu_l2_aux";
+ };
+
+ kraitcc: clock-controller {
+ compatible = "qcom,krait-cc-v1";
+ #clock-cells = <1>;
+ };
+
saw0: regulator@2089000 {
compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon";
reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
@@ -243,6 +739,52 @@
regulator;
};
+ saw_l2: regulator@02012000 {
+ compatible = "qcom,saw2", "syscon";
+ reg = <0x02012000 0x1000>;
+ regulator;
+ };
+
+ sic_non_secure: sic-non-secure@12100000 {
+ compatible = "syscon";
+ reg = <0x12100000 0x10000>;
+ };
+
+ gsbi1: gsbi@12440000 {
+ compatible = "qcom,gsbi-v1.0.0";
+ cell-index = <1>;
+ reg = <0x12440000 0x100>;
+ clocks = <&gcc GSBI1_H_CLK>;
+ clock-names = "iface";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ status = "disabled";
+
+ syscon-tcsr = <&tcsr>;
+
+ gsbi1_serial: serial@12450000 {
+ compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
+ reg = <0x12450000 0x100>,
+ <0x12400000 0x03>;
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GSBI1_UART_CLK>, <&gcc GSBI1_H_CLK>;
+ clock-names = "core", "iface";
+ status = "disabled";
+ };
+
+ gsbi1_i2c: i2c@12460000 {
+ compatible = "qcom,i2c-qup-v1.1.1";
+ reg = <0x12460000 0x1000>;
+ interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GSBI1_QUP_CLK>, <&gcc GSBI1_H_CLK>;
+ clock-names = "core", "iface";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ };
+
gsbi2: gsbi@12480000 {
compatible = "qcom,gsbi-v1.0.0";
cell-index = <2>;
@@ -368,6 +910,33 @@
};
};
+ gsbi6: gsbi@16500000 {
+ status = "disabled";
+ compatible = "qcom,gsbi-v1.0.0";
+ cell-index = <6>;
+ reg = <0x16500000 0x100>;
+ clocks = <&gcc GSBI6_H_CLK>;
+ clock-names = "iface";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ syscon-tcsr = <&tcsr>;
+
+ gsbi6_i2c: i2c@16580000 {
+ compatible = "qcom,i2c-qup-v1.1.1";
+ reg = <0x16580000 0x1000>;
+ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&gcc GSBI6_QUP_CLK>, <&gcc GSBI6_H_CLK>;
+ clock-names = "core", "iface";
+ status = "disabled";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
gsbi7: gsbi@16600000 {
status = "disabled";
compatible = "qcom,gsbi-v1.0.0";
@@ -389,6 +958,19 @@
clock-names = "core", "iface";
status = "disabled";
};
+
+ gsbi7_i2c: i2c@16680000 {
+ compatible = "qcom,i2c-qup-v1.1.1";
+ reg = <0x16680000 0x1000>;
+ interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&gcc GSBI7_QUP_CLK>, <&gcc GSBI7_H_CLK>;
+ clock-names = "core", "iface";
+ status = "disabled";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
};
sata_phy: sata-phy@1b400000 {
@@ -478,6 +1060,95 @@
#reset-cells = <1>;
};
+ sfpb_mutex_block: syscon@1200600 {
+ compatible = "syscon";
+ reg = <0x01200600 0x100>;
+ };
+
+ hs_phy_0: hs_phy_0 {
+ compatible = "qcom,ipq806x-usb-phy-hs";
+ reg = <0x110f8800 0x30>;
+ clocks = <&gcc USB30_0_UTMI_CLK>;
+ clock-names = "ref";
+ #phy-cells = <0>;
+ };
+
+ ss_phy_0: ss_phy_0 {
+ compatible = "qcom,ipq806x-usb-phy-ss";
+ reg = <0x110f8830 0x30>;
+ clocks = <&gcc USB30_0_MASTER_CLK>;
+ clock-names = "ref";
+ #phy-cells = <0>;
+ };
+
+ usb3_0: usb3@110f8800 {
+ compatible = "qcom,dwc3", "syscon";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x110f8800 0x8000>;
+ clocks = <&gcc USB30_0_MASTER_CLK>;
+ clock-names = "core";
+
+ ranges;
+
+ resets = <&gcc USB30_0_MASTER_RESET>;
+ reset-names = "master";
+
+ status = "disabled";
+
+ dwc3_0: dwc3@11000000 {
+ compatible = "snps,dwc3";
+ reg = <0x11000000 0xcd00>;
+ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&hs_phy_0>, <&ss_phy_0>;
+ phy-names = "usb2-phy", "usb3-phy";
+ dr_mode = "host";
+ snps,dis_u3_susphy_quirk;
+ };
+ };
+
+ hs_phy_1: hs_phy_1 {
+ compatible = "qcom,ipq806x-usb-phy-hs";
+ reg = <0x100f8800 0x30>;
+ clocks = <&gcc USB30_1_UTMI_CLK>;
+ clock-names = "ref";
+ #phy-cells = <0>;
+ };
+
+ ss_phy_1: ss_phy_1 {
+ compatible = "qcom,ipq806x-usb-phy-ss";
+ reg = <0x100f8830 0x30>;
+ clocks = <&gcc USB30_1_MASTER_CLK>;
+ clock-names = "ref";
+ #phy-cells = <0>;
+ };
+
+ usb3_1: usb3@100f8800 {
+ compatible = "qcom,dwc3", "syscon";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x100f8800 0x8000>;
+ clocks = <&gcc USB30_1_MASTER_CLK>;
+ clock-names = "core";
+
+ ranges;
+
+ resets = <&gcc USB30_1_MASTER_RESET>;
+ reset-names = "master";
+
+ status = "disabled";
+
+ dwc3_1: dwc3@10000000 {
+ compatible = "snps,dwc3";
+ reg = <0x10000000 0xcd00>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&hs_phy_1>, <&ss_phy_1>;
+ phy-names = "usb2-phy", "usb3-phy";
+ dr_mode = "host";
+ snps,dis_u3_susphy_quirk;
+ };
+ };
+
pcie0: pci@1b500000 {
compatible = "qcom,pcie-ipq8064";
reg = <0x1b500000 0x1000
@@ -739,6 +1410,59 @@
status = "disabled";
};
+ adm_dma: dma@18300000 {
+ compatible = "qcom,adm";
+ reg = <0x18300000 0x100000>;
+ interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
+ #dma-cells = <1>;
+
+ clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>;
+ clock-names = "core", "iface";
+
+ resets = <&gcc ADM0_RESET>,
+ <&gcc ADM0_PBUS_RESET>,
+ <&gcc ADM0_C0_RESET>,
+ <&gcc ADM0_C1_RESET>,
+ <&gcc ADM0_C2_RESET>;
+ reset-names = "clk", "pbus", "c0", "c1", "c2";
+ qcom,ee = <0>;
+
+ status = "disabled";
+ };
+
+ nand_controller: nand-controller@1ac00000 {
+ compatible = "qcom,ipq806x-nand";
+ reg = <0x1ac00000 0x800>;
+
+ clocks = <&gcc EBI2_CLK>,
+ <&gcc EBI2_AON_CLK>;
+ clock-names = "core", "aon";
+
+ dmas = <&adm_dma 3>;
+ dma-names = "rxtx";
+ qcom,cmd-crci = <15>;
+ qcom,data-crci = <3>;
+
+ status = "disabled";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mdio0: mdio@37000000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,ipq8064-mdio", "syscon";
+ reg = <0x37000000 0x200000>;
+ resets = <&gcc GMAC_CORE1_RESET>;
+ reset-names = "stmmaceth";
+ clocks = <&gcc GMAC_CORE1_CLK>;
+ clock-names = "stmmaceth";
+
+ status = "disabled";
+ };
+
vsdcc_fixed: vsdcc-regulator {
compatible = "regulator-fixed";
regulator-name = "SDCC Power";
@@ -814,4 +1538,17 @@
};
};
};
+
+ sfpb_mutex: sfpb-mutex {
+ compatible = "qcom,sfpb-mutex";
+ syscon = <&sfpb_mutex_block 4 4>;
+
+ #hwlock-cells = <1>;
+ };
+
+ smem {
+ compatible = "qcom,smem";
+ memory-region = <&smem>;
+ hwlocks = <&sfpb_mutex 3>;
+ };
};

View File

@ -0,0 +1,89 @@
This uses upstream qcom-ipq8064-v1.0.dtsi and modifies it by patches
instead of keeping a local version.
We drop partitions, LEDs and keys from the file as we will implement
them differently anyway.
--- a/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi
@@ -42,16 +42,6 @@
#size-cells = <1>;
spi-max-frequency = <50000000>;
reg = <0>;
-
- partition@0 {
- label = "rootfs";
- reg = <0x0 0x1000000>;
- };
-
- partition@1 {
- label = "scratch";
- reg = <0x1000000 0x1000000>;
- };
};
};
};
@@ -64,64 +54,5 @@
ports-implemented = <0x1>;
status = "ok";
};
-
- gpio_keys {
- compatible = "gpio-keys";
- pinctrl-0 = <&buttons_pins>;
- pinctrl-names = "default";
-
- button@1 {
- label = "reset";
- linux,code = <KEY_RESTART>;
- gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>;
- linux,input-type = <1>;
- debounce-interval = <60>;
- };
- button@2 {
- label = "wps";
- linux,code = <KEY_WPS_BUTTON>;
- gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>;
- linux,input-type = <1>;
- debounce-interval = <60>;
- };
- };
-
- leds {
- compatible = "gpio-leds";
- pinctrl-0 = <&leds_pins>;
- pinctrl-names = "default";
-
- led@7 {
- label = "led_usb1";
- gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>;
- linux,default-trigger = "usbdev";
- default-state = "off";
- };
-
- led@8 {
- label = "led_usb3";
- gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>;
- linux,default-trigger = "usbdev";
- default-state = "off";
- };
-
- led@9 {
- label = "status_led_fail";
- gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>;
- default-state = "off";
- };
-
- led@26 {
- label = "sata_led";
- gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>;
- default-state = "off";
- };
-
- led@53 {
- label = "status_led_pass";
- gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>;
- default-state = "off";
- };
- };
};
};

View File

@ -0,0 +1,14 @@
This uses upstream qcom-ipq8064-v1.0.dtsi and modifies it by patches
instead of keeping a local version. This patch adds our local adjustments
for the (local) additional contents of qcom-ipq8064.dtsi
--- a/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi
@@ -56,3 +56,7 @@
};
};
};
+
+&CPU_SPC {
+ status = "okay";
+};

View File

@ -0,0 +1,145 @@
--- a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts
+++ b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts
@@ -24,73 +24,6 @@
device_type = "memory";
};
- mdio0: mdio-0 {
- status = "okay";
- compatible = "virtual,mdio-gpio";
- gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH>,
- <&qcom_pinmux 0 GPIO_ACTIVE_HIGH>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- pinctrl-0 = <&mdio0_pins>;
- pinctrl-names = "default";
-
- switch0: switch@10 {
- compatible = "qca,qca8337";
- #address-cells = <1>;
- #size-cells = <0>;
-
- dsa,member = <0 0>;
-
- pinctrl-0 = <&sw0_reset_pin>;
- pinctrl-names = "default";
-
- reset-gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>;
- reg = <0x10>;
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- switch0cpu: port@0 {
- reg = <0>;
- label = "cpu";
- ethernet = <&gmac0>;
- phy-mode = "rgmii-id";
- fixed-link {
- speed = <1000>;
- full-duplex;
- };
- };
-
- port@1 {
- reg = <1>;
- label = "sw1";
- };
-
- port@2 {
- reg = <2>;
- label = "sw2";
- };
-
- port@3 {
- reg = <3>;
- label = "sw3";
- };
-
- port@4 {
- reg = <4>;
- label = "sw4";
- };
-
- port@5 {
- reg = <5>;
- label = "sw5";
- };
- };
- };
- };
-
mdio1: mdio-1 {
status = "okay";
compatible = "virtual,mdio-gpio";
@@ -216,6 +149,68 @@
};
};
+&mdio0 {
+ status = "okay";
+
+ pinctrl-0 = <&mdio0_pins>;
+ pinctrl-names = "default";
+
+ switch0: switch@10 {
+ compatible = "qca,qca8337";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dsa,member = <0 0>;
+
+ pinctrl-0 = <&sw0_reset_pin>;
+ pinctrl-names = "default";
+
+ reset-gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>;
+ reg = <0x10>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ switch0cpu: port@0 {
+ reg = <0>;
+ label = "cpu";
+ ethernet = <&gmac0>;
+ phy-mode = "rgmii-id";
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "sw1";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "sw2";
+ };
+
+ port@3 {
+ reg = <3>;
+ label = "sw3";
+ };
+
+ port@4 {
+ reg = <4>;
+ label = "sw4";
+ };
+
+ port@5 {
+ reg = <5>;
+ label = "sw5";
+ };
+ };
+ };
+};
+
&gmac0 {
status = "okay";

View File

@ -0,0 +1,51 @@
From a206d4061f1cc2c5cd17ee45c53a0ba711e48e6d Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sun, 7 Feb 2021 16:42:52 +0100
Subject: [PATCH 3/3] drivers: cpufreq: qcom-cpufreq-nvmem: support specific
cpufreq driver
Add support for specific cpufreq driver for qcom-cpufreq-nvmem driver.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/cpufreq/qcom-cpufreq-nvmem.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
@@ -52,6 +52,7 @@ struct qcom_cpufreq_match_data {
char **pvs_name,
struct qcom_cpufreq_drv *drv);
const char **genpd_names;
+ const char *cpufreq_driver;
};
struct qcom_cpufreq_drv {
@@ -250,6 +251,7 @@ static const struct qcom_cpufreq_match_d
static const struct qcom_cpufreq_match_data match_data_krait = {
.get_version = qcom_cpufreq_krait_name_version,
+ .cpufreq_driver = "krait-cpufreq",
};
static const char *qcs404_genpd_names[] = { "cpr", NULL };
@@ -385,6 +387,19 @@ static int qcom_cpufreq_probe(struct pla
}
}
+ if (drv->data->cpufreq_driver) {
+ cpufreq_dt_pdev = platform_device_register_simple(
+ drv->data->cpufreq_driver, -1, NULL, 0);
+ if (!IS_ERR(cpufreq_dt_pdev)) {
+ platform_set_drvdata(pdev, drv);
+ return 0;
+ } else {
+ dev_err(cpu_dev,
+ "Failed to register dedicated %s cpufreq\n",
+ drv->data->cpufreq_driver);
+ }
+ }
+
cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
NULL, 0);
if (!IS_ERR(cpufreq_dt_pdev)) {

View File

@ -0,0 +1,99 @@
From 0af44917941cbfecdc86bb9bf05ff01d22a88973 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sun, 7 Feb 2021 16:52:56 +0100
Subject: [PATCH 1/4] ipq806x: gcc: add missing clk flag
Some flag are missing from the original code.
These clk can't be set using the protected-clock proprities as they
cause the malfunction of the serial interface.
These clks are needed for the rpm interface to work proprely or the
cpu regulators starts to fail as soon as they are disabled by the
kernel.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/clk/qcom/gcc-ipq806x.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -65,6 +65,7 @@ static struct clk_pll pll3 = {
.parent_names = (const char *[]){ "pxo" },
.num_parents = 1,
.ops = &clk_pll_ops,
+ .flags = CLK_IS_CRITICAL,
},
};
@@ -782,7 +783,7 @@ static struct clk_rcg gsbi4_qup_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
- .flags = CLK_SET_PARENT_GATE,
+ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED,
},
},
};
@@ -798,7 +799,7 @@ static struct clk_branch gsbi4_qup_clk =
.parent_names = (const char *[]){ "gsbi4_qup_src" },
.num_parents = 1,
.ops = &clk_branch_ops,
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
},
};
@@ -880,7 +881,7 @@ static struct clk_rcg gsbi6_qup_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
- .flags = CLK_SET_PARENT_GATE,
+ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED,
},
},
};
@@ -945,7 +946,7 @@ static struct clk_branch gsbi7_qup_clk =
.parent_names = (const char *[]){ "gsbi7_qup_src" },
.num_parents = 1,
.ops = &clk_branch_ops,
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
},
};
@@ -991,6 +992,7 @@ static struct clk_branch gsbi4_h_clk = {
.hw.init = &(struct clk_init_data){
.name = "gsbi4_h_clk",
.ops = &clk_branch_ops,
+ .flags = CLK_IGNORE_UNUSED,
},
},
};
@@ -1424,6 +1426,7 @@ static struct clk_rcg tsif_ref_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
},
}
};
@@ -2694,7 +2697,8 @@ static struct clk_dyn_rcg ubi32_core1_sr
.parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
.num_parents = 5,
.ops = &clk_dyn_rcg_ops,
- .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE |
+ CLK_IGNORE_UNUSED,
},
},
};
@@ -2747,7 +2751,8 @@ static struct clk_dyn_rcg ubi32_core2_sr
.parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
.num_parents = 5,
.ops = &clk_dyn_rcg_ops,
- .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE |
+ CLK_IGNORE_UNUSED,
},
},
};

View File

@ -0,0 +1,59 @@
From 3a5f1793c0bf4a6b536751886b0a44589fe05f35 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sun, 7 Feb 2021 17:00:07 +0100
Subject: [PATCH 2/4] ipq806x: lcc: add missing reset
Add missing reset for ipq806x lcc clk
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/clk/qcom/lcc-ipq806x.c | 8 ++++++++
include/dt-bindings/clock/qcom,lcc-ipq806x.h | 1 +
2 files changed, 9 insertions(+)
--- a/drivers/clk/qcom/lcc-ipq806x.c
+++ b/drivers/clk/qcom/lcc-ipq806x.c
@@ -12,6 +12,7 @@
#include <linux/of_device.h>
#include <linux/clk-provider.h>
#include <linux/regmap.h>
+#include <linux/reset-controller.h>
#include <dt-bindings/clock/qcom,lcc-ipq806x.h>
@@ -22,6 +23,7 @@
#include "clk-branch.h"
#include "clk-regmap-divider.h"
#include "clk-regmap-mux.h"
+#include "reset.h"
static struct clk_pll pll4 = {
.l_reg = 0x4,
@@ -39,6 +41,10 @@ static struct clk_pll pll4 = {
},
};
+static const struct qcom_reset_map lcc_ipq806x_resets[] = {
+ [LCC_PCM_RESET] = { 0x54, 13 },
+};
+
static const struct pll_config pll4_config = {
.l = 0xf,
.m = 0x91,
@@ -417,6 +423,8 @@ static const struct qcom_cc_desc lcc_ipq
.config = &lcc_ipq806x_regmap_config,
.clks = lcc_ipq806x_clks,
.num_clks = ARRAY_SIZE(lcc_ipq806x_clks),
+ .resets = lcc_ipq806x_resets,
+ .num_resets = ARRAY_SIZE(lcc_ipq806x_resets),
};
static const struct of_device_id lcc_ipq806x_match_table[] = {
--- a/include/dt-bindings/clock/qcom,lcc-ipq806x.h
+++ b/include/dt-bindings/clock/qcom,lcc-ipq806x.h
@@ -19,4 +19,5 @@
#define SPDIF_CLK 10
#define AHBIX_CLK 11
+#define LCC_PCM_RESET 0
#endif

View File

@ -0,0 +1,57 @@
From f8fdbecdaca97f0f2eebd77256e2eca4a8da6c39 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sun, 7 Feb 2021 17:08:16 +0100
Subject: [PATCH 3/4] clk: qcom: krait: add missing enable disable
Add missing enable disable mux function. Add extra check to
div2_round_rate.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/clk/qcom/clk-krait.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
--- a/drivers/clk/qcom/clk-krait.c
+++ b/drivers/clk/qcom/clk-krait.c
@@ -68,7 +68,25 @@ static u8 krait_mux_get_parent(struct cl
return clk_mux_val_to_index(hw, mux->parent_map, 0, sel);
}
+static int krait_mux_enable(struct clk_hw *hw)
+{
+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
+
+ __krait_mux_set_sel(mux, mux->en_mask);
+
+ return 0;
+}
+
+static void krait_mux_disable(struct clk_hw *hw)
+{
+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
+
+ __krait_mux_set_sel(mux, mux->safe_sel);
+}
+
const struct clk_ops krait_mux_clk_ops = {
+ .enable = krait_mux_enable,
+ .disable = krait_mux_disable,
.set_parent = krait_mux_set_parent,
.get_parent = krait_mux_get_parent,
.determine_rate = __clk_mux_determine_rate_closest,
@@ -79,8 +97,13 @@ EXPORT_SYMBOL_GPL(krait_mux_clk_ops);
static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
- *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2);
- return DIV_ROUND_UP(*parent_rate, 2);
+ struct clk_hw *hw_parent = clk_hw_get_parent(hw);
+
+ if (hw_parent) {
+ *parent_rate = clk_hw_round_rate(hw_parent, rate * 2);
+ return DIV_ROUND_UP(*parent_rate, 2);
+ } else
+ return -1;
}
static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate,

View File

@ -0,0 +1,372 @@
From 22a0f55b0e505fbbbb680e451a62878bc97f7ff1 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sun, 7 Feb 2021 17:23:38 +0100
Subject: [PATCH 4/4] ipq806x: gcc: add missing clk and reset for crypto engine
Add missing clk and reset needed for nss additional core and crypto
engine.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/clk/qcom/gcc-ipq806x.c | 250 +++++++++++++++++++
include/dt-bindings/clock/qcom,gcc-ipq806x.h | 5 +-
include/dt-bindings/reset/qcom,gcc-ipq806x.h | 5 +
3 files changed, 259 insertions(+), 1 deletion(-)
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -223,7 +223,9 @@ static struct clk_regmap pll14_vote = {
static struct pll_freq_tbl pll18_freq_tbl[] = {
NSS_PLL_RATE(550000000, 44, 0, 1, 0x01495625),
+ NSS_PLL_RATE(600000000, 48, 0, 1, 0x01495625),
NSS_PLL_RATE(733000000, 58, 16, 25, 0x014b5625),
+ NSS_PLL_RATE(800000000, 64, 0, 1, 0x01495625),
};
static struct clk_pll pll18 = {
@@ -245,6 +247,22 @@ static struct clk_pll pll18 = {
},
};
+static struct clk_pll pll11 = {
+ .l_reg = 0x3184,
+ .m_reg = 0x3188,
+ .n_reg = 0x318c,
+ .config_reg = 0x3194,
+ .mode_reg = 0x3180,
+ .status_reg = 0x3198,
+ .status_bit = 16,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pll11",
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
enum {
P_PXO,
P_PLL8,
@@ -253,6 +271,7 @@ enum {
P_CXO,
P_PLL14,
P_PLL18,
+ P_PLL11,
};
static const struct parent_map gcc_pxo_pll8_map[] = {
@@ -320,6 +339,42 @@ static const char * const gcc_pxo_pll8_p
"pll18",
};
+static const struct parent_map gcc_pxo_pll8_pll0_pll14_pll18_pll11_map[] = {
+ { P_PXO, 0 },
+ { P_PLL8, 4 },
+ { P_PLL0, 2 },
+ { P_PLL14, 5 },
+ { P_PLL18, 1 },
+ { P_PLL11, 3 },
+};
+
+static const char *gcc_pxo_pll8_pll0_pll14_pll18_pll11[] = {
+ "pxo",
+ "pll8_vote",
+ "pll0_vote",
+ "pll14",
+ "pll18",
+ "pll11"
+};
+
+static const struct parent_map gcc_pxo_pll3_pll0_pll14_pll18_pll11_map[] = {
+ { P_PXO, 0 },
+ { P_PLL3, 6 },
+ { P_PLL0, 2 },
+ { P_PLL14, 5 },
+ { P_PLL18, 1 },
+ { P_PLL11, 3 },
+};
+
+static const char *gcc_pxo_pll3_pll0_pll14_pll18_pll11[] = {
+ "pxo",
+ "pll3",
+ "pll0_vote",
+ "pll14",
+ "pll18",
+ "pll11"
+};
+
static struct freq_tbl clk_tbl_gsbi_uart[] = {
{ 1843200, P_PLL8, 2, 6, 625 },
{ 3686400, P_PLL8, 2, 12, 625 },
@@ -1261,6 +1316,7 @@ static const struct freq_tbl clk_tbl_sdc
{ 20210000, P_PLL8, 1, 1, 19 },
{ 24000000, P_PLL8, 4, 1, 4 },
{ 48000000, P_PLL8, 4, 1, 2 },
+ { 52000000, P_PLL8, 1, 2, 15 }, /* 51.2 Mhz */
{ 64000000, P_PLL8, 3, 1, 2 },
{ 96000000, P_PLL8, 4, 0, 0 },
{ 192000000, P_PLL8, 2, 0, 0 },
@@ -2645,7 +2701,9 @@ static const struct freq_tbl clk_tbl_nss
{ 110000000, P_PLL18, 1, 1, 5 },
{ 275000000, P_PLL18, 2, 0, 0 },
{ 550000000, P_PLL18, 1, 0, 0 },
+ { 600000000, P_PLL18, 1, 0, 0 },
{ 733000000, P_PLL18, 1, 0, 0 },
+ { 800000000, P_PLL18, 1, 0, 0 },
{ }
};
@@ -2757,6 +2815,186 @@ static struct clk_dyn_rcg ubi32_core2_sr
},
};
+static const struct freq_tbl clk_tbl_ce5_core[] = {
+ { 150000000, P_PLL3, 8, 1, 1 },
+ { 213200000, P_PLL11, 5, 1, 1 },
+ { }
+};
+
+static struct clk_dyn_rcg ce5_core_src = {
+ .ns_reg[0] = 0x36C4,
+ .ns_reg[1] = 0x36C8,
+ .bank_reg = 0x36C0,
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll3_pll0_pll14_pll18_pll11_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll3_pll0_pll14_pll18_pll11_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 4,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 4,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_ce5_core,
+ .clkr = {
+ .enable_reg = 0x36C0,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "ce5_core_src",
+ .parent_names = gcc_pxo_pll3_pll0_pll14_pll18_pll11,
+ .num_parents = 6,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch ce5_core_clk = {
+ .halt_reg = 0x2FDC,
+ .halt_bit = 5,
+ .hwcg_reg = 0x36CC,
+ .hwcg_bit = 6,
+ .clkr = {
+ .enable_reg = 0x36CC,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "ce5_core_clk",
+ .parent_names = (const char *[]){
+ "ce5_core_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static const struct freq_tbl clk_tbl_ce5_a_clk[] = {
+ { 160000000, P_PLL0, 5, 1, 1 },
+ { 213200000, P_PLL11, 5, 1, 1 },
+ { }
+};
+
+static struct clk_dyn_rcg ce5_a_clk_src = {
+ .ns_reg[0] = 0x3d84,
+ .ns_reg[1] = 0x3d88,
+ .bank_reg = 0x3d80,
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 4,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 4,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_ce5_a_clk,
+ .clkr = {
+ .enable_reg = 0x3d80,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "ce5_a_clk_src",
+ .parent_names = gcc_pxo_pll8_pll0_pll14_pll18_pll11,
+ .num_parents = 6,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch ce5_a_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 12,
+ .hwcg_reg = 0x3d8c,
+ .hwcg_bit = 6,
+ .clkr = {
+ .enable_reg = 0x3d8c,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "ce5_a_clk",
+ .parent_names = (const char *[]){
+ "ce5_a_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static const struct freq_tbl clk_tbl_ce5_h_clk[] = {
+ { 160000000, P_PLL0, 5, 1, 1 },
+ { 213200000, P_PLL11, 5, 1, 1 },
+ { }
+};
+
+static struct clk_dyn_rcg ce5_h_clk_src = {
+ .ns_reg[0] = 0x3c64,
+ .ns_reg[1] = 0x3c68,
+ .bank_reg = 0x3c60,
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 4,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 4,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_ce5_h_clk,
+ .clkr = {
+ .enable_reg = 0x3c60,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "ce5_h_clk_src",
+ .parent_names = gcc_pxo_pll8_pll0_pll14_pll18_pll11,
+ .num_parents = 6,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch ce5_h_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 11,
+ .hwcg_reg = 0x3c6c,
+ .hwcg_bit = 6,
+ .clkr = {
+ .enable_reg = 0x3c6c,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "ce5_h_clk",
+ .parent_names = (const char *[]){
+ "ce5_h_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
static struct clk_regmap *gcc_ipq806x_clks[] = {
[PLL0] = &pll0.clkr,
[PLL0_VOTE] = &pll0_vote,
@@ -2764,6 +3002,7 @@ static struct clk_regmap *gcc_ipq806x_cl
[PLL4_VOTE] = &pll4_vote,
[PLL8] = &pll8.clkr,
[PLL8_VOTE] = &pll8_vote,
+ [PLL11] = &pll11.clkr,
[PLL14] = &pll14.clkr,
[PLL14_VOTE] = &pll14_vote,
[PLL18] = &pll18.clkr,
@@ -2878,6 +3117,12 @@ static struct clk_regmap *gcc_ipq806x_cl
[PLL9] = &hfpll0.clkr,
[PLL10] = &hfpll1.clkr,
[PLL12] = &hfpll_l2.clkr,
+ [CE5_A_CLK_SRC] = &ce5_a_clk_src.clkr,
+ [CE5_A_CLK] = &ce5_a_clk.clkr,
+ [CE5_H_CLK_SRC] = &ce5_h_clk_src.clkr,
+ [CE5_H_CLK] = &ce5_h_clk.clkr,
+ [CE5_CORE_CLK_SRC] = &ce5_core_src.clkr,
+ [CE5_CORE_CLK] = &ce5_core_clk.clkr,
};
static const struct qcom_reset_map gcc_ipq806x_resets[] = {
@@ -3009,6 +3254,11 @@ static const struct qcom_reset_map gcc_i
[GMAC_CORE3_RESET] = { 0x3cfc, 0 },
[GMAC_CORE4_RESET] = { 0x3d1c, 0 },
[GMAC_AHB_RESET] = { 0x3e24, 0 },
+ [CRYPTO_ENG1_RESET] = { 0x3e00, 0},
+ [CRYPTO_ENG2_RESET] = { 0x3e04, 0},
+ [CRYPTO_ENG3_RESET] = { 0x3e08, 0},
+ [CRYPTO_ENG4_RESET] = { 0x3e0c, 0},
+ [CRYPTO_AHB_RESET] = { 0x3e10, 0},
[NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 },
[NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 },
[NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 },
--- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h
+++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h
@@ -240,7 +240,7 @@
#define PLL14 232
#define PLL14_VOTE 233
#define PLL18 234
-#define CE5_SRC 235
+#define CE5_A_CLK 235
#define CE5_H_CLK 236
#define CE5_CORE_CLK 237
#define CE3_SLEEP_CLK 238
@@ -283,5 +283,8 @@
#define EBI2_AON_CLK 281
#define NSSTCM_CLK_SRC 282
#define NSSTCM_CLK 283
+#define CE5_A_CLK_SRC 285
+#define CE5_H_CLK_SRC 286
+#define CE5_CORE_CLK_SRC 287
#endif
--- a/include/dt-bindings/reset/qcom,gcc-ipq806x.h
+++ b/include/dt-bindings/reset/qcom,gcc-ipq806x.h
@@ -163,5 +163,10 @@
#define NSS_CAL_PRBS_RST_N_RESET 154
#define NSS_LCKDT_RST_N_RESET 155
#define NSS_SRDS_N_RESET 156
+#define CRYPTO_ENG1_RESET 157
+#define CRYPTO_ENG2_RESET 158
+#define CRYPTO_ENG3_RESET 159
+#define CRYPTO_ENG4_RESET 160
+#define CRYPTO_AHB_RESET 161
#endif

View File

@ -0,0 +1,681 @@
From cc41a266280cad0b55319e614167c88dff344248 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sat, 22 Feb 2020 16:33:10 +0100
Subject: [PATCH 1/8] cpufreq: add Krait dedicated scaling driver
This new driver is based on generic cpufreq-dt driver.
Krait SoCs have 2-4 cpu and one shared L2 cache that can
operate at different frequency based on the maximum cpu clk
across all core.
L2 frequency and voltage are scaled on every frequency change
if needed. On Krait SoCs is present a bug that can cause
transition problem between frequency bin, to workaround this
on more than one transition, the L2 frequency is first set to the
base rate and then to the target rate.
The L2 frequency use the OPP framework and use the opp-level
bindings to link the l2 freq to different cpu freq. This is needed
as the Krait l2 clk are note mapped 1:1 to the core clks and some
of the l2 clk is set based on a range of the cpu clks. If the driver
find a broken config (for example no opp-level set) the l2 scaling is
skipped.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/cpufreq/Kconfig.arm | 14 +-
drivers/cpufreq/Makefile | 2 +
drivers/cpufreq/qcom-cpufreq-krait.c | 589 +++++++++++++++++++++++++++
3 files changed, 604 insertions(+), 1 deletion(-)
create mode 100644 drivers/cpufreq/qcom-cpufreq-krait.c
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -150,6 +150,18 @@ config ARM_QCOM_CPUFREQ_HW
The driver implements the cpufreq interface for this HW engine.
Say Y if you want to support CPUFreq HW.
+config ARM_QCOM_CPUFREQ_KRAIT
+ tristate "CPU Frequency scaling support for Krait SoCs"
+ depends on ARCH_QCOM || COMPILE_TEST
+ select PM_OPP
+ select ARM_QCOM_CPUFREQ_NVMEM
+ help
+ This adds the CPUFreq driver for Qualcomm Krait SoC based boards.
+ This scale the cache clk and regulator based on the different cpu
+ clks when scaling the different cores clk.
+
+ If in doubt, say N.
+
config ARM_RASPBERRYPI_CPUFREQ
tristate "Raspberry Pi cpufreq support"
depends on CLK_RASPBERRYPI || COMPILE_TEST
@@ -339,4 +351,4 @@ config ARM_PXA2xx_CPUFREQ
help
This add the CPUFreq driver support for Intel PXA2xx SOCs.
- If in doubt, say N.
+ If in doubt, say N.
\ No newline at end of file
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2
obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o
obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o
+obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRAIT) += qcom-cpufreq-krait.o
obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o
obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
@@ -86,6 +87,7 @@ obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += te
obj-$(CONFIG_ARM_TEGRA194_CPUFREQ) += tegra194-cpufreq.o
obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o
obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
+obj-$(CONFIG_ARM_KRAIT_CPUFREQ) += krait-cpufreq.o
##################################################################################
--- /dev/null
+++ b/drivers/cpufreq/qcom-cpufreq-krait.c
@@ -0,0 +1,603 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+
+#include "cpufreq-dt.h"
+
+static struct platform_device *l2_pdev;
+
+struct private_data {
+ struct opp_table *opp_table;
+ struct device *cpu_dev;
+ const char *reg_name;
+ bool have_static_opps;
+};
+
+static int set_target(struct cpufreq_policy *policy, unsigned int index)
+{
+ struct private_data *priv = policy->driver_data;
+ unsigned long freq = policy->freq_table[index].frequency;
+ unsigned long target_freq = freq * 1000;
+ struct dev_pm_opp *opp;
+ unsigned int level;
+ int cpu, ret;
+
+ if (l2_pdev) {
+ int policy_cpu = policy->cpu;
+
+ /* find the max freq across all core */
+ for_each_present_cpu(cpu)
+ if (cpu != policy_cpu)
+ target_freq = max(
+ target_freq,
+ (unsigned long)cpufreq_quick_get(cpu));
+
+ opp = dev_pm_opp_find_freq_exact(priv->cpu_dev, target_freq,
+ true);
+ if (IS_ERR(opp)) {
+ dev_err(&l2_pdev->dev, "failed to find OPP for %ld\n",
+ target_freq);
+ return PTR_ERR(opp);
+ }
+ level = dev_pm_opp_get_level(opp);
+ dev_pm_opp_put(opp);
+
+ /*
+ * Hardware constraint:
+ * Krait CPU cannot operate at 384MHz with L2 at 1Ghz.
+ * Assume index 0 with the idle freq and level > 0 as
+ * any L2 freq > 384MHz.
+ * Skip CPU freq change in this corner case.
+ */
+ if (unlikely(index == 0 && level != 0)) {
+ dev_err(priv->cpu_dev, "Krait CPU can't operate at idle freq with L2 at 1GHz");
+ return -EINVAL;
+ }
+
+ opp = dev_pm_opp_find_level_exact(&l2_pdev->dev, level);
+ if (IS_ERR(opp)) {
+ dev_err(&l2_pdev->dev,
+ "failed to find level OPP for %d\n", level);
+ return PTR_ERR(opp);
+ }
+ target_freq = dev_pm_opp_get_freq(opp);
+ dev_pm_opp_put(opp);
+
+ ret = dev_pm_opp_set_rate(&l2_pdev->dev, target_freq);
+ if (ret)
+ return ret;
+ }
+
+ ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000);
+ if (ret)
+ return ret;
+
+ arch_set_freq_scale(policy->related_cpus, freq,
+ policy->cpuinfo.max_freq);
+
+ return 0;
+}
+
+/*
+ * An earlier version of opp-v1 bindings used to name the regulator
+ * "cpu0-supply", we still need to handle that for backwards compatibility.
+ */
+static const char *find_supply_name(struct device *dev)
+{
+ struct device_node *np;
+ struct property *pp;
+ int cpu = dev->id;
+ const char *name = NULL;
+
+ np = of_node_get(dev->of_node);
+
+ /* This must be valid for sure */
+ if (WARN_ON(!np))
+ return NULL;
+
+ /* Try "cpu0" for older DTs */
+ if (!cpu) {
+ pp = of_find_property(np, "cpu0-supply", NULL);
+ if (pp) {
+ name = "cpu0";
+ goto node_put;
+ }
+ }
+
+ pp = of_find_property(np, "cpu-supply", NULL);
+ if (pp) {
+ name = "cpu";
+ goto node_put;
+ }
+
+ dev_dbg(dev, "no regulator for cpu%d\n", cpu);
+node_put:
+ of_node_put(np);
+ return name;
+}
+
+static int resources_available(void)
+{
+ struct device *cpu_dev;
+ struct regulator *cpu_reg;
+ struct clk *cpu_clk;
+ int ret = 0;
+ const char *name;
+
+ cpu_dev = get_cpu_device(0);
+ if (!cpu_dev) {
+ pr_err("failed to get cpu0 device\n");
+ return -ENODEV;
+ }
+
+ cpu_clk = clk_get(cpu_dev, NULL);
+ ret = PTR_ERR_OR_ZERO(cpu_clk);
+ if (ret) {
+ /*
+ * If cpu's clk node is present, but clock is not yet
+ * registered, we should try defering probe.
+ */
+ if (ret == -EPROBE_DEFER)
+ dev_dbg(cpu_dev, "clock not ready, retry\n");
+ else
+ dev_err(cpu_dev, "failed to get clock: %d\n", ret);
+
+ return ret;
+ }
+
+ clk_put(cpu_clk);
+
+ name = find_supply_name(cpu_dev);
+ /* Platform doesn't require regulator */
+ if (!name)
+ return 0;
+
+ cpu_reg = regulator_get_optional(cpu_dev, name);
+ ret = PTR_ERR_OR_ZERO(cpu_reg);
+ if (ret) {
+ /*
+ * If cpu's regulator supply node is present, but regulator is
+ * not yet registered, we should try defering probe.
+ */
+ if (ret == -EPROBE_DEFER)
+ dev_dbg(cpu_dev, "cpu0 regulator not ready, retry\n");
+ else
+ dev_dbg(cpu_dev, "no regulator for cpu0: %d\n", ret);
+
+ return ret;
+ }
+
+ regulator_put(cpu_reg);
+ return 0;
+}
+
+static int cpufreq_init(struct cpufreq_policy *policy)
+{
+ struct cpufreq_frequency_table *freq_table;
+ struct opp_table *opp_table = NULL;
+ unsigned int transition_latency;
+ struct private_data *priv;
+ struct device *cpu_dev;
+ bool fallback = false;
+ struct clk *cpu_clk;
+ const char *name;
+ int ret;
+
+ cpu_dev = get_cpu_device(policy->cpu);
+ if (!cpu_dev) {
+ pr_err("failed to get cpu%d device\n", policy->cpu);
+ return -ENODEV;
+ }
+
+ cpu_clk = clk_get(cpu_dev, NULL);
+ if (IS_ERR(cpu_clk)) {
+ ret = PTR_ERR(cpu_clk);
+ dev_err(cpu_dev, "%s: failed to get clk: %d\n", __func__, ret);
+ return ret;
+ }
+
+ /* Get OPP-sharing information from "operating-points-v2" bindings */
+ ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus);
+ if (ret) {
+ if (ret != -ENOENT)
+ goto out_put_clk;
+
+ /*
+ * operating-points-v2 not supported, fallback to old method of
+ * finding shared-OPPs for backward compatibility if the
+ * platform hasn't set sharing CPUs.
+ */
+ if (dev_pm_opp_get_sharing_cpus(cpu_dev, policy->cpus))
+ fallback = true;
+ }
+
+ /*
+ * OPP layer will be taking care of regulators now, but it needs to know
+ * the name of the regulator first.
+ */
+ name = find_supply_name(cpu_dev);
+ if (name) {
+ opp_table = dev_pm_opp_set_regulators(cpu_dev, &name, 1);
+ if (IS_ERR(opp_table)) {
+ ret = PTR_ERR(opp_table);
+ dev_err(cpu_dev,
+ "Failed to set regulator for cpu%d: %d\n",
+ policy->cpu, ret);
+ goto out_put_clk;
+ }
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto out_put_regulator;
+ }
+
+ priv->reg_name = name;
+ priv->opp_table = opp_table;
+
+ /*
+ * Initialize OPP tables for all policy->cpus. They will be shared by
+ * all CPUs which have marked their CPUs shared with OPP bindings.
+ *
+ * For platforms not using operating-points-v2 bindings, we do this
+ * before updating policy->cpus. Otherwise, we will end up creating
+ * duplicate OPPs for policy->cpus.
+ *
+ * OPPs might be populated at runtime, don't check for error here
+ */
+ if (!dev_pm_opp_of_cpumask_add_table(policy->cpus))
+ priv->have_static_opps = true;
+
+ /*
+ * But we need OPP table to function so if it is not there let's
+ * give platform code chance to provide it for us.
+ */
+ ret = dev_pm_opp_get_opp_count(cpu_dev);
+ if (ret <= 0) {
+ dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n");
+ ret = -EPROBE_DEFER;
+ goto out_free_opp;
+ }
+
+ if (fallback) {
+ cpumask_setall(policy->cpus);
+
+ /*
+ * OPP tables are initialized only for policy->cpu, do it for
+ * others as well.
+ */
+ ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus);
+ if (ret)
+ dev_err(cpu_dev,
+ "%s: failed to mark OPPs as shared: %d\n",
+ __func__, ret);
+ }
+
+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
+ if (ret) {
+ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
+ goto out_free_opp;
+ }
+
+ priv->cpu_dev = cpu_dev;
+
+ policy->driver_data = priv;
+ policy->clk = cpu_clk;
+ policy->freq_table = freq_table;
+
+ policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000;
+
+ transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev);
+ if (!transition_latency)
+ transition_latency = CPUFREQ_ETERNAL;
+
+ policy->cpuinfo.transition_latency = transition_latency;
+ policy->dvfs_possible_from_any_cpu = true;
+
+ dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
+
+ return 0;
+
+out_free_opp:
+ if (priv->have_static_opps)
+ dev_pm_opp_of_cpumask_remove_table(policy->cpus);
+ kfree(priv);
+out_put_regulator:
+ if (name)
+ dev_pm_opp_put_regulators(opp_table);
+out_put_clk:
+ clk_put(cpu_clk);
+
+ return ret;
+}
+
+static int cpufreq_online(struct cpufreq_policy *policy)
+{
+ /* We did light-weight tear down earlier, nothing to do here */
+ return 0;
+}
+
+static int cpufreq_offline(struct cpufreq_policy *policy)
+{
+ /*
+ * Preserve policy->driver_data and don't free resources on light-weight
+ * tear down.
+ */
+ return 0;
+}
+
+static int cpufreq_exit(struct cpufreq_policy *policy)
+{
+ struct private_data *priv = policy->driver_data;
+
+ dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
+ if (priv->have_static_opps)
+ dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
+ if (priv->reg_name)
+ dev_pm_opp_put_regulators(priv->opp_table);
+
+ clk_put(policy->clk);
+ kfree(priv);
+
+ return 0;
+}
+
+static struct cpufreq_driver krait_cpufreq_driver = {
+ .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+ CPUFREQ_IS_COOLING_DEV,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = set_target,
+ .get = cpufreq_generic_get,
+ .init = cpufreq_init,
+ .exit = cpufreq_exit,
+ .online = cpufreq_online,
+ .offline = cpufreq_offline,
+ .name = "krait-cpufreq",
+ .suspend = cpufreq_generic_suspend,
+};
+
+struct krait_data {
+ unsigned long idle_freq;
+ bool regulator_enabled;
+};
+
+static int krait_cache_set_opp(struct dev_pm_set_opp_data *data)
+{
+ unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate;
+ struct dev_pm_opp_supply *supply = &data->new_opp.supplies[0];
+ struct regulator *reg = data->regulators[0];
+ struct clk *clk = data->clk;
+ struct krait_data *kdata;
+ unsigned long idle_freq;
+ int ret;
+
+ kdata = (struct krait_data *)dev_get_drvdata(data->dev);
+ idle_freq = kdata->idle_freq;
+
+ /* Scaling up? Scale voltage before frequency */
+ if (freq >= old_freq) {
+ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
+ supply->u_volt,
+ supply->u_volt_max);
+ if (ret)
+ goto exit;
+ }
+
+ /*
+ * Set to idle bin if switching from normal to high bin
+ * or vice versa. It has been notice that a bug is triggered
+ * in cache scaling when more than one bin is scaled, to fix
+ * this we first need to transition to the base rate and then
+ * to target rate
+ */
+ if (likely(freq != idle_freq && old_freq != idle_freq)) {
+ ret = clk_set_rate(clk, idle_freq);
+ if (ret)
+ goto exit;
+ }
+
+ ret = clk_set_rate(clk, freq);
+ if (ret)
+ goto exit;
+
+ /* Scaling down? Scale voltage after frequency */
+ if (freq < old_freq) {
+ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
+ supply->u_volt,
+ supply->u_volt_max);
+ }
+
+ if (unlikely(!kdata->regulator_enabled)) {
+ ret = regulator_enable(reg);
+ if (ret < 0)
+ dev_warn(data->dev, "Failed to enable regulator: %d", ret);
+ else
+ kdata->regulator_enabled = true;
+ }
+
+exit:
+ return ret;
+};
+
+static int krait_cache_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct krait_data *data;
+ struct opp_table *table;
+ struct dev_pm_opp *opp;
+ struct device *cpu_dev;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ table = dev_pm_opp_set_regulators(dev, (const char *[]){ "l2" }, 1);
+ if (IS_ERR(table)) {
+ ret = PTR_ERR(table);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to set regulators %d\n", ret);
+
+ return ret;
+ }
+
+ ret = PTR_ERR_OR_ZERO(
+ dev_pm_opp_register_set_opp_helper(dev, krait_cache_set_opp));
+ if (ret)
+ return ret;
+
+ ret = dev_pm_opp_of_add_table(dev);
+ if (ret) {
+ dev_err(dev, "failed to parse L2 freq thresholds\n");
+ return ret;
+ }
+
+ opp = dev_pm_opp_find_freq_ceil(dev, &data->idle_freq);
+ dev_pm_opp_put(opp);
+
+ /*
+ * Check opp-level configuration
+ * At least 2 level must be set or the cache will always be scaled
+ * the idle freq causing some performance problem
+ *
+ * In case of invalid configuration, the l2 scaling is skipped
+ */
+ cpu_dev = get_cpu_device(0);
+ if (!cpu_dev) {
+ pr_err("failed to get cpu0 device\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Check if we have at least opp-level 1, 0 should always be set to
+ * the idle freq
+ */
+ opp = dev_pm_opp_find_level_exact(dev, 1);
+ if (IS_ERR(opp)) {
+ dev_err(dev,
+ "Invalid configuration found of l2 opp. Can't find opp-level 1");
+ goto invalid_conf;
+ }
+ dev_pm_opp_put(opp);
+
+ /*
+ * Check if we have at least opp-level 1 in the cpu opp, 0 should always
+ * be set to the idle freq
+ */
+ opp = dev_pm_opp_find_level_exact(cpu_dev, 1);
+ if (IS_ERR(opp)) {
+ dev_err(dev,
+ "Invalid configuration found of cpu opp. Can't find opp-level 1");
+ goto invalid_conf;
+ }
+ dev_pm_opp_put(opp);
+
+ platform_set_drvdata(pdev, data);
+
+ /* The l2 scaling is enabled by linking the cpufreq driver */
+ l2_pdev = pdev;
+
+ return 0;
+
+invalid_conf:
+ dev_pm_opp_remove_table(dev);
+ dev_pm_opp_put_regulators(table);
+ dev_pm_opp_unregister_set_opp_helper(table);
+
+ return -EINVAL;
+};
+
+static int krait_cache_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct opp_table *table = dev_pm_opp_get_opp_table(dev);
+
+ dev_pm_opp_remove_table(dev);
+ dev_pm_opp_put_regulators(table);
+ dev_pm_opp_unregister_set_opp_helper(table);
+
+ return 0;
+};
+
+static const struct of_device_id krait_cache_match_table[] = {
+ { .compatible = "qcom,krait-cache" },
+ {}
+};
+
+static struct platform_driver krait_cache_driver = {
+ .driver = {
+ .name = "krait-cache",
+ .of_match_table = krait_cache_match_table,
+ },
+ .probe = krait_cache_probe,
+ .remove = krait_cache_remove,
+};
+module_platform_driver(krait_cache_driver);
+
+static int krait_cpufreq_probe(struct platform_device *pdev)
+{
+ struct cpufreq_dt_platform_data *data = dev_get_platdata(&pdev->dev);
+ int ret;
+
+ /*
+ * All per-cluster (CPUs sharing clock/voltages) initialization is done
+ * from ->init(). In probe(), we just need to make sure that clk and
+ * regulators are available. Else defer probe and retry.
+ *
+ * FIXME: Is checking this only for CPU0 sufficient ?
+ */
+ ret = resources_available();
+ if (ret)
+ return ret;
+
+ if (data) {
+ if (data->have_governor_per_policy)
+ krait_cpufreq_driver.flags |=
+ CPUFREQ_HAVE_GOVERNOR_PER_POLICY;
+
+ krait_cpufreq_driver.resume = data->resume;
+ if (data->suspend)
+ krait_cpufreq_driver.suspend = data->suspend;
+ }
+
+ ret = cpufreq_register_driver(&krait_cpufreq_driver);
+ if (ret)
+ dev_err(&pdev->dev, "failed register driver: %d\n", ret);
+
+ return ret;
+}
+
+static int krait_cpufreq_remove(struct platform_device *pdev)
+{
+ cpufreq_unregister_driver(&krait_cpufreq_driver);
+ return 0;
+}
+
+static struct platform_driver krait_cpufreq_platdrv = {
+ .driver = {
+ .name = "krait-cpufreq",
+ },
+ .probe = krait_cpufreq_probe,
+ .remove = krait_cpufreq_remove,
+};
+module_platform_driver(krait_cpufreq_platdrv);
+
+MODULE_ALIAS("platform:krait-cpufreq");
+MODULE_AUTHOR("Ansuel Smith <ansuelsmth@gmail.com>");
+MODULE_DESCRIPTION("Dedicated Krait SoC cpufreq driver");
+MODULE_LICENSE("GPL");

View File

@ -0,0 +1,237 @@
From c9ecd920324a647bf1f2b47f771c8f599cc7b551 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sat, 22 Feb 2020 18:02:17 +0100
Subject: [PATCH 2/8] Documentation: cpufreq: add qcom,krait-cache bindings
Document dedicated cpufreq for Krait CPUs.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
.../bindings/cpufreq/qcom-cpufreq-krait.yaml | 221 ++++++++++++++++++
1 file changed, 221 insertions(+)
create mode 100644 Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml
@@ -0,0 +1,221 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/cpufreq/qcom-cpufreq-krait.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: CPU Frequency scaling driver for Krait SoCs
+
+maintainers:
+ - Ansuel Smith <ansuelsmth@gmail.com>
+
+description: |
+ The krait cpufreq driver is a dedicated frequency scaling driver
+ based on cpufreq-dt generic driver that scale L2 cache and the
+ cores. TEST
+
+ The L2 cache is scaled based on the max clk across all cores and
+ the clock is decided based on the opp-level set in the device tree.
+
+ Different core freq can be linked to a specific l2 freq and the driver
+ on frequency change will scale the core and the l2 clk based of the
+ linked freq.
+
+ On Krait SoC is present a bug and on every L2 clk change the driver
+ needs to set the clk to the idle freq before changing it to the new value.
+
+ This requires the qcom cpufreq nvmem driver to parse the different opp
+ core clk and an additional opp table for the l2 scaling.
+
+ If the driver detect broken config (for example missing opp-level) the
+ cpufreq driver skips the l2 scaling
+
+ Referring to this example opp-level can be used to link a range of cpu freq
+ to a specific l2 freq:
+ cpu opp freq 384000000 has opp-level 0
+ l2 opp freq 384000000 has opp-level 0
+ The driver will scale l2 to 384000000
+
+ cpu opp freq 600000000-1000000000 has opp-level 1
+ l2 opp freq 1000000000 has opp-level 1
+ The driver will scale l2 to 1000000000
+
+allOf:
+ - $ref: /schemas/cache-controller.yaml#
+
+select:
+ properties:
+ compatible:
+ items:
+ - enum:
+ - qcom,krait-cache
+
+ required:
+ - compatible
+
+properties:
+ compatible:
+ items:
+ - const: qcom,krait-cache
+ - const: cache
+
+ cache-level:
+ const: 2
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: l2
+
+ l2-supply: true
+
+ operating-points-v2: true
+
+required:
+ - compatible
+ - cache-level
+ - clocks
+ - clock-names
+ - l2-supply
+ - operating-points-v2
+
+additionalProperties: false
+
+examples:
+ - |
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "qcom,krait";
+ enable-method = "qcom,kpss-acc-v1";
+ device_type = "cpu";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ qcom,acc = <&acc0>;
+ qcom,saw = <&saw0>;
+ clocks = <&kraitcc 0>, <&kraitcc 4>;
+ clock-names = "cpu", "l2";
+ clock-latency = <100000>;
+ cpu-supply = <&smb208_s2a>;
+ operating-points-v2 = <&opp_table0>;
+ voltage-tolerance = <5>;
+ cooling-min-state = <0>;
+ cooling-max-state = <10>;
+ #cooling-cells = <2>;
+ cpu-idle-states = <&CPU_SPC>;
+ };
+
+ /* ... */
+
+ };
+
+ opp_table0: opp_table0 {
+ compatible = "operating-points-v2-kryo-cpu";
+ nvmem-cells = <&speedbin_efuse>;
+
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1000000>;
+ opp-microvolt-speed0-pvs1-v0 = <925000>;
+ opp-microvolt-speed0-pvs2-v0 = <875000>;
+ opp-microvolt-speed0-pvs3-v0 = <800000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <0>;
+ };
+
+ opp-600000000 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1050000>;
+ opp-microvolt-speed0-pvs1-v0 = <975000>;
+ opp-microvolt-speed0-pvs2-v0 = <925000>;
+ opp-microvolt-speed0-pvs3-v0 = <850000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <1>;
+ };
+
+ opp-800000000 {
+ opp-hz = /bits/ 64 <800000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1100000>;
+ opp-microvolt-speed0-pvs1-v0 = <1025000>;
+ opp-microvolt-speed0-pvs2-v0 = <995000>;
+ opp-microvolt-speed0-pvs3-v0 = <900000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <1>;
+ };
+
+ opp-1000000000 {
+ opp-hz = /bits/ 64 <1000000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1150000>;
+ opp-microvolt-speed0-pvs1-v0 = <1075000>;
+ opp-microvolt-speed0-pvs2-v0 = <1025000>;
+ opp-microvolt-speed0-pvs3-v0 = <950000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <1>;
+ };
+
+ opp-1200000000 {
+ opp-hz = /bits/ 64 <1200000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1200000>;
+ opp-microvolt-speed0-pvs1-v0 = <1125000>;
+ opp-microvolt-speed0-pvs2-v0 = <1075000>;
+ opp-microvolt-speed0-pvs3-v0 = <1000000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <2>;
+ };
+
+ opp-1400000000 {
+ opp-hz = /bits/ 64 <1400000000>;
+ opp-microvolt-speed0-pvs0-v0 = <1250000>;
+ opp-microvolt-speed0-pvs1-v0 = <1175000>;
+ opp-microvolt-speed0-pvs2-v0 = <1125000>;
+ opp-microvolt-speed0-pvs3-v0 = <1050000>;
+ opp-supported-hw = <0x1>;
+ clock-latency-ns = <100000>;
+ opp-level = <2>;
+ };
+ };
+
+ opp_table_l2: opp_table_l2 {
+ compatible = "operating-points-v2";
+
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ opp-microvolt = <1100000>;
+ clock-latency-ns = <100000>;
+ opp-level = <0>;
+ };
+ opp-1000000000 {
+ opp-hz = /bits/ 64 <1000000000>;
+ opp-microvolt = <1100000>;
+ clock-latency-ns = <100000>;
+ opp-level = <1>;
+ };
+ opp-1200000000 {
+ opp-hz = /bits/ 64 <1200000000>;
+ opp-microvolt = <1150000>;
+ clock-latency-ns = <100000>;
+ opp-level = <2>;
+ };
+ };
+
+ soc {
+ L2: l2-cache {
+ compatible = "qcom,krait-cache", "cache";
+ cache-level = <2>;
+
+ clocks = <&kraitcc 4>;
+ clock-names = "l2";
+ l2-supply = <&smb208_s1a>;
+ operating-points-v2 = <&opp_table_l2>;
+ };
+ };
+
+...

View File

@ -0,0 +1,243 @@
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -15,6 +15,7 @@ clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-k
clk-qcom-y += clk-hfpll.o
clk-qcom-y += reset.o
clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
+clk-qcom-y += fab_scaling.o
# Keep alphabetically sorted by config
obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
--- /dev/null
+++ b/drivers/clk/qcom/fab_scaling.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/fab_scaling.h>
+
+struct qcom_fab_scaling_data {
+ u32 fab_freq_high;
+ u32 fab_freq_nominal;
+ u32 cpu_freq_threshold;
+ struct clk *apps_fab_clk;
+ struct clk *ddr_fab_clk;
+};
+
+static struct qcom_fab_scaling_data *drv_data;
+
+int scale_fabrics(unsigned long max_cpu_freq)
+{
+ struct clk *apps_fab_clk = drv_data->apps_fab_clk,
+ *ddr_fab_clk = drv_data->ddr_fab_clk;
+ unsigned long target_freq, cur_freq;
+ int ret;
+
+ /* Skip fab scaling if the driver is not ready */
+ if (!apps_fab_clk || !ddr_fab_clk)
+ return 0;
+
+ if (max_cpu_freq > drv_data->cpu_freq_threshold)
+ target_freq = drv_data->fab_freq_high;
+ else
+ target_freq = drv_data->fab_freq_nominal;
+
+ cur_freq = clk_get_rate(ddr_fab_clk);
+
+ if (target_freq != cur_freq) {
+ ret = clk_set_rate(apps_fab_clk, target_freq);
+ if (ret)
+ return ret;
+ ret = clk_set_rate(ddr_fab_clk, target_freq);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(scale_fabrics);
+
+static int ipq806x_fab_scaling_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct clk *apps_fab_clk, *ddr_fab_clk;
+ int ret;
+
+ if (!np)
+ return -ENODEV;
+
+ drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
+ if (!drv_data)
+ return -ENOMEM;
+
+ if (of_property_read_u32(np, "fab_freq_high", &drv_data->fab_freq_high)) {
+ pr_err("FABRICS turbo freq not found. Using defaults...\n");
+ drv_data->fab_freq_high = 533000000;
+ }
+
+ if (of_property_read_u32(np, "fab_freq_nominal", &drv_data->fab_freq_nominal)) {
+ pr_err("FABRICS nominal freq not found. Using defaults...\n");
+ drv_data->fab_freq_nominal = 400000000;
+ }
+
+ if (of_property_read_u32(np, "cpu_freq_threshold", &drv_data->cpu_freq_threshold)) {
+ pr_err("FABRICS cpu freq threshold not found. Using defaults...\n");
+ drv_data->cpu_freq_threshold = 1000000000;
+ }
+
+ apps_fab_clk = devm_clk_get(&pdev->dev, "apps-fab-clk");
+ ret = PTR_ERR_OR_ZERO(apps_fab_clk);
+ if (ret) {
+ /*
+ * If apps fab clk node is present, but clock is not yet
+ * registered, we should try defering probe.
+ */
+ if (ret != -EPROBE_DEFER) {
+ pr_err("Failed to get APPS FABRIC clock: %d\n", ret);
+ ret = -ENODEV;
+ }
+ goto err;
+ }
+
+ clk_prepare_enable(apps_fab_clk);
+ clk_set_rate(apps_fab_clk, drv_data->fab_freq_high);
+ drv_data->apps_fab_clk = apps_fab_clk;
+
+ ddr_fab_clk = devm_clk_get(&pdev->dev, "ddr-fab-clk");
+ ret = PTR_ERR_OR_ZERO(ddr_fab_clk);
+ if (ret) {
+ /*
+ * If ddr fab clk node is present, but clock is not yet
+ * registered, we should try defering probe.
+ */
+ if (ret != -EPROBE_DEFER) {
+ pr_err("Failed to get DDR FABRIC clock: %d\n", ret);
+ ddr_fab_clk = NULL;
+ ret = -ENODEV;
+ }
+ goto err;
+ }
+
+ clk_prepare_enable(ddr_fab_clk);
+ clk_set_rate(ddr_fab_clk, drv_data->fab_freq_high);
+ drv_data->ddr_fab_clk = ddr_fab_clk;
+
+ return 0;
+err:
+ kfree(drv_data);
+ return ret;
+}
+
+static int ipq806x_fab_scaling_remove(struct platform_device *pdev)
+{
+ kfree(drv_data);
+ return 0;
+}
+
+static const struct of_device_id fab_scaling_ipq806x_match_table[] = {
+ { .compatible = "qcom,fab-scaling" },
+ { }
+};
+
+static struct platform_driver fab_scaling_ipq806x_driver = {
+ .probe = ipq806x_fab_scaling_probe,
+ .remove = ipq806x_fab_scaling_remove,
+ .driver = {
+ .name = "fab-scaling",
+ .of_match_table = fab_scaling_ipq806x_match_table,
+ },
+};
+
+static int __init fab_scaling_ipq806x_init(void)
+{
+ return platform_driver_register(&fab_scaling_ipq806x_driver);
+}
+late_initcall(fab_scaling_ipq806x_init);
+
+static void __exit fab_scaling_ipq806x_exit(void)
+{
+ platform_driver_unregister(&fab_scaling_ipq806x_driver);
+}
+module_exit(fab_scaling_ipq806x_exit);
--- /dev/null
+++ b/include/linux/fab_scaling.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef __FAB_SCALING_H
+#define __FAB_SCALING_H
+
+/**
+ * scale_fabrics - Scale DDR and APPS FABRICS
+ *
+ * This function monitors all the registered clocks and does APPS
+ * and DDR FABRIC scaling based on the idle frequencies with which
+ * it was registered.
+ *
+ */
+int scale_fabrics(unsigned long max_cpu_freq);
+
+#endif
--- a/drivers/cpufreq/qcom-cpufreq-krait.c
+++ b/drivers/cpufreq/qcom-cpufreq-krait.c
@@ -15,6 +15,7 @@
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/thermal.h>
+#include <linux/fab_scaling.h>
#include "cpufreq-dt.h"
@@ -68,6 +69,13 @@ static int set_target(struct cpufreq_pol
return -EINVAL;
}
+ /*
+ * Scale fabrics with max freq across all cores
+ */
+ ret = scale_fabrics(target_freq);
+ if (ret)
+ return ret;
+
opp = dev_pm_opp_find_level_exact(&l2_pdev->dev, level);
if (IS_ERR(opp)) {
dev_err(&l2_pdev->dev,

View File

@ -0,0 +1,239 @@
From 6949d651e3be3ebbfedb6bbd5b541cfda6ee58a9 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Wed, 10 Feb 2021 10:40:17 +0100
Subject: [PATCH 1/2] mtd: nand: raw: qcom_nandc: add boot_layout_mode support
ipq806x nand have a special ecc configuration for the boot pages. The
use of the non-boot pages configuration on boot pages cause I/O error
and can cause broken data written to the nand. Add support for this
special configuration if the page to be read/write is in the size of the
boot pages set by the dts.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/mtd/nand/raw/qcom_nandc.c | 82 +++++++++++++++++++++++++++++--
1 file changed, 77 insertions(+), 5 deletions(-)
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -159,6 +159,11 @@
/* NAND_CTRL bits */
#define BAM_MODE_EN BIT(0)
+
+#define UD_SIZE_BYTES_MASK (0x3ff << UD_SIZE_BYTES)
+#define SPARE_SIZE_BYTES_MASK (0xf << SPARE_SIZE_BYTES)
+#define ECC_NUM_DATA_BYTES_MASK (0x3ff << ECC_NUM_DATA_BYTES)
+
/*
* the NAND controller performs reads/writes with ECC in 516 byte chunks.
* the driver calls the chunks 'step' or 'codeword' interchangeably
@@ -430,6 +435,13 @@ struct qcom_nand_controller {
* @cfg0, cfg1, cfg0_raw..: NANDc register configurations needed for
* ecc/non-ecc mode for the current nand flash
* device
+ *
+ * @boot_pages_conf: keep track of the current ecc configuration used by
+ * the driver for read/write operation. (boot pages
+ * have different configuration than normal page)
+ * @boot_pages: number of pages starting from 0 used as boot pages
+ * where the driver will use the boot pages ecc
+ * configuration for read/write operation
*/
struct qcom_nand_host {
struct nand_chip chip;
@@ -452,6 +464,9 @@ struct qcom_nand_host {
u32 ecc_bch_cfg;
u32 clrflashstatus;
u32 clrreadstatus;
+
+ bool boot_pages_conf;
+ u32 boot_pages;
};
/*
@@ -460,12 +475,14 @@ struct qcom_nand_host {
* @ecc_modes - ecc mode for NAND
* @is_bam - whether NAND controller is using BAM
* @is_qpic - whether NAND CTRL is part of qpic IP
+ * @has_boot_pages - whether NAND has different ecc settings for boot pages
* @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
*/
struct qcom_nandc_props {
u32 ecc_modes;
bool is_bam;
bool is_qpic;
+ bool has_boot_pages;
u32 dev_cmd_reg_start;
};
@@ -1604,7 +1621,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *
data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
oob_size1 = host->bbm_size;
- if (cw == (ecc->steps - 1)) {
+ if (cw == (ecc->steps - 1) && !host->boot_pages_conf) {
data_size2 = ecc->size - data_size1 -
((ecc->steps - 1) * 4);
oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw +
@@ -1685,7 +1702,7 @@ check_for_erased_page(struct qcom_nand_h
}
for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) {
- if (cw == (ecc->steps - 1)) {
+ if (cw == (ecc->steps - 1) && !host->boot_pages_conf) {
data_size = ecc->size - ((ecc->steps - 1) * 4);
oob_size = (ecc->steps * 4) + host->ecc_bytes_hw;
} else {
@@ -1844,7 +1861,7 @@ static int read_page_ecc(struct qcom_nan
for (i = 0; i < ecc->steps; i++) {
int data_size, oob_size;
- if (i == (ecc->steps - 1)) {
+ if (i == (ecc->steps - 1) && !host->boot_pages_conf) {
data_size = ecc->size - ((ecc->steps - 1) << 2);
oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
host->spare_bytes;
@@ -1941,6 +1958,30 @@ static int copy_last_cw(struct qcom_nand
return ret;
}
+static void
+check_boot_pages_conf(struct qcom_nand_host *host, int page)
+{
+ bool boot_pages_conf = page < host->boot_pages;
+
+ /* Skip conf write if we are already in the correct mode */
+ if (boot_pages_conf != host->boot_pages_conf) {
+ host->boot_pages_conf = boot_pages_conf;
+
+ host->cw_data = boot_pages_conf ? 512 : 516;
+ host->spare_bytes = host->cw_size - host->ecc_bytes_hw -
+ host->bbm_size - host->cw_data;
+
+ host->cfg0 &= ~(SPARE_SIZE_BYTES_MASK | UD_SIZE_BYTES_MASK);
+ host->cfg0 |= host->spare_bytes << SPARE_SIZE_BYTES |
+ host->cw_data << UD_SIZE_BYTES;
+
+ host->ecc_bch_cfg &= ~ECC_NUM_DATA_BYTES_MASK;
+ host->ecc_bch_cfg |= host->cw_data << ECC_NUM_DATA_BYTES;
+ host->ecc_buf_cfg = (boot_pages_conf ? 0x1ff : 0x203) <<
+ NUM_STEPS;
+ }
+}
+
/* implements ecc->read_page() */
static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
@@ -1949,6 +1990,9 @@ static int qcom_nandc_read_page(struct n
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
u8 *data_buf, *oob_buf = NULL;
+ if (host->boot_pages)
+ check_boot_pages_conf(host, page);
+
nand_read_page_op(chip, page, 0, NULL, 0);
data_buf = buf;
oob_buf = oob_required ? chip->oob_poi : NULL;
@@ -1968,6 +2012,9 @@ static int qcom_nandc_read_page_raw(stru
int cw, ret;
u8 *data_buf = buf, *oob_buf = chip->oob_poi;
+ if (host->boot_pages)
+ check_boot_pages_conf(host, page);
+
for (cw = 0; cw < ecc->steps; cw++) {
ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf,
page, cw);
@@ -1988,6 +2035,9 @@ static int qcom_nandc_read_oob(struct na
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
+ if (host->boot_pages)
+ check_boot_pages_conf(host, page);
+
clear_read_regs(nandc);
clear_bam_transaction(nandc);
@@ -2008,6 +2058,9 @@ static int qcom_nandc_write_page(struct
u8 *data_buf, *oob_buf;
int i, ret;
+ if (host->boot_pages)
+ check_boot_pages_conf(host, page);
+
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
clear_read_regs(nandc);
@@ -2023,7 +2076,7 @@ static int qcom_nandc_write_page(struct
for (i = 0; i < ecc->steps; i++) {
int data_size, oob_size;
- if (i == (ecc->steps - 1)) {
+ if (i == (ecc->steps - 1) && !host->boot_pages_conf) {
data_size = ecc->size - ((ecc->steps - 1) << 2);
oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
host->spare_bytes;
@@ -2080,6 +2133,9 @@ static int qcom_nandc_write_page_raw(str
u8 *data_buf, *oob_buf;
int i, ret;
+ if (host->boot_pages)
+ check_boot_pages_conf(host, page);
+
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
clear_read_regs(nandc);
clear_bam_transaction(nandc);
@@ -2098,7 +2154,7 @@ static int qcom_nandc_write_page_raw(str
data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
oob_size1 = host->bbm_size;
- if (i == (ecc->steps - 1)) {
+ if (i == (ecc->steps - 1) && !host->boot_pages_conf) {
data_size2 = ecc->size - data_size1 -
((ecc->steps - 1) << 2);
oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
@@ -2158,6 +2214,9 @@ static int qcom_nandc_write_oob(struct n
int data_size, oob_size;
int ret;
+ if (host->boot_pages)
+ check_boot_pages_conf(host, page);
+
host->use_ecc = true;
clear_bam_transaction(nandc);
@@ -2806,6 +2865,7 @@ static int qcom_nand_host_init_and_regis
struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct device *dev = nandc->dev;
+ u32 boot_pages_size;
int ret;
ret = of_property_read_u32(dn, "reg", &host->cs);
@@ -2866,6 +2926,17 @@ static int qcom_nand_host_init_and_regis
if (ret)
nand_cleanup(chip);
+ if (nandc->props->has_boot_pages &&
+ of_property_read_bool(dn, "nand-is-boot-medium")) {
+ ret = of_property_read_u32(dn, "qcom,boot_pages_size",
+ &boot_pages_size);
+ if (ret)
+ dev_warn(dev, "can't get boot pages size");
+ else
+ /* Convert size to nand pages */
+ host->boot_pages = boot_pages_size / mtd->writesize;
+ }
+
return ret;
}
@@ -3032,6 +3103,7 @@ static int qcom_nandc_remove(struct plat
static const struct qcom_nandc_props ipq806x_nandc_props = {
.ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
.is_bam = false,
+ .has_boot_pages = true,
.dev_cmd_reg_start = 0x0,
};

View File

@ -0,0 +1,42 @@
From 6fb003a7a117f97a35b078ba726c84adeae29c4c Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Wed, 10 Feb 2021 10:54:19 +0100
Subject: [PATCH 2/2] Documentation: devicetree: mtd: qcom_nandc: document
qcom,boot_layout_size binding
Document new qcom,boot_layout_size binding used to apply special
read/write confituation to boots partitions.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
Documentation/devicetree/bindings/mtd/qcom_nandc.txt | 11 +++++++++++
1 file changed, 11 insertions(+)
--- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
+++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
@@ -52,6 +52,15 @@ Optional properties:
be used according to chip requirement and available
OOB size.
+EBI2 specific properties:
+- nand-is-boot-medium: nand contains boot partitions and different ecc configuration
+ should be used for these partitions.
+- qcom,boot_pages_size: should contain the size of the total boot partitions
+ where the boot layout read/write specific configuration
+ should be used. The boot layout is considered from the
+ start of the nand to the value set in this binding.
+ Only used in combination with 'nand-is-boot-medium'.
+
Each nandcs device node may optionally contain a 'partitions' sub-node, which
further contains sub-nodes describing the flash partition mapping. See
partition.txt for more detail.
@@ -80,6 +89,9 @@ nand-controller@1ac00000 {
nand-ecc-strength = <4>;
nand-bus-width = <8>;
+ nand-is-boot-medium;
+ qcom,boot_pages_size: <0x58a0000>;
+
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;

View File

@ -0,0 +1,965 @@
From 5c9f8c2dbdbe53818bcde6aa6695e1331e5f841f Mon Sep 17 00:00:00 2001
From: Jonathan McDowell <noodles@earth.li>
Date: Sat, 14 Nov 2020 14:02:33 +0000
Subject: dmaengine: qcom: Add ADM driver
Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA
controller found in the MSM8x60 and IPQ/APQ8064 platforms.
The ADM supports both memory to memory transactions and memory
to/from peripheral device transactions. The controller also provides
flow control capabilities for transactions to/from peripheral devices.
The initial release of this driver supports slave transfers to/from
peripherals and also incorporates CRCI (client rate control interface)
flow control.
The hardware only supports a 32 bit physical address, so specifying
!PHYS_ADDR_T_64BIT gives maximum COMPILE_TEST coverage without having to
spend effort on kludging things in the code that will never actually be
needed on real hardware.
Signed-off-by: Andy Gross <agross@codeaurora.org>
Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
Signed-off-by: Jonathan McDowell <noodles@earth.li>
Link: https://lore.kernel.org/r/20201114140233.GM32650@earth.li
Signed-off-by: Vinod Koul <vkoul@kernel.org>
---
drivers/dma/qcom/Kconfig | 11 +
drivers/dma/qcom/Makefile | 1 +
drivers/dma/qcom/qcom_adm.c | 903 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 915 insertions(+)
create mode 100644 drivers/dma/qcom/qcom_adm.c
--- a/drivers/dma/qcom/Kconfig
+++ b/drivers/dma/qcom/Kconfig
@@ -1,4 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-only
+config QCOM_ADM
+ tristate "Qualcomm ADM support"
+ depends on (ARCH_QCOM || COMPILE_TEST) && !PHYS_ADDR_T_64BIT
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Enable support for the Qualcomm Application Data Mover (ADM) DMA
+ controller, as present on MSM8x60, APQ8064, and IPQ8064 devices.
+ This controller provides DMA capabilities for both general purpose
+ and on-chip peripheral devices.
+
config QCOM_BAM_DMA
tristate "QCOM BAM DMA support"
depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM)
--- a/drivers/dma/qcom/Makefile
+++ b/drivers/dma/qcom/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_QCOM_ADM) += qcom_adm.o
obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o
obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o
hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o
--- /dev/null
+++ b/drivers/dma/qcom/qcom_adm.c
@@ -0,0 +1,903 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+
+#include "../dmaengine.h"
+#include "../virt-dma.h"
+
+/* ADM registers - calculated from channel number and security domain */
+#define ADM_CHAN_MULTI 0x4
+#define ADM_CI_MULTI 0x4
+#define ADM_CRCI_MULTI 0x4
+#define ADM_EE_MULTI 0x800
+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan))
+#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * (ee))
+#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee))
+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan))
+#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci))
+#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee))
+#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee))
+#define ADM_CH_FLUSH_STATE0(chan, ee) (0x80 + ADM_CHAN_EE_OFFS(chan, ee))
+#define ADM_CH_STATUS_SD(chan, ee) (0x200 + ADM_CHAN_EE_OFFS(chan, ee))
+#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan))
+#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee))
+#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee))
+#define ADM_CI_CONF(ci) (0x390 + (ci) * ADM_CI_MULTI)
+#define ADM_GP_CTL 0x3d8
+#define ADM_CRCI_CTL(crci, ee) (0x400 + (crci) * ADM_CRCI_MULTI + \
+ ADM_EE_OFFS(ee))
+
+/* channel status */
+#define ADM_CH_STATUS_VALID BIT(1)
+
+/* channel result */
+#define ADM_CH_RSLT_VALID BIT(31)
+#define ADM_CH_RSLT_ERR BIT(3)
+#define ADM_CH_RSLT_FLUSH BIT(2)
+#define ADM_CH_RSLT_TPD BIT(1)
+
+/* channel conf */
+#define ADM_CH_CONF_SHADOW_EN BIT(12)
+#define ADM_CH_CONF_MPU_DISABLE BIT(11)
+#define ADM_CH_CONF_PERM_MPU_CONF BIT(9)
+#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7)
+#define ADM_CH_CONF_SEC_DOMAIN(ee) ((((ee) & 0x3) << 4) | (((ee) & 0x4) << 11))
+
+/* channel result conf */
+#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1)
+#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0)
+
+/* CRCI CTL */
+#define ADM_CRCI_CTL_MUX_SEL BIT(18)
+#define ADM_CRCI_CTL_RST BIT(17)
+
+/* CI configuration */
+#define ADM_CI_RANGE_END(x) ((x) << 24)
+#define ADM_CI_RANGE_START(x) ((x) << 16)
+#define ADM_CI_BURST_4_WORDS BIT(2)
+#define ADM_CI_BURST_8_WORDS BIT(3)
+
+/* GP CTL */
+#define ADM_GP_CTL_LP_EN BIT(12)
+#define ADM_GP_CTL_LP_CNT(x) ((x) << 8)
+
+/* Command pointer list entry */
+#define ADM_CPLE_LP BIT(31)
+#define ADM_CPLE_CMD_PTR_LIST BIT(29)
+
+/* Command list entry */
+#define ADM_CMD_LC BIT(31)
+#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7)
+#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3)
+
+#define ADM_CMD_TYPE_SINGLE 0x0
+#define ADM_CMD_TYPE_BOX 0x3
+
+#define ADM_CRCI_MUX_SEL BIT(4)
+#define ADM_DESC_ALIGN 8
+#define ADM_MAX_XFER (SZ_64K - 1)
+#define ADM_MAX_ROWS (SZ_64K - 1)
+#define ADM_MAX_CHANNELS 16
+
+struct adm_desc_hw_box {
+ u32 cmd;
+ u32 src_addr;
+ u32 dst_addr;
+ u32 row_len;
+ u32 num_rows;
+ u32 row_offset;
+};
+
+struct adm_desc_hw_single {
+ u32 cmd;
+ u32 src_addr;
+ u32 dst_addr;
+ u32 len;
+};
+
+struct adm_async_desc {
+ struct virt_dma_desc vd;
+ struct adm_device *adev;
+
+ size_t length;
+ enum dma_transfer_direction dir;
+ dma_addr_t dma_addr;
+ size_t dma_len;
+
+ void *cpl;
+ dma_addr_t cp_addr;
+ u32 crci;
+ u32 mux;
+ u32 blk_size;
+};
+
+struct adm_chan {
+ struct virt_dma_chan vc;
+ struct adm_device *adev;
+
+ /* parsed from DT */
+ u32 id; /* channel id */
+
+ struct adm_async_desc *curr_txd;
+ struct dma_slave_config slave;
+ struct list_head node;
+
+ int error;
+ int initialized;
+};
+
+static inline struct adm_chan *to_adm_chan(struct dma_chan *common)
+{
+ return container_of(common, struct adm_chan, vc.chan);
+}
+
+struct adm_device {
+ void __iomem *regs;
+ struct device *dev;
+ struct dma_device common;
+ struct device_dma_parameters dma_parms;
+ struct adm_chan *channels;
+
+ u32 ee;
+
+ struct clk *core_clk;
+ struct clk *iface_clk;
+
+ struct reset_control *clk_reset;
+ struct reset_control *c0_reset;
+ struct reset_control *c1_reset;
+ struct reset_control *c2_reset;
+ int irq;
+};
+
+/**
+ * adm_free_chan - Frees dma resources associated with the specific channel
+ *
+ * Free all allocated descriptors associated with this channel
+ *
+ */
+static void adm_free_chan(struct dma_chan *chan)
+{
+ /* free all queued descriptors */
+ vchan_free_chan_resources(to_virt_chan(chan));
+}
+
+/**
+ * adm_get_blksize - Get block size from burst value
+ *
+ */
+static int adm_get_blksize(unsigned int burst)
+{
+ int ret;
+
+ switch (burst) {
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ ret = ffs(burst >> 4) - 1;
+ break;
+ case 192:
+ ret = 4;
+ break;
+ case 256:
+ ret = 5;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * adm_process_fc_descriptors - Process descriptors for flow controlled xfers
+ *
+ * @achan: ADM channel
+ * @desc: Descriptor memory pointer
+ * @sg: Scatterlist entry
+ * @crci: CRCI value
+ * @burst: Burst size of transaction
+ * @direction: DMA transfer direction
+ */
+static void *adm_process_fc_descriptors(struct adm_chan *achan, void *desc,
+ struct scatterlist *sg, u32 crci,
+ u32 burst,
+ enum dma_transfer_direction direction)
+{
+ struct adm_desc_hw_box *box_desc = NULL;
+ struct adm_desc_hw_single *single_desc;
+ u32 remainder = sg_dma_len(sg);
+ u32 rows, row_offset, crci_cmd;
+ u32 mem_addr = sg_dma_address(sg);
+ u32 *incr_addr = &mem_addr;
+ u32 *src, *dst;
+
+ if (direction == DMA_DEV_TO_MEM) {
+ crci_cmd = ADM_CMD_SRC_CRCI(crci);
+ row_offset = burst;
+ src = &achan->slave.src_addr;
+ dst = &mem_addr;
+ } else {
+ crci_cmd = ADM_CMD_DST_CRCI(crci);
+ row_offset = burst << 16;
+ src = &mem_addr;
+ dst = &achan->slave.dst_addr;
+ }
+
+ while (remainder >= burst) {
+ box_desc = desc;
+ box_desc->cmd = ADM_CMD_TYPE_BOX | crci_cmd;
+ box_desc->row_offset = row_offset;
+ box_desc->src_addr = *src;
+ box_desc->dst_addr = *dst;
+
+ rows = remainder / burst;
+ rows = min_t(u32, rows, ADM_MAX_ROWS);
+ box_desc->num_rows = rows << 16 | rows;
+ box_desc->row_len = burst << 16 | burst;
+
+ *incr_addr += burst * rows;
+ remainder -= burst * rows;
+ desc += sizeof(*box_desc);
+ }
+
+ /* if leftover bytes, do one single descriptor */
+ if (remainder) {
+ single_desc = desc;
+ single_desc->cmd = ADM_CMD_TYPE_SINGLE | crci_cmd;
+ single_desc->len = remainder;
+ single_desc->src_addr = *src;
+ single_desc->dst_addr = *dst;
+ desc += sizeof(*single_desc);
+
+ if (sg_is_last(sg))
+ single_desc->cmd |= ADM_CMD_LC;
+ } else {
+ if (box_desc && sg_is_last(sg))
+ box_desc->cmd |= ADM_CMD_LC;
+ }
+
+ return desc;
+}
+
+/**
+ * adm_process_non_fc_descriptors - Process descriptors for non-fc xfers
+ *
+ * @achan: ADM channel
+ * @desc: Descriptor memory pointer
+ * @sg: Scatterlist entry
+ * @direction: DMA transfer direction
+ */
+static void *adm_process_non_fc_descriptors(struct adm_chan *achan, void *desc,
+ struct scatterlist *sg,
+ enum dma_transfer_direction direction)
+{
+ struct adm_desc_hw_single *single_desc;
+ u32 remainder = sg_dma_len(sg);
+ u32 mem_addr = sg_dma_address(sg);
+ u32 *incr_addr = &mem_addr;
+ u32 *src, *dst;
+
+ if (direction == DMA_DEV_TO_MEM) {
+ src = &achan->slave.src_addr;
+ dst = &mem_addr;
+ } else {
+ src = &mem_addr;
+ dst = &achan->slave.dst_addr;
+ }
+
+ do {
+ single_desc = desc;
+ single_desc->cmd = ADM_CMD_TYPE_SINGLE;
+ single_desc->src_addr = *src;
+ single_desc->dst_addr = *dst;
+ single_desc->len = (remainder > ADM_MAX_XFER) ?
+ ADM_MAX_XFER : remainder;
+
+ remainder -= single_desc->len;
+ *incr_addr += single_desc->len;
+ desc += sizeof(*single_desc);
+ } while (remainder);
+
+ /* set last command if this is the end of the whole transaction */
+ if (sg_is_last(sg))
+ single_desc->cmd |= ADM_CMD_LC;
+
+ return desc;
+}
+
+/**
+ * adm_prep_slave_sg - Prep slave sg transaction
+ *
+ * @chan: dma channel
+ * @sgl: scatter gather list
+ * @sg_len: length of sg
+ * @direction: DMA transfer direction
+ * @flags: DMA flags
+ * @context: transfer context (unused)
+ */
+static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan,
+ struct scatterlist *sgl,
+ unsigned int sg_len,
+ enum dma_transfer_direction direction,
+ unsigned long flags,
+ void *context)
+{
+ struct adm_chan *achan = to_adm_chan(chan);
+ struct adm_device *adev = achan->adev;
+ struct adm_async_desc *async_desc;
+ struct scatterlist *sg;
+ dma_addr_t cple_addr;
+ u32 i, burst;
+ u32 single_count = 0, box_count = 0, crci = 0;
+ void *desc;
+ u32 *cple;
+ int blk_size = 0;
+
+ if (!is_slave_direction(direction)) {
+ dev_err(adev->dev, "invalid dma direction\n");
+ return NULL;
+ }
+
+ /*
+ * get burst value from slave configuration
+ */
+ burst = (direction == DMA_MEM_TO_DEV) ?
+ achan->slave.dst_maxburst :
+ achan->slave.src_maxburst;
+
+ /* if using flow control, validate burst and crci values */
+ if (achan->slave.device_fc) {
+ blk_size = adm_get_blksize(burst);
+ if (blk_size < 0) {
+ dev_err(adev->dev, "invalid burst value: %d\n",
+ burst);
+ return ERR_PTR(-EINVAL);
+ }
+
+ crci = achan->slave.slave_id & 0xf;
+ if (!crci || achan->slave.slave_id > 0x1f) {
+ dev_err(adev->dev, "invalid crci value\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ /* iterate through sgs and compute allocation size of structures */
+ for_each_sg(sgl, sg, sg_len, i) {
+ if (achan->slave.device_fc) {
+ box_count += DIV_ROUND_UP(sg_dma_len(sg) / burst,
+ ADM_MAX_ROWS);
+ if (sg_dma_len(sg) % burst)
+ single_count++;
+ } else {
+ single_count += DIV_ROUND_UP(sg_dma_len(sg),
+ ADM_MAX_XFER);
+ }
+ }
+
+ async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT);
+ if (!async_desc)
+ return ERR_PTR(-ENOMEM);
+
+ if (crci)
+ async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ?
+ ADM_CRCI_CTL_MUX_SEL : 0;
+ async_desc->crci = crci;
+ async_desc->blk_size = blk_size;
+ async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) +
+ box_count * sizeof(struct adm_desc_hw_box) +
+ sizeof(*cple) + 2 * ADM_DESC_ALIGN;
+
+ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_NOWAIT);
+ if (!async_desc->cpl)
+ goto free;
+
+ async_desc->adev = adev;
+
+ /* both command list entry and descriptors must be 8 byte aligned */
+ cple = PTR_ALIGN(async_desc->cpl, ADM_DESC_ALIGN);
+ desc = PTR_ALIGN(cple + 1, ADM_DESC_ALIGN);
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ async_desc->length += sg_dma_len(sg);
+
+ if (achan->slave.device_fc)
+ desc = adm_process_fc_descriptors(achan, desc, sg, crci,
+ burst, direction);
+ else
+ desc = adm_process_non_fc_descriptors(achan, desc, sg,
+ direction);
+ }
+
+ async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl,
+ async_desc->dma_len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(adev->dev, async_desc->dma_addr))
+ goto free;
+
+ cple_addr = async_desc->dma_addr + ((void *)cple - async_desc->cpl);
+
+ /* init cmd list */
+ dma_sync_single_for_cpu(adev->dev, cple_addr, sizeof(*cple),
+ DMA_TO_DEVICE);
+ *cple = ADM_CPLE_LP;
+ *cple |= (async_desc->dma_addr + ADM_DESC_ALIGN) >> 3;
+ dma_sync_single_for_device(adev->dev, cple_addr, sizeof(*cple),
+ DMA_TO_DEVICE);
+
+ return vchan_tx_prep(&achan->vc, &async_desc->vd, flags);
+
+free:
+ kfree(async_desc);
+ return ERR_PTR(-ENOMEM);
+}
+
+/**
+ * adm_terminate_all - terminate all transactions on a channel
+ * @achan: adm dma channel
+ *
+ * Dequeues and frees all transactions, aborts current transaction
+ * No callbacks are done
+ *
+ */
+static int adm_terminate_all(struct dma_chan *chan)
+{
+ struct adm_chan *achan = to_adm_chan(chan);
+ struct adm_device *adev = achan->adev;
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&achan->vc.lock, flags);
+ vchan_get_all_descriptors(&achan->vc, &head);
+
+ /* send flush command to terminate current transaction */
+ writel_relaxed(0x0,
+ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee));
+
+ spin_unlock_irqrestore(&achan->vc.lock, flags);
+
+ vchan_dma_desc_free_list(&achan->vc, &head);
+
+ return 0;
+}
+
+static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg)
+{
+ struct adm_chan *achan = to_adm_chan(chan);
+ unsigned long flag;
+
+ spin_lock_irqsave(&achan->vc.lock, flag);
+ memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config));
+ spin_unlock_irqrestore(&achan->vc.lock, flag);
+
+ return 0;
+}
+
+/**
+ * adm_start_dma - start next transaction
+ * @achan - ADM dma channel
+ */
+static void adm_start_dma(struct adm_chan *achan)
+{
+ struct virt_dma_desc *vd = vchan_next_desc(&achan->vc);
+ struct adm_device *adev = achan->adev;
+ struct adm_async_desc *async_desc;
+
+ lockdep_assert_held(&achan->vc.lock);
+
+ if (!vd)
+ return;
+
+ list_del(&vd->node);
+
+ /* write next command list out to the CMD FIFO */
+ async_desc = container_of(vd, struct adm_async_desc, vd);
+ achan->curr_txd = async_desc;
+
+ /* reset channel error */
+ achan->error = 0;
+
+ if (!achan->initialized) {
+ /* enable interrupts */
+ writel(ADM_CH_CONF_SHADOW_EN |
+ ADM_CH_CONF_PERM_MPU_CONF |
+ ADM_CH_CONF_MPU_DISABLE |
+ ADM_CH_CONF_SEC_DOMAIN(adev->ee),
+ adev->regs + ADM_CH_CONF(achan->id));
+
+ writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN,
+ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee));
+
+ achan->initialized = 1;
+ }
+
+ /* set the crci block size if this transaction requires CRCI */
+ if (async_desc->crci) {
+ writel(async_desc->mux | async_desc->blk_size,
+ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee));
+ }
+
+ /* make sure IRQ enable doesn't get reordered */
+ wmb();
+
+ /* write next command list out to the CMD FIFO */
+ writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3,
+ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee));
+}
+
+/**
+ * adm_dma_irq - irq handler for ADM controller
+ * @irq: IRQ of interrupt
+ * @data: callback data
+ *
+ * IRQ handler for the bam controller
+ */
+static irqreturn_t adm_dma_irq(int irq, void *data)
+{
+ struct adm_device *adev = data;
+ u32 srcs, i;
+ struct adm_async_desc *async_desc;
+ unsigned long flags;
+
+ srcs = readl_relaxed(adev->regs +
+ ADM_SEC_DOMAIN_IRQ_STATUS(adev->ee));
+
+ for (i = 0; i < ADM_MAX_CHANNELS; i++) {
+ struct adm_chan *achan = &adev->channels[i];
+ u32 status, result;
+
+ if (srcs & BIT(i)) {
+ status = readl_relaxed(adev->regs +
+ ADM_CH_STATUS_SD(i, adev->ee));
+
+ /* if no result present, skip */
+ if (!(status & ADM_CH_STATUS_VALID))
+ continue;
+
+ result = readl_relaxed(adev->regs +
+ ADM_CH_RSLT(i, adev->ee));
+
+ /* no valid results, skip */
+ if (!(result & ADM_CH_RSLT_VALID))
+ continue;
+
+ /* flag error if transaction was flushed or failed */
+ if (result & (ADM_CH_RSLT_ERR | ADM_CH_RSLT_FLUSH))
+ achan->error = 1;
+
+ spin_lock_irqsave(&achan->vc.lock, flags);
+ async_desc = achan->curr_txd;
+
+ achan->curr_txd = NULL;
+
+ if (async_desc) {
+ vchan_cookie_complete(&async_desc->vd);
+
+ /* kick off next DMA */
+ adm_start_dma(achan);
+ }
+
+ spin_unlock_irqrestore(&achan->vc.lock, flags);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * adm_tx_status - returns status of transaction
+ * @chan: dma channel
+ * @cookie: transaction cookie
+ * @txstate: DMA transaction state
+ *
+ * Return status of dma transaction
+ */
+static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct adm_chan *achan = to_adm_chan(chan);
+ struct virt_dma_desc *vd;
+ enum dma_status ret;
+ unsigned long flags;
+ size_t residue = 0;
+
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (ret == DMA_COMPLETE || !txstate)
+ return ret;
+
+ spin_lock_irqsave(&achan->vc.lock, flags);
+
+ vd = vchan_find_desc(&achan->vc, cookie);
+ if (vd)
+ residue = container_of(vd, struct adm_async_desc, vd)->length;
+
+ spin_unlock_irqrestore(&achan->vc.lock, flags);
+
+ /*
+ * residue is either the full length if it is in the issued list, or 0
+ * if it is in progress. We have no reliable way of determining
+ * anything inbetween
+ */
+ dma_set_residue(txstate, residue);
+
+ if (achan->error)
+ return DMA_ERROR;
+
+ return ret;
+}
+
+/**
+ * adm_issue_pending - starts pending transactions
+ * @chan: dma channel
+ *
+ * Issues all pending transactions and starts DMA
+ */
+static void adm_issue_pending(struct dma_chan *chan)
+{
+ struct adm_chan *achan = to_adm_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&achan->vc.lock, flags);
+
+ if (vchan_issue_pending(&achan->vc) && !achan->curr_txd)
+ adm_start_dma(achan);
+ spin_unlock_irqrestore(&achan->vc.lock, flags);
+}
+
+/**
+ * adm_dma_free_desc - free descriptor memory
+ * @vd: virtual descriptor
+ *
+ */
+static void adm_dma_free_desc(struct virt_dma_desc *vd)
+{
+ struct adm_async_desc *async_desc = container_of(vd,
+ struct adm_async_desc, vd);
+
+ dma_unmap_single(async_desc->adev->dev, async_desc->dma_addr,
+ async_desc->dma_len, DMA_TO_DEVICE);
+ kfree(async_desc->cpl);
+ kfree(async_desc);
+}
+
+static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan,
+ u32 index)
+{
+ achan->id = index;
+ achan->adev = adev;
+
+ vchan_init(&achan->vc, &adev->common);
+ achan->vc.desc_free = adm_dma_free_desc;
+}
+
+static int adm_dma_probe(struct platform_device *pdev)
+{
+ struct adm_device *adev;
+ int ret;
+ u32 i;
+
+ adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL);
+ if (!adev)
+ return -ENOMEM;
+
+ adev->dev = &pdev->dev;
+
+ adev->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(adev->regs))
+ return PTR_ERR(adev->regs);
+
+ adev->irq = platform_get_irq(pdev, 0);
+ if (adev->irq < 0)
+ return adev->irq;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &adev->ee);
+ if (ret) {
+ dev_err(adev->dev, "Execution environment unspecified\n");
+ return ret;
+ }
+
+ adev->core_clk = devm_clk_get(adev->dev, "core");
+ if (IS_ERR(adev->core_clk))
+ return PTR_ERR(adev->core_clk);
+
+ adev->iface_clk = devm_clk_get(adev->dev, "iface");
+ if (IS_ERR(adev->iface_clk))
+ return PTR_ERR(adev->iface_clk);
+
+ adev->clk_reset = devm_reset_control_get_exclusive(&pdev->dev, "clk");
+ if (IS_ERR(adev->clk_reset)) {
+ dev_err(adev->dev, "failed to get ADM0 reset\n");
+ return PTR_ERR(adev->clk_reset);
+ }
+
+ adev->c0_reset = devm_reset_control_get_exclusive(&pdev->dev, "c0");
+ if (IS_ERR(adev->c0_reset)) {
+ dev_err(adev->dev, "failed to get ADM0 C0 reset\n");
+ return PTR_ERR(adev->c0_reset);
+ }
+
+ adev->c1_reset = devm_reset_control_get_exclusive(&pdev->dev, "c1");
+ if (IS_ERR(adev->c1_reset)) {
+ dev_err(adev->dev, "failed to get ADM0 C1 reset\n");
+ return PTR_ERR(adev->c1_reset);
+ }
+
+ adev->c2_reset = devm_reset_control_get_exclusive(&pdev->dev, "c2");
+ if (IS_ERR(adev->c2_reset)) {
+ dev_err(adev->dev, "failed to get ADM0 C2 reset\n");
+ return PTR_ERR(adev->c2_reset);
+ }
+
+ ret = clk_prepare_enable(adev->core_clk);
+ if (ret) {
+ dev_err(adev->dev, "failed to prepare/enable core clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(adev->iface_clk);
+ if (ret) {
+ dev_err(adev->dev, "failed to prepare/enable iface clock\n");
+ goto err_disable_core_clk;
+ }
+
+ reset_control_assert(adev->clk_reset);
+ reset_control_assert(adev->c0_reset);
+ reset_control_assert(adev->c1_reset);
+ reset_control_assert(adev->c2_reset);
+
+ udelay(2);
+
+ reset_control_deassert(adev->clk_reset);
+ reset_control_deassert(adev->c0_reset);
+ reset_control_deassert(adev->c1_reset);
+ reset_control_deassert(adev->c2_reset);
+
+ adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS,
+ sizeof(*adev->channels), GFP_KERNEL);
+
+ if (!adev->channels) {
+ ret = -ENOMEM;
+ goto err_disable_clks;
+ }
+
+ /* allocate and initialize channels */
+ INIT_LIST_HEAD(&adev->common.channels);
+
+ for (i = 0; i < ADM_MAX_CHANNELS; i++)
+ adm_channel_init(adev, &adev->channels[i], i);
+
+ /* reset CRCIs */
+ for (i = 0; i < 16; i++)
+ writel(ADM_CRCI_CTL_RST, adev->regs +
+ ADM_CRCI_CTL(i, adev->ee));
+
+ /* configure client interfaces */
+ writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) |
+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0));
+ writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) |
+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1));
+ writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) |
+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2));
+ writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf),
+ adev->regs + ADM_GP_CTL);
+
+ ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq,
+ 0, "adm_dma", adev);
+ if (ret)
+ goto err_disable_clks;
+
+ platform_set_drvdata(pdev, adev);
+
+ adev->common.dev = adev->dev;
+ adev->common.dev->dma_parms = &adev->dma_parms;
+
+ /* set capabilities */
+ dma_cap_zero(adev->common.cap_mask);
+ dma_cap_set(DMA_SLAVE, adev->common.cap_mask);
+ dma_cap_set(DMA_PRIVATE, adev->common.cap_mask);
+
+ /* initialize dmaengine apis */
+ adev->common.directions = BIT(DMA_DEV_TO_MEM | DMA_MEM_TO_DEV);
+ adev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+ adev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ adev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ adev->common.device_free_chan_resources = adm_free_chan;
+ adev->common.device_prep_slave_sg = adm_prep_slave_sg;
+ adev->common.device_issue_pending = adm_issue_pending;
+ adev->common.device_tx_status = adm_tx_status;
+ adev->common.device_terminate_all = adm_terminate_all;
+ adev->common.device_config = adm_slave_config;
+
+ ret = dma_async_device_register(&adev->common);
+ if (ret) {
+ dev_err(adev->dev, "failed to register dma async device\n");
+ goto err_disable_clks;
+ }
+
+ ret = of_dma_controller_register(pdev->dev.of_node,
+ of_dma_xlate_by_chan_id,
+ &adev->common);
+ if (ret)
+ goto err_unregister_dma;
+
+ return 0;
+
+err_unregister_dma:
+ dma_async_device_unregister(&adev->common);
+err_disable_clks:
+ clk_disable_unprepare(adev->iface_clk);
+err_disable_core_clk:
+ clk_disable_unprepare(adev->core_clk);
+
+ return ret;
+}
+
+static int adm_dma_remove(struct platform_device *pdev)
+{
+ struct adm_device *adev = platform_get_drvdata(pdev);
+ struct adm_chan *achan;
+ u32 i;
+
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(&adev->common);
+
+ for (i = 0; i < ADM_MAX_CHANNELS; i++) {
+ achan = &adev->channels[i];
+
+ /* mask IRQs for this channel/EE pair */
+ writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee));
+
+ tasklet_kill(&adev->channels[i].vc.task);
+ adm_terminate_all(&adev->channels[i].vc.chan);
+ }
+
+ devm_free_irq(adev->dev, adev->irq, adev);
+
+ clk_disable_unprepare(adev->core_clk);
+ clk_disable_unprepare(adev->iface_clk);
+
+ return 0;
+}
+
+static const struct of_device_id adm_of_match[] = {
+ { .compatible = "qcom,adm", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, adm_of_match);
+
+static struct platform_driver adm_dma_driver = {
+ .probe = adm_dma_probe,
+ .remove = adm_dma_remove,
+ .driver = {
+ .name = "adm-dma-engine",
+ .of_match_table = adm_of_match,
+ },
+};
+
+module_platform_driver(adm_dma_driver);
+
+MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
+MODULE_DESCRIPTION("QCOM ADM DMA engine driver");
+MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,217 @@
From 803eb124e1a64e42888542c3444bfe6dac412c7f Mon Sep 17 00:00:00 2001
From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Date: Mon, 4 Jan 2021 09:41:35 +0530
Subject: mtd: parsers: Add Qcom SMEM parser
NAND based Qualcomm platforms have the partition table populated in the
Shared Memory (SMEM). Hence, add a parser for parsing the partitions
from it.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadhasivam@linaro.org
---
drivers/mtd/parsers/Kconfig | 8 ++
drivers/mtd/parsers/Makefile | 1 +
drivers/mtd/parsers/qcomsmempart.c | 170 +++++++++++++++++++++++++++++++++++++
3 files changed, 179 insertions(+)
create mode 100644 drivers/mtd/parsers/qcomsmempart.c
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -196,6 +196,14 @@ config MTD_REDBOOT_PARTS_READONLY
endif # MTD_REDBOOT_PARTS
+config MTD_QCOMSMEM_PARTS
+ tristate "Qualcomm SMEM NAND flash partition parser"
+ depends on MTD_NAND_QCOM || COMPILE_TEST
+ depends on QCOM_SMEM
+ help
+ This provides support for parsing partitions from Shared Memory (SMEM)
+ for NAND flash on Qualcomm platforms.
+
config MTD_ROUTERBOOT_PARTS
tristate "RouterBoot flash partition parser"
depends on MTD && OF
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -13,4 +13,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
+obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o
obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o
--- /dev/null
+++ b/drivers/mtd/parsers/qcomsmempart.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Qualcomm SMEM NAND flash partition parser
+ *
+ * Copyright (C) 2020, Linaro Ltd.
+ */
+
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/smem.h>
+
+#define SMEM_AARM_PARTITION_TABLE 9
+#define SMEM_APPS 0
+
+#define SMEM_FLASH_PART_MAGIC1 0x55ee73aa
+#define SMEM_FLASH_PART_MAGIC2 0xe35ebddb
+#define SMEM_FLASH_PTABLE_V3 3
+#define SMEM_FLASH_PTABLE_V4 4
+#define SMEM_FLASH_PTABLE_MAX_PARTS_V3 16
+#define SMEM_FLASH_PTABLE_MAX_PARTS_V4 48
+#define SMEM_FLASH_PTABLE_HDR_LEN (4 * sizeof(u32))
+#define SMEM_FLASH_PTABLE_NAME_SIZE 16
+
+/**
+ * struct smem_flash_pentry - SMEM Flash partition entry
+ * @name: Name of the partition
+ * @offset: Offset in blocks
+ * @length: Length of the partition in blocks
+ * @attr: Flags for this partition
+ */
+struct smem_flash_pentry {
+ char name[SMEM_FLASH_PTABLE_NAME_SIZE];
+ __le32 offset;
+ __le32 length;
+ u8 attr;
+} __packed __aligned(4);
+
+/**
+ * struct smem_flash_ptable - SMEM Flash partition table
+ * @magic1: Partition table Magic 1
+ * @magic2: Partition table Magic 2
+ * @version: Partition table version
+ * @numparts: Number of partitions in this ptable
+ * @pentry: Flash partition entries belonging to this ptable
+ */
+struct smem_flash_ptable {
+ __le32 magic1;
+ __le32 magic2;
+ __le32 version;
+ __le32 numparts;
+ struct smem_flash_pentry pentry[SMEM_FLASH_PTABLE_MAX_PARTS_V4];
+} __packed __aligned(4);
+
+static int parse_qcomsmem_part(struct mtd_info *mtd,
+ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+{
+ struct smem_flash_pentry *pentry;
+ struct smem_flash_ptable *ptable;
+ size_t len = SMEM_FLASH_PTABLE_HDR_LEN;
+ struct mtd_partition *parts;
+ int ret, i, numparts;
+ char *name, *c;
+
+ pr_debug("Parsing partition table info from SMEM\n");
+ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len);
+ if (IS_ERR(ptable)) {
+ pr_err("Error reading partition table header\n");
+ return PTR_ERR(ptable);
+ }
+
+ /* Verify ptable magic */
+ if (le32_to_cpu(ptable->magic1) != SMEM_FLASH_PART_MAGIC1 ||
+ le32_to_cpu(ptable->magic2) != SMEM_FLASH_PART_MAGIC2) {
+ pr_err("Partition table magic verification failed\n");
+ return -EINVAL;
+ }
+
+ /* Ensure that # of partitions is less than the max we have allocated */
+ numparts = le32_to_cpu(ptable->numparts);
+ if (numparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) {
+ pr_err("Partition numbers exceed the max limit\n");
+ return -EINVAL;
+ }
+
+ /* Find out length of partition data based on table version */
+ if (le32_to_cpu(ptable->version) <= SMEM_FLASH_PTABLE_V3) {
+ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V3 *
+ sizeof(struct smem_flash_pentry);
+ } else if (le32_to_cpu(ptable->version) == SMEM_FLASH_PTABLE_V4) {
+ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V4 *
+ sizeof(struct smem_flash_pentry);
+ } else {
+ pr_err("Unknown ptable version (%d)", le32_to_cpu(ptable->version));
+ return -EINVAL;
+ }
+
+ /*
+ * Now that the partition table header has been parsed, verified
+ * and the length of the partition table calculated, read the
+ * complete partition table
+ */
+ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len);
+ if (IS_ERR_OR_NULL(ptable)) {
+ pr_err("Error reading partition table\n");
+ return PTR_ERR(ptable);
+ }
+
+ parts = kcalloc(numparts, sizeof(*parts), GFP_KERNEL);
+ if (!parts)
+ return -ENOMEM;
+
+ for (i = 0; i < numparts; i++) {
+ pentry = &ptable->pentry[i];
+ if (pentry->name[0] == '\0')
+ continue;
+
+ name = kstrdup(pentry->name, GFP_KERNEL);
+ if (!name) {
+ ret = -ENOMEM;
+ goto out_free_parts;
+ }
+
+ /* Convert name to lower case */
+ for (c = name; *c != '\0'; c++)
+ *c = tolower(*c);
+
+ parts[i].name = name;
+ parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize;
+ parts[i].mask_flags = pentry->attr;
+ parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize;
+ pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n",
+ i, pentry->name, le32_to_cpu(pentry->offset),
+ le32_to_cpu(pentry->length), pentry->attr);
+ }
+
+ pr_debug("SMEM partition table found: ver: %d len: %d\n",
+ le32_to_cpu(ptable->version), numparts);
+ *pparts = parts;
+
+ return numparts;
+
+out_free_parts:
+ while (--i >= 0)
+ kfree(parts[i].name);
+ kfree(parts);
+ *pparts = NULL;
+
+ return ret;
+}
+
+static const struct of_device_id qcomsmem_of_match_table[] = {
+ { .compatible = "qcom,smem-part" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, qcomsmem_of_match_table);
+
+static struct mtd_part_parser mtd_parser_qcomsmem = {
+ .parse_fn = parse_qcomsmem_part,
+ .name = "qcomsmem",
+ .of_match_table = qcomsmem_of_match_table,
+};
+module_mtd_part_parser(mtd_parser_qcomsmem);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm SMEM NAND flash partition parser");

View File

@ -0,0 +1,83 @@
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
@@ -64,6 +64,17 @@
#define NSS_COMMON_CLK_DIV_SGMII_100 4
#define NSS_COMMON_CLK_DIV_SGMII_10 49
+#define QSGMII_PCS_ALL_CH_CTL 0x80
+#define QSGMII_PCS_CH_SPEED_FORCE 0x2
+#define QSGMII_PCS_CH_SPEED_10 0x0
+#define QSGMII_PCS_CH_SPEED_100 0x4
+#define QSGMII_PCS_CH_SPEED_1000 0x8
+#define QSGMII_PCS_CH_SPEED_MASK (QSGMII_PCS_CH_SPEED_FORCE | \
+ QSGMII_PCS_CH_SPEED_10 | \
+ QSGMII_PCS_CH_SPEED_100 | \
+ QSGMII_PCS_CH_SPEED_1000)
+#define QSGMII_PCS_CH_SPEED_SHIFT(x) (x * 4)
+
#define QSGMII_PCS_CAL_LCKDT_CTL 0x120
#define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19)
@@ -242,6 +253,36 @@ static void ipq806x_gmac_fix_mac_speed(v
ipq806x_gmac_set_speed(gmac, speed);
}
+static int
+ipq806x_gmac_get_qsgmii_pcs_speed_val(struct platform_device *pdev) {
+ struct device_node *fixed_link_node;
+ int rv;
+ int fixed_link_speed;
+
+ if (!of_phy_is_fixed_link(pdev->dev.of_node))
+ return 0;
+
+ fixed_link_node = of_get_child_by_name(pdev->dev.of_node, "fixed-link");
+ if (!fixed_link_node)
+ return -1;
+
+ rv = of_property_read_u32(fixed_link_node, "speed", &fixed_link_speed);
+ of_node_put(fixed_link_node);
+ if (rv)
+ return -1;
+
+ switch (fixed_link_speed) {
+ case SPEED_1000:
+ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_1000;
+ case SPEED_100:
+ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_100;
+ case SPEED_10:
+ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_10;
+ }
+
+ return -1;
+}
+
static int ipq806x_gmac_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
@@ -250,6 +291,7 @@ static int ipq806x_gmac_probe(struct pla
struct ipq806x_gmac *gmac;
int val;
int err;
+ int qsgmii_pcs_speed;
val = stmmac_get_platform_resources(pdev, &stmmac_res);
if (val)
@@ -339,6 +381,17 @@ static int ipq806x_gmac_probe(struct pla
0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET);
+
+ qsgmii_pcs_speed = ipq806x_gmac_get_qsgmii_pcs_speed_val(pdev);
+ if (qsgmii_pcs_speed != -1) {
+ regmap_update_bits(
+ gmac->qsgmii_csr,
+ QSGMII_PCS_ALL_CH_CTL,
+ QSGMII_PCS_CH_SPEED_MASK <<
+ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id),
+ qsgmii_pcs_speed <<
+ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id));
+ }
}
plat_dat->has_gmac = true;

View File

@ -0,0 +1,24 @@
From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 9 Mar 2017 09:31:44 +0100
Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting
Signed-off-by: John Crispin <john@phrozen.org>
---
drivers/mtd/parsers/qcomsmempart.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/mtd/parsers/qcomsmempart.c
+++ b/drivers/mtd/parsers/qcomsmempart.c
@@ -132,6 +132,11 @@ static int parse_qcomsmem_part(struct mt
parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize;
parts[i].mask_flags = pentry->attr;
parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize;
+
+ /* "rootfs" conflicts with OpenWrt auto mounting */
+ if (mtd_type_is_nand(mtd) && !strcmp(name, "rootfs"))
+ parts[i].name = "ubi";
+
pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n",
i, pentry->name, le32_to_cpu(pentry->offset),
le32_to_cpu(pentry->length), pentry->attr);

View File

@ -0,0 +1,46 @@
From 84909e85881d67244240c9f40974ce12a51e3886 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Tue, 11 May 2021 23:09:45 +0200
Subject: [PATCH] ARM: dts: qcom: reduce pci IO size to 64K
The current value is probably a typo and is actually uncommon to find
1MB IO space even on a x86 arch. Also with recent changes to the pci
driver, pci1 and pci2 now fails to function as any connected device
fails any reg read/write. Reduce this to 64K as it should be more than
enough and 3 * 64K of total IO space doesn't exceed the IO_SPACE_LIMIT
hardcoded for the ARM arch.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
arch/arm/boot/dts/qcom-ipq8064.dtsi | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -1163,7 +1163,7 @@
#address-cells = <3>;
#size-cells = <2>;
- ranges = <0x81000000 0 0x0fe00000 0x0fe00000 0 0x00100000 /* downstream I/O */
+ ranges = <0x81000000 0 0x0fe00000 0x0fe00000 0 0x00010000 /* downstream I/O */
0x82000000 0 0x08000000 0x08000000 0 0x07e00000>; /* non-prefetchable memory */
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
@@ -1214,7 +1214,7 @@
#address-cells = <3>;
#size-cells = <2>;
- ranges = <0x81000000 0 0x31e00000 0x31e00000 0 0x00100000 /* downstream I/O */
+ ranges = <0x81000000 0 0x31e00000 0x31e00000 0 0x00010000 /* downstream I/O */
0x82000000 0 0x2e000000 0x2e000000 0 0x03e00000>; /* non-prefetchable memory */
interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
@@ -1265,7 +1265,7 @@
#address-cells = <3>;
#size-cells = <2>;
- ranges = <0x81000000 0 0x35e00000 0x35e00000 0 0x00100000 /* downstream I/O */
+ ranges = <0x81000000 0 0x35e00000 0x35e00000 0 0x00010000 /* downstream I/O */
0x82000000 0 0x32000000 0x32000000 0 0x03e00000>; /* non-prefetchable memory */
interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;

View File

@ -0,0 +1,285 @@
From 5c7d1181056feef0b58fb2f556f55e170ba5b479 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sat, 25 Jul 2020 19:14:59 +0200
Subject: [PATCH 01/10] drivers: thermal: tsens: Add VER_0 tsens version
VER_0 is used to describe device based on tsens version before v0.1.
These device are devices based on msm8960 for example apq8064 or
ipq806x.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org>
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
---
drivers/thermal/qcom/tsens.c | 150 ++++++++++++++++++++++++++++-------
drivers/thermal/qcom/tsens.h | 4 +-
2 files changed, 124 insertions(+), 30 deletions(-)
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -12,6 +12,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
+#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/regmap.h>
@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int
dev_dbg(priv->dev, "[%u] %s: no violation: %d\n",
hw_id, __func__, temp);
}
+
+ if (tsens_version(priv) < VER_0_1) {
+ /* Constraint: There is only 1 interrupt control register for all
+ * 11 temperature sensor. So monitoring more than 1 sensor based
+ * on interrupts will yield inconsistent result. To overcome this
+ * issue we will monitor only sensor 0 which is the master sensor.
+ */
+ break;
+ }
}
return IRQ_HANDLED;
@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor
int high_val, low_val, cl_high, cl_low;
u32 hw_id = s->hw_id;
+ if (tsens_version(priv) < VER_0_1) {
+ /* Pre v0.1 IP had a single register for each type of interrupt
+ * and thresholds
+ */
+ hw_id = 0;
+ }
+
dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
hw_id, __func__, low, high);
@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct ts
u32 valid;
int ret;
- ret = regmap_field_read(priv->rf[valid_idx], &valid);
- if (ret)
- return ret;
- while (!valid) {
- /* Valid bit is 0 for 6 AHB clock cycles.
- * At 19.2MHz, 1 AHB clock is ~60ns.
- * We should enter this loop very, very rarely.
- */
- ndelay(400);
+ /* VER_0 doesn't have VALID bit */
+ if (tsens_version(priv) >= VER_0_1) {
ret = regmap_field_read(priv->rf[valid_idx], &valid);
if (ret)
return ret;
+ while (!valid) {
+ /* Valid bit is 0 for 6 AHB clock cycles.
+ * At 19.2MHz, 1 AHB clock is ~60ns.
+ * We should enter this loop very, very rarely.
+ */
+ ndelay(400);
+ ret = regmap_field_read(priv->rf[valid_idx], &valid);
+ if (ret)
+ return ret;
+ }
}
/* Valid bit is set, OK to read the temperature */
@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_s
{
struct tsens_priv *priv = s->priv;
int hw_id = s->hw_id;
- int last_temp = 0, ret;
+ int last_temp = 0, ret, trdy;
+ unsigned long timeout;
- ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp);
- if (ret)
- return ret;
+ timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
+ do {
+ if (tsens_version(priv) == VER_0) {
+ ret = regmap_field_read(priv->rf[TRDY], &trdy);
+ if (ret)
+ return ret;
+ if (!trdy)
+ continue;
+ }
- *temp = code_to_degc(last_temp, s) * 1000;
+ ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp);
+ if (ret)
+ return ret;
- return 0;
+ *temp = code_to_degc(last_temp, s) * 1000;
+
+ return 0;
+ } while (time_before(jiffies, timeout));
+
+ return -ETIMEDOUT;
}
#ifdef CONFIG_DEBUG_FS
@@ -738,19 +772,34 @@ int __init init_common(struct tsens_priv
priv->tm_offset = 0x1000;
}
- res = platform_get_resource(op, IORESOURCE_MEM, 0);
- tm_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(tm_base)) {
- ret = PTR_ERR(tm_base);
- goto err_put_device;
+ if (tsens_version(priv) >= VER_0_1) {
+ res = platform_get_resource(op, IORESOURCE_MEM, 0);
+ tm_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(tm_base)) {
+ ret = PTR_ERR(tm_base);
+ goto err_put_device;
+ }
+
+ priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
+ } else { /* VER_0 share the same gcc regs using a syscon */
+ struct device *parent = priv->dev->parent;
+
+ if (parent)
+ priv->tm_map = syscon_node_to_regmap(parent->of_node);
}
- priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
- if (IS_ERR(priv->tm_map)) {
- ret = PTR_ERR(priv->tm_map);
+ if (IS_ERR_OR_NULL(priv->tm_map)) {
+ if (!priv->tm_map)
+ ret = -ENODEV;
+ else
+ ret = PTR_ERR(priv->tm_map);
goto err_put_device;
}
+ /* VER_0 have only tm_map */
+ if (!priv->srot_map)
+ priv->srot_map = priv->tm_map;
+
if (tsens_version(priv) > VER_0_1) {
for (i = VER_MAJOR; i <= VER_STEP; i++) {
priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map,
@@ -771,6 +820,10 @@ int __init init_common(struct tsens_priv
ret = PTR_ERR(priv->rf[TSENS_EN]);
goto err_put_device;
}
+ /* in VER_0 TSENS need to be explicitly enabled */
+ if (tsens_version(priv) == VER_0)
+ regmap_field_write(priv->rf[TSENS_EN], 1);
+
ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
if (ret)
goto err_put_device;
@@ -793,6 +846,19 @@ int __init init_common(struct tsens_priv
goto err_put_device;
}
+ priv->rf[TSENS_SW_RST] =
+ devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]);
+ if (IS_ERR(priv->rf[TSENS_SW_RST])) {
+ ret = PTR_ERR(priv->rf[TSENS_SW_RST]);
+ goto err_put_device;
+ }
+
+ priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]);
+ if (IS_ERR(priv->rf[TRDY])) {
+ ret = PTR_ERR(priv->rf[TRDY]);
+ goto err_put_device;
+ }
+
/* This loop might need changes if enum regfield_ids is reordered */
for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) {
for (i = 0; i < priv->feat->max_sensors; i++) {
@@ -808,7 +874,7 @@ int __init init_common(struct tsens_priv
}
}
- if (priv->feat->crit_int) {
+ if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) {
/* Loop might need changes if enum regfield_ids is reordered */
for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) {
for (i = 0; i < priv->feat->max_sensors; i++) {
@@ -846,7 +912,11 @@ int __init init_common(struct tsens_priv
}
spin_lock_init(&priv->ul_lock);
- tsens_enable_irq(priv);
+
+ /* VER_0 interrupt doesn't need to be enabled */
+ if (tsens_version(priv) >= VER_0_1)
+ tsens_enable_irq(priv);
+
tsens_debug_init(op);
err_put_device:
@@ -945,10 +1015,19 @@ static int tsens_register_irq(struct tse
if (irq == -ENXIO)
ret = 0;
} else {
- ret = devm_request_threaded_irq(&pdev->dev, irq,
- NULL, thread_fn,
- IRQF_ONESHOT,
- dev_name(&pdev->dev), priv);
+ /* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */
+ if (tsens_version(priv) == VER_0)
+ ret = devm_request_threaded_irq(&pdev->dev, irq,
+ thread_fn, NULL,
+ IRQF_TRIGGER_RISING,
+ dev_name(&pdev->dev),
+ priv);
+ else
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ thread_fn, IRQF_ONESHOT,
+ dev_name(&pdev->dev),
+ priv);
+
if (ret)
dev_err(&pdev->dev, "%s: failed to get irq\n",
__func__);
@@ -977,6 +1056,19 @@ static int tsens_register(struct tsens_p
priv->ops->enable(priv, i);
}
+ /* VER_0 require to set MIN and MAX THRESH
+ * These 2 regs are set using the:
+ * - CRIT_THRESH_0 for MAX THRESH hardcoded to 120°C
+ * - CRIT_THRESH_1 for MIN THRESH hardcoded to 0°C
+ */
+ if (tsens_version(priv) < VER_0_1) {
+ regmap_field_write(priv->rf[CRIT_THRESH_0],
+ tsens_mC_to_hw(priv->sensor, 120000));
+
+ regmap_field_write(priv->rf[CRIT_THRESH_1],
+ tsens_mC_to_hw(priv->sensor, 0));
+ }
+
ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
if (ret < 0)
return ret;
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -13,6 +13,7 @@
#define CAL_DEGC_PT2 120
#define SLOPE_FACTOR 1000
#define SLOPE_DEFAULT 3200
+#define TIMEOUT_US 100
#define THRESHOLD_MAX_ADC_CODE 0x3ff
#define THRESHOLD_MIN_ADC_CODE 0x0
@@ -25,7 +26,8 @@ struct tsens_priv;
/* IP version numbers in ascending order */
enum tsens_ver {
- VER_0_1 = 0,
+ VER_0 = 0,
+ VER_0_1,
VER_1_X,
VER_2_X,
};

View File

@ -0,0 +1,28 @@
From efa0d50a6c5ec7619371dfe4d3e6ca54b73787d5 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Wed, 25 Nov 2020 16:47:21 +0100
Subject: [PATCH 02/10] drivers: thermal: tsens: Don't hardcode sensor slope
Function compute_intercept_slope hardcode the sensor slope to
SLOPE_DEFAULT. Change this and use the default value only if a slope is
not defined. This is needed for tsens VER_0 that has a hardcoded slope
table.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org>
---
drivers/thermal/qcom/tsens.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsen
"%s: sensor%d - data_point1:%#x data_point2:%#x\n",
__func__, i, p1[i], p2[i]);
- priv->sensor[i].slope = SLOPE_DEFAULT;
+ if (!priv->sensor[i].slope)
+ priv->sensor[i].slope = SLOPE_DEFAULT;
if (mode == TWO_PT_CALIB) {
/*
* slope (m) = adc_code2 - adc_code1 (y2 - y1)/

View File

@ -0,0 +1,119 @@
From 6bac2e2fa36c2d7c304768a689d8b73155b90aa2 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Wed, 25 Nov 2020 17:15:51 +0100
Subject: [PATCH 03/10] drivers: thermal: tsens: Convert msm8960 to reg_field
Convert msm9860 driver to reg_field to use the init_common
function.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Acked-by: Thara Gopinath <thara.gopinath@linaro.org>
---
drivers/thermal/qcom/tsens-8960.c | 80 ++++++++++++++++++++++++++++++-
1 file changed, 79 insertions(+), 1 deletion(-)
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -51,11 +51,22 @@
#define MIN_LIMIT_TH 0x0
#define MAX_LIMIT_TH 0xff
-#define S0_STATUS_ADDR 0x3628
#define INT_STATUS_ADDR 0x363c
#define TRDY_MASK BIT(7)
#define TIMEOUT_US 100
+#define S0_STATUS_OFF 0x3628
+#define S1_STATUS_OFF 0x362c
+#define S2_STATUS_OFF 0x3630
+#define S3_STATUS_OFF 0x3634
+#define S4_STATUS_OFF 0x3638
+#define S5_STATUS_OFF 0x3664 /* Sensors 5-10 found on apq8064/msm8960 */
+#define S6_STATUS_OFF 0x3668
+#define S7_STATUS_OFF 0x366c
+#define S8_STATUS_OFF 0x3670
+#define S9_STATUS_OFF 0x3674
+#define S10_STATUS_OFF 0x3678
+
static int suspend_8960(struct tsens_priv *priv)
{
int ret;
@@ -269,6 +280,71 @@ static int get_temp_8960(const struct ts
return -ETIMEDOUT;
}
+static struct tsens_features tsens_8960_feat = {
+ .ver_major = VER_0,
+ .crit_int = 0,
+ .adc = 1,
+ .srot_split = 0,
+ .max_sensors = 11,
+};
+
+static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
+ /* ----- SROT ------ */
+ /* No VERSION information */
+
+ /* CNTL */
+ [TSENS_EN] = REG_FIELD(CNTL_ADDR, 0, 0),
+ [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR, 1, 1),
+ /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */
+ [SENSOR_EN] = REG_FIELD(CNTL_ADDR, 3, 7),
+
+ /* ----- TM ------ */
+ /* INTERRUPT ENABLE */
+ /* NO INTERRUPT ENABLE */
+
+ /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */
+ [LOW_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 0, 7),
+ [UP_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 8, 15),
+ /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield
+ * Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp
+ * MIN_THRESH_0 -> CRIT_THRESH_1
+ * MAX_THRESH_0 -> CRIT_THRESH_0
+ */
+ [CRIT_THRESH_1] = REG_FIELD(THRESHOLD_ADDR, 16, 23),
+ [CRIT_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 24, 31),
+
+ /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */
+ /* 1 == clear, 0 == normal operation */
+ [LOW_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 9, 9),
+ [UP_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 10, 10),
+
+ /* NO CRITICAL INTERRUPT SUPPORT on 8960 */
+
+ /* Sn_STATUS */
+ [LAST_TEMP_0] = REG_FIELD(S0_STATUS_OFF, 0, 7),
+ [LAST_TEMP_1] = REG_FIELD(S1_STATUS_OFF, 0, 7),
+ [LAST_TEMP_2] = REG_FIELD(S2_STATUS_OFF, 0, 7),
+ [LAST_TEMP_3] = REG_FIELD(S3_STATUS_OFF, 0, 7),
+ [LAST_TEMP_4] = REG_FIELD(S4_STATUS_OFF, 0, 7),
+ [LAST_TEMP_5] = REG_FIELD(S5_STATUS_OFF, 0, 7),
+ [LAST_TEMP_6] = REG_FIELD(S6_STATUS_OFF, 0, 7),
+ [LAST_TEMP_7] = REG_FIELD(S7_STATUS_OFF, 0, 7),
+ [LAST_TEMP_8] = REG_FIELD(S8_STATUS_OFF, 0, 7),
+ [LAST_TEMP_9] = REG_FIELD(S9_STATUS_OFF, 0, 7),
+ [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0, 7),
+
+ /* No VALID field on 8960 */
+ /* TSENS_INT_STATUS bits: 1 == threshold violated */
+ [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0),
+ [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1),
+ [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2),
+ /* No CRITICAL field on 8960 */
+ [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3),
+
+ /* TRDY: 1=ready, 0=in progress */
+ [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7),
+};
+
static const struct tsens_ops ops_8960 = {
.init = init_8960,
.calibrate = calibrate_8960,
@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 =
struct tsens_plat_data data_8960 = {
.num_sensors = 11,
.ops = &ops_8960,
+ .feat = &tsens_8960_feat,
+ .fields = tsens_8960_regfields,
};

View File

@ -0,0 +1,81 @@
From c04f98a496929f75d75c65115d5717423c3d0634 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Wed, 25 Nov 2020 17:16:36 +0100
Subject: [PATCH 04/10] drivers: thermal: tsens: Use init_common for msm8960
Use init_common and drop custom init for msm8960.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org>
---
drivers/thermal/qcom/tsens-8960.c | 52 +------------------------------
1 file changed, 1 insertion(+), 51 deletions(-)
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_pr
regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
}
-static int init_8960(struct tsens_priv *priv)
-{
- int ret, i;
- u32 reg_cntl;
-
- priv->tm_map = dev_get_regmap(priv->dev, NULL);
- if (!priv->tm_map)
- return -ENODEV;
-
- /*
- * The status registers for each sensor are discontiguous
- * because some SoCs have 5 sensors while others have more
- * but the control registers stay in the same place, i.e
- * directly after the first 5 status registers.
- */
- for (i = 0; i < priv->num_sensors; i++) {
- if (i >= 5)
- priv->sensor[i].status = S0_STATUS_ADDR + 40;
- priv->sensor[i].status += i * 4;
- }
-
- reg_cntl = SW_RST;
- ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
- if (ret)
- return ret;
-
- if (priv->num_sensors > 1) {
- reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
- reg_cntl &= ~SW_RST;
- ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
- CONFIG_MASK, CONFIG);
- } else {
- reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
- reg_cntl &= ~CONFIG_MASK_8660;
- reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
- }
-
- reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
- ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
- if (ret)
- return ret;
-
- reg_cntl |= EN;
- ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
- if (ret)
- return ret;
-
- return 0;
-}
-
static int calibrate_8960(struct tsens_priv *priv)
{
int i;
@@ -346,7 +296,7 @@ static const struct reg_field tsens_8960
};
static const struct tsens_ops ops_8960 = {
- .init = init_8960,
+ .init = init_common,
.calibrate = calibrate_8960,
.get_temp = get_temp_8960,
.enable = enable_8960,

View File

@ -0,0 +1,66 @@
From b3e8bd33b84a6b6c863bd1733bd15b5f1483b8ab Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Wed, 25 Nov 2020 17:06:55 +0100
Subject: [PATCH 05/10] drivers: thermal: tsens: Fix bug in sensor enable for
msm8960
Device based on tsens VER_0 contains a hardware bug that results in some
problem with sensor enablement. Sensor id 6-11 can't be enabled
selectively and all of them must be enabled in one step.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Acked-by: Thara Gopinath <thara.gopinath@linaro.org>
---
drivers/thermal/qcom/tsens-8960.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -27,9 +27,9 @@
#define EN BIT(0)
#define SW_RST BIT(1)
#define SENSOR0_EN BIT(3)
+#define MEASURE_PERIOD BIT(18)
#define SLP_CLK_ENA BIT(26)
#define SLP_CLK_ENA_8660 BIT(24)
-#define MEASURE_PERIOD 1
#define SENSOR0_SHIFT 3
/* INT_STATUS_ADDR bitmasks */
@@ -126,17 +126,34 @@ static int resume_8960(struct tsens_priv
static int enable_8960(struct tsens_priv *priv, int id)
{
int ret;
- u32 reg, mask;
+ u32 reg, mask = BIT(id);
ret = regmap_read(priv->tm_map, CNTL_ADDR, &reg);
if (ret)
return ret;
- mask = BIT(id + SENSOR0_SHIFT);
+ /* HARDWARE BUG:
+ * On platforms with more than 6 sensors, all remaining sensors
+ * must be enabled together, otherwise undefined results are expected.
+ * (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver,
+ * all the sensors are enabled in one step hence this bug is not
+ * triggered.
+ */
+ if (id > 5)
+ mask = GENMASK(10, 6);
+
+ mask <<= SENSOR0_SHIFT;
+
+ /* Sensors already enabled. Skip. */
+ if ((reg & mask) == mask)
+ return 0;
+
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
if (ret)
return ret;
+ reg |= MEASURE_PERIOD;
+
if (priv->num_sensors > 1)
reg |= mask | SLP_CLK_ENA | EN;
else

View File

@ -0,0 +1,109 @@
From 1ff9f982051759e0387e8c7e793b49c48eae291d Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Wed, 25 Nov 2020 17:11:05 +0100
Subject: [PATCH 06/10] drivers: thermal: tsens: Replace custom 8960 apis with
generic apis
Rework calibrate function to use common function. Derive the offset from
a missing hardcoded slope table and the data from the nvmem calib
efuses.
Drop custom get_temp function and use generic api.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Acked-by: Thara Gopinath <thara.gopinath@linaro.org>
---
drivers/thermal/qcom/tsens-8960.c | 56 +++++++++----------------------
1 file changed, 15 insertions(+), 41 deletions(-)
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -67,6 +67,13 @@
#define S9_STATUS_OFF 0x3674
#define S10_STATUS_OFF 0x3678
+/* Original slope - 200 to compensate mC to C inaccuracy */
+static u32 tsens_msm8960_slope[] = {
+ 976, 976, 954, 976,
+ 911, 932, 932, 999,
+ 932, 999, 932
+ };
+
static int suspend_8960(struct tsens_priv *priv)
{
int ret;
@@ -194,9 +201,7 @@ static int calibrate_8960(struct tsens_p
{
int i;
char *data;
-
- ssize_t num_read = priv->num_sensors;
- struct tsens_sensor *s = priv->sensor;
+ u32 p1[11];
data = qfprom_read(priv->dev, "calib");
if (IS_ERR(data))
@@ -204,49 +209,18 @@ static int calibrate_8960(struct tsens_p
if (IS_ERR(data))
return PTR_ERR(data);
- for (i = 0; i < num_read; i++, s++)
- s->offset = data[i];
+ for (i = 0; i < priv->num_sensors; i++) {
+ p1[i] = data[i];
+ priv->sensor[i].slope = tsens_msm8960_slope[i];
+ }
+
+ compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB);
kfree(data);
return 0;
}
-/* Temperature on y axis and ADC-code on x-axis */
-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
-{
- int slope, offset;
-
- slope = thermal_zone_get_slope(s->tzd);
- offset = CAL_MDEGC - slope * s->offset;
-
- return adc_code * slope + offset;
-}
-
-static int get_temp_8960(const struct tsens_sensor *s, int *temp)
-{
- int ret;
- u32 code, trdy;
- struct tsens_priv *priv = s->priv;
- unsigned long timeout;
-
- timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
- do {
- ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy);
- if (ret)
- return ret;
- if (!(trdy & TRDY_MASK))
- continue;
- ret = regmap_read(priv->tm_map, s->status, &code);
- if (ret)
- return ret;
- *temp = code_to_mdegC(code, s);
- return 0;
- } while (time_before(jiffies, timeout));
-
- return -ETIMEDOUT;
-}
-
static struct tsens_features tsens_8960_feat = {
.ver_major = VER_0,
.crit_int = 0,
@@ -315,7 +289,7 @@ static const struct reg_field tsens_8960
static const struct tsens_ops ops_8960 = {
.init = init_common,
.calibrate = calibrate_8960,
- .get_temp = get_temp_8960,
+ .get_temp = get_temp_common,
.enable = enable_8960,
.disable = disable_8960,
.suspend = suspend_8960,

View File

@ -0,0 +1,65 @@
From 5716a61239c6ac9ceb137e825e93c3aea06c4634 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Fri, 19 Mar 2021 00:48:23 +0100
Subject: [PATCH 07/10] drivers: thermal: tsens: Drop unused define for msm8960
Drop unused define for msm8960 replaced by generic api and reg_field.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org>
---
drivers/thermal/qcom/tsens-8960.c | 24 +-----------------------
1 file changed, 1 insertion(+), 23 deletions(-)
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -10,8 +10,6 @@
#include <linux/thermal.h>
#include "tsens.h"
-#define CAL_MDEGC 30000
-
#define CONFIG_ADDR 0x3640
#define CONFIG_ADDR_8660 0x3620
/* CONFIG_ADDR bitmasks */
@@ -21,39 +19,19 @@
#define CONFIG_SHIFT_8660 28
#define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660)
-#define STATUS_CNTL_ADDR_8064 0x3660
#define CNTL_ADDR 0x3620
/* CNTL_ADDR bitmasks */
#define EN BIT(0)
#define SW_RST BIT(1)
-#define SENSOR0_EN BIT(3)
+
#define MEASURE_PERIOD BIT(18)
#define SLP_CLK_ENA BIT(26)
#define SLP_CLK_ENA_8660 BIT(24)
#define SENSOR0_SHIFT 3
-/* INT_STATUS_ADDR bitmasks */
-#define MIN_STATUS_MASK BIT(0)
-#define LOWER_STATUS_CLR BIT(1)
-#define UPPER_STATUS_CLR BIT(2)
-#define MAX_STATUS_MASK BIT(3)
-
#define THRESHOLD_ADDR 0x3624
-/* THRESHOLD_ADDR bitmasks */
-#define THRESHOLD_MAX_LIMIT_SHIFT 24
-#define THRESHOLD_MIN_LIMIT_SHIFT 16
-#define THRESHOLD_UPPER_LIMIT_SHIFT 8
-#define THRESHOLD_LOWER_LIMIT_SHIFT 0
-
-/* Initial temperature threshold values */
-#define LOWER_LIMIT_TH 0x50
-#define UPPER_LIMIT_TH 0xdf
-#define MIN_LIMIT_TH 0x0
-#define MAX_LIMIT_TH 0xff
#define INT_STATUS_ADDR 0x363c
-#define TRDY_MASK BIT(7)
-#define TIMEOUT_US 100
#define S0_STATUS_OFF 0x3628
#define S1_STATUS_OFF 0x362c

View File

@ -0,0 +1,26 @@
From 0d0c22a59bf2672b57e23da9a9ea743e91b71f54 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Sat, 25 Jul 2020 19:55:57 +0200
Subject: [PATCH 08/10] drivers: thermal: tsens: Add support for ipq8064-tsens
Add support for tsens present in ipq806x SoCs based on generic msm8960
tsens driver.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org>
---
drivers/thermal/qcom/tsens.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -968,6 +968,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, t
static const struct of_device_id tsens_table[] = {
{
+ .compatible = "qcom,ipq8064-tsens",
+ .data = &data_8960,
+ }, {
.compatible = "qcom,msm8916-tsens",
.data = &data_8916,
}, {

View File

@ -0,0 +1,112 @@
From ac369071920d427dd484cf74cddba2774bba45f5 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Thu, 9 Jul 2020 22:35:54 +0200
Subject: [PATCH 09/10] dt-bindings: thermal: tsens: Document ipq8064 bindings
Document the use of bindings used for msm8960 tsens based devices.
msm8960 use the same gcc regs and is set as a child of the qcom gcc.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
.../bindings/thermal/qcom-tsens.yaml | 56 ++++++++++++++++---
1 file changed, 48 insertions(+), 8 deletions(-)
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
@@ -19,6 +19,11 @@ description: |
properties:
compatible:
oneOf:
+ - description: msm9860 TSENS based
+ items:
+ - enum:
+ - qcom,ipq8064-tsens
+
- description: v0.1 of TSENS
items:
- enum:
@@ -73,7 +78,9 @@ properties:
maxItems: 2
items:
- const: calib
- - const: calib_sel
+ - enum:
+ - calib_backup
+ - calib_sel
"#qcom,sensors":
description:
@@ -88,12 +95,20 @@ properties:
Number of cells required to uniquely identify the thermal sensors. Since
we have multiple sensors this is set to 1
+required:
+ - compatible
+ - interrupts
+ - interrupt-names
+ - "#thermal-sensor-cells"
+ - "#qcom,sensors"
+
allOf:
- if:
properties:
compatible:
contains:
enum:
+ - qcom,ipq8064-tsens
- qcom,msm8916-tsens
- qcom,msm8974-tsens
- qcom,msm8976-tsens
@@ -114,19 +129,44 @@ allOf:
interrupt-names:
minItems: 2
-required:
- - compatible
- - reg
- - "#qcom,sensors"
- - interrupts
- - interrupt-names
- - "#thermal-sensor-cells"
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,tsens-v0_1
+ - qcom,tsens-v1
+ - qcom,tsens-v2
+
+ then:
+ required:
+ - reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
+ // Example msm9860 based SoC (ipq8064):
+ gcc: clock-controller {
+
+ /* ... */
+
+ tsens: thermal-sensor {
+ compatible = "qcom,ipq8064-tsens";
+
+ nvmem-cells = <&tsens_calib>, <&tsens_calib_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
+ interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "uplow";
+
+ #qcom,sensors = <11>;
+ #thermal-sensor-cells = <1>;
+ };
+ };
+
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
// Example 1 (legacy: for pre v1 IP):
tsens1: thermal-sensor@900000 {
compatible = "qcom,msm8916-tsens", "qcom,tsens-v0_1";

View File

@ -0,0 +1,32 @@
From 68e720ed73c8f038c8c500e4c49c1e65a993a448 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Tue, 6 Apr 2021 04:45:31 +0200
Subject: [PATCH 10/10] drivers: thermal: tsens: Fix wrong slope on msm-8960
Some user using some stats with the old legacy implementation and the
new implementation using the compute_intercept_slope reported an offset
of 3C. Fix the slope table to reflect the original temp.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/thermal/qcom/tsens-8960.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -45,11 +45,11 @@
#define S9_STATUS_OFF 0x3674
#define S10_STATUS_OFF 0x3678
-/* Original slope - 200 to compensate mC to C inaccuracy */
+/* Original slope - 350 to compensate mC to C inaccuracy */
static u32 tsens_msm8960_slope[] = {
- 976, 976, 954, 976,
- 911, 932, 932, 999,
- 932, 999, 932
+ 826, 826, 804, 826,
+ 761, 782, 782, 849,
+ 782, 849, 782
};
static int suspend_8960(struct tsens_priv *priv)

View File

@ -0,0 +1,41 @@
From 8f32d48a309246a80bdca505968085a484d54408 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Mon, 19 Apr 2021 03:01:53 +0200
Subject: [thermal-next PATCH v2 1/2] thermal: qcom: tsens: init debugfs only with
successful probe
calibrate and tsens_register can fail or PROBE_DEFER. This will cause a
double or a wrong init of the debugfs information. Init debugfs only
with successful probe fixing warning about directory already present.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Acked-by: Thara Gopinath <thara.gopinath@linaro.org>
---
drivers/thermal/qcom/tsens.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -918,8 +918,6 @@ int __init init_common(struct tsens_priv
if (tsens_version(priv) >= VER_0_1)
tsens_enable_irq(priv);
- tsens_debug_init(op);
-
err_put_device:
put_device(&op->dev);
return ret;
@@ -1155,7 +1153,12 @@ static int tsens_probe(struct platform_d
}
}
- return tsens_register(priv);
+ ret = tsens_register(priv);
+
+ if (!ret)
+ tsens_debug_init(pdev);
+
+ return ret;
}
static int tsens_remove(struct platform_device *pdev)

View File

@ -0,0 +1,54 @@
From 4204f22060f7a5d42c6ccb4d4c25a6a875571099 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Mon, 19 Apr 2021 03:08:37 +0200
Subject: [thermal-next PATCH v2 2/2] thermal: qcom: tsens: simplify debugfs init
function
Simplify debugfs init function.
- Add check for existing dev directory.
- Fix wrong version in dbg_version_show (with version 0.0.0, 0.1.0 was
incorrectly reported)
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org>
---
drivers/thermal/qcom/tsens.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -692,7 +692,7 @@ static int dbg_version_show(struct seq_f
return ret;
seq_printf(s, "%d.%d.%d\n", maj_ver, min_ver, step_ver);
} else {
- seq_puts(s, "0.1.0\n");
+ seq_printf(s, "0.%d.0\n", priv->feat->ver_major);
}
return 0;
@@ -704,21 +704,17 @@ DEFINE_SHOW_ATTRIBUTE(dbg_sensors);
static void tsens_debug_init(struct platform_device *pdev)
{
struct tsens_priv *priv = platform_get_drvdata(pdev);
- struct dentry *root, *file;
- root = debugfs_lookup("tsens", NULL);
- if (!root)
+ priv->debug_root = debugfs_lookup("tsens", NULL);
+ if (!priv->debug_root)
priv->debug_root = debugfs_create_dir("tsens", NULL);
- else
- priv->debug_root = root;
- file = debugfs_lookup("version", priv->debug_root);
- if (!file)
+ if (!debugfs_lookup("version", priv->debug_root))
debugfs_create_file("version", 0444, priv->debug_root,
pdev, &dbg_version_fops);
/* A directory for each instance of the TSENS IP */
- priv->debug = debugfs_create_dir(dev_name(&pdev->dev), priv->debug_root);
+ priv->debug = debugfs_lookup(dev_name(&pdev->dev), priv->debug_root);
debugfs_create_file("sensors", 0444, priv->debug, pdev, &dbg_sensors_fops);
}
#else

View File

@ -0,0 +1,75 @@
From e67f325e9cd67562b761e884680c0fec03a6f404 Mon Sep 17 00:00:00 2001
From: Matthew Hagan <mnhagan88@gmail.com>
Date: Tue, 8 Jun 2021 19:59:06 +0100
Subject: net: stmmac: explicitly deassert GMAC_AHB_RESET
We are currently assuming that GMAC_AHB_RESET will already be deasserted
by the bootloader. However if this has not been done, probing of the GMAC
will fail. To remedy this we must ensure GMAC_AHB_RESET has been deasserted
prior to probing.
v2 changes:
- remove NULL condition check for stmmac_ahb_rst in stmmac_main.c
- unwrap dev_err() message in stmmac_main.c
- add PTR_ERR() around plat->stmmac_ahb_rst in stmmac_platform.c
v3 changes:
- add error pointer to dev_err() output
- add reset_control_assert(stmmac_ahb_rst) in stmmac_dvr_remove
- revert PTR_ERR() around plat->stmmac_ahb_rst since this is performed
on the returned value of ret by the calling function
Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +++++
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 6 ++++++
include/linux/stmmac.h | 1 +
3 files changed, 12 insertions(+)
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -5021,6 +5021,10 @@ int stmmac_dvr_probe(struct device *devi
reset_control_reset(priv->plat->stmmac_rst);
}
+ ret = reset_control_deassert(priv->plat->stmmac_ahb_rst);
+ if (ret == -ENOTSUPP)
+ dev_err(priv->device, "unable to bring out of ahb reset\n");
+
/* Init MAC and get the capabilities */
ret = stmmac_hw_init(priv);
if (ret)
@@ -5245,6 +5249,7 @@ int stmmac_dvr_remove(struct device *dev
phylink_destroy(priv->phylink);
if (priv->plat->stmmac_rst)
reset_control_assert(priv->plat->stmmac_rst);
+ reset_control_assert(priv->plat->stmmac_ahb_rst);
pm_runtime_put(dev);
pm_runtime_disable(dev);
if (priv->hw->pcs != STMMAC_PCS_TBI &&
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -617,6 +617,12 @@ stmmac_probe_config_dt(struct platform_d
plat->stmmac_rst = NULL;
}
+ plat->stmmac_ahb_rst = devm_reset_control_get_optional_shared(
+ &pdev->dev, "ahb");
+ if (IS_ERR(plat->stmmac_ahb_rst))
+ if (PTR_ERR(plat->stmmac_ahb_rst) == -EPROBE_DEFER)
+ goto error_hw_init;
+
return plat;
error_hw_init:
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -192,6 +192,7 @@ struct plat_stmmacenet_data {
unsigned int clk_ref_rate;
s32 ptp_max_adj;
struct reset_control *stmmac_rst;
+ struct reset_control *stmmac_ahb_rst;
struct stmmac_axi *axi;
int has_gmac4;
bool has_sun8i;

View File

@ -0,0 +1,64 @@
From f95c4c56d65225a537a2d88735fde7ec4d37641d Mon Sep 17 00:00:00 2001
From: Matthew Hagan <mnhagan88@gmail.com>
Date: Sat, 5 Jun 2021 18:35:38 +0100
Subject: ARM: dts: qcom: add ahb reset to ipq806x-gmac
Add GMAC_AHB_RESET to the resets property of each gmac node.
Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
Link: https://lore.kernel.org/r/20210605173546.4102455-2-mnhagan88@gmail.com
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
arch/arm/boot/dts/qcom-ipq8064.dtsi | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -1335,8 +1335,9 @@
clocks = <&gcc GMAC_CORE1_CLK>;
clock-names = "stmmaceth";
- resets = <&gcc GMAC_CORE1_RESET>;
- reset-names = "stmmaceth";
+ resets = <&gcc GMAC_CORE1_RESET>,
+ <&gcc GMAC_AHB_RESET>;
+ reset-names = "stmmaceth", "ahb";
status = "disabled";
};
@@ -1358,8 +1359,9 @@
clocks = <&gcc GMAC_CORE2_CLK>;
clock-names = "stmmaceth";
- resets = <&gcc GMAC_CORE2_RESET>;
- reset-names = "stmmaceth";
+ resets = <&gcc GMAC_CORE2_RESET>,
+ <&gcc GMAC_AHB_RESET>;
+ reset-names = "stmmaceth", "ahb";
status = "disabled";
};
@@ -1381,8 +1383,9 @@
clocks = <&gcc GMAC_CORE3_CLK>;
clock-names = "stmmaceth";
- resets = <&gcc GMAC_CORE3_RESET>;
- reset-names = "stmmaceth";
+ resets = <&gcc GMAC_CORE3_RESET>,
+ <&gcc GMAC_AHB_RESET>;
+ reset-names = "stmmaceth", "ahb";
status = "disabled";
};
@@ -1404,8 +1407,9 @@
clocks = <&gcc GMAC_CORE4_CLK>;
clock-names = "stmmaceth";
- resets = <&gcc GMAC_CORE4_RESET>;
- reset-names = "stmmaceth";
+ resets = <&gcc GMAC_CORE4_RESET>,
+ <&gcc GMAC_AHB_RESET>;
+ reset-names = "stmmaceth", "ahb";
status = "disabled";
};

View File

@ -0,0 +1,121 @@
From: Christian Lamparter <chunkeey@googlemail.com>
Subject: SoC: add qualcomm syscon
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
+obj-$(CONFIG_QCOM_TCSR) += qcom_tcsr.o
obj-$(CONFIG_QCOM_APR) += apr.o
obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -189,6 +189,13 @@ config QCOM_SOCINFO
Say yes here to support the Qualcomm socinfo driver, providing
information about the SoC to user space.
+config QCOM_TCSR
+ tristate "QCOM Top Control and Status Registers"
+ depends on ARCH_QCOM
+ help
+ Say y here to enable TCSR support. The TCSR provides control
+ functions for various peripherals.
+
config QCOM_WCNSS_CTRL
tristate "Qualcomm WCNSS control driver"
depends on ARCH_QCOM || COMPILE_TEST
--- /dev/null
+++ b/drivers/soc/qcom/qcom_tcsr.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, The Linux foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License rev 2 and
+ * only rev 2 as published by the free Software foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or fITNESS fOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#define TCSR_USB_PORT_SEL 0xb0
+
+static int tcsr_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ const struct device_node *node = pdev->dev.of_node;
+ void __iomem *base;
+ u32 val;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ if (!of_property_read_u32(node, "qcom,usb-ctrl-select", &val)) {
+ dev_err(&pdev->dev, "setting usb port select = %d\n", val);
+ writel(val, base + TCSR_USB_PORT_SEL);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id tcsr_dt_match[] = {
+ { .compatible = "qcom,tcsr", },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, tcsr_dt_match);
+
+static struct platform_driver tcsr_driver = {
+ .driver = {
+ .name = "tcsr",
+ .owner = THIS_MODULE,
+ .of_match_table = tcsr_dt_match,
+ },
+ .probe = tcsr_probe,
+};
+
+module_platform_driver(tcsr_driver);
+
+MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
+MODULE_DESCRIPTION("QCOM TCSR driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+++ b/include/dt-bindings/soc/qcom,tcsr.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DT_BINDINGS_QCOM_TCSR_H
+#define __DT_BINDINGS_QCOM_TCSR_H
+
+#define TCSR_USB_SELECT_USB3_P0 0x1
+#define TCSR_USB_SELECT_USB3_P1 0x2
+#define TCSR_USB_SELECT_USB3_DUAL 0x3
+
+/* TCSR A/B REG */
+#define IPQ806X_TCSR_REG_A_ADM_CRCI_MUX_SEL 0
+#define IPQ806X_TCSR_REG_B_ADM_CRCI_MUX_SEL 1
+
+#endif

View File

@ -0,0 +1,37 @@
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1794,6 +1794,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGL
endchoice
+config CMDLINE_OVERRIDE
+ bool "Use alternative cmdline from device tree"
+ help
+ Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can
+ be used, this is not a good option for kernels that are shared across
+ devices. This setting enables using "chosen/cmdline-override" as the
+ cmdline if it exists in the device tree.
+
config CMDLINE
string "Default kernel command string"
default ""
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -1059,6 +1059,17 @@ int __init early_init_dt_scan_chosen(uns
if (p != NULL && l > 0)
strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE));
+ /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different
+ * device tree option of chosen/bootargs-override. This is
+ * helpful on boards where u-boot sets bootargs, and is unable
+ * to be modified.
+ */
+#ifdef CONFIG_CMDLINE_OVERRIDE
+ p = of_get_flat_dt_prop(node, "bootargs-override", &l);
+ if (p != NULL && l > 0)
+ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
+#endif
+
/*
* CONFIG_CMDLINE is meant to be a default in case nothing else
* managed to set the command line, unless CONFIG_CMDLINE_FORCE