diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6fabfff0b..cf505039f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -217,6 +217,8 @@ jobs: _make PLATFORM=qcom-ipq96xx _make PLATFORM=qcom-ipq52xx _make PLATFORM=qcom-nord + _make PLATFORM=qcom-cacao + _make PLATFORM=qcom-shikra - name: arm rockchip make_commands: | _make PLATFORM=rockchip-px30 diff --git a/MAINTAINERS b/MAINTAINERS index 3c01ffde3..b2ddf43a1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -146,6 +146,11 @@ S: Maintained F: core/drivers/qcom/cmd_db/ F: core/include/drivers/qcom/cmd_db/ +Core Drivers QCOM HWKM +R: Amirreza Zarrabi [@qc-azarrabi] +S: Maintained +F: core/drivers/crypto/qcom/ + Core Drivers QCOM QFPROM R: Selvam Sathappan Periakaruppan [@zelvam95] R: Kishore Batta [@kishorebatta-ossqcom] diff --git a/core/arch/arm/plat-qcom/bobcat/ipq52xx/target.mk b/core/arch/arm/plat-qcom/bobcat/ipq52xx/target.mk index 4a226d28b..0ec62ba96 100644 --- a/core/arch/arm/plat-qcom/bobcat/ipq52xx/target.mk +++ b/core/arch/arm/plat-qcom/bobcat/ipq52xx/target.mk @@ -6,3 +6,10 @@ CFG_QCOM_DIAG_LOG ?= $(CFG_TEE_CORE_DEBUG) CFG_TZDRAM_START ?= 0x87D80000 CFG_TZDRAM_SIZE ?= 0x280000 CFG_TEE_RAM_VA_SIZE ?= 0x280000 + +$(call force,CFG_QCOM_CSRNG,y) +$(call force,CFG_WITH_SOFTWARE_PRNG,n) + +CFG_HWRNG_PTA ?= y +CFG_HWRNG_QUALITY ?= 1024 +CFG_HWRNG_RATE ?= 0 diff --git a/core/arch/arm/plat-qcom/bobcat/ipq52xx/target_config.h b/core/arch/arm/plat-qcom/bobcat/ipq52xx/target_config.h index 17008a0a0..7269d7d85 100644 --- a/core/arch/arm/plat-qcom/bobcat/ipq52xx/target_config.h +++ b/core/arch/arm/plat-qcom/bobcat/ipq52xx/target_config.h @@ -20,4 +20,9 @@ #define IMEM_BASE UL(0x8600000) #define IMEM_SIZE UL(0x18000) +#define QCOM_RNG_REG_BASE UL(0x4C5000) + +#define QCOM_WDT_TMR_BASE UL(0x0B117000) +#define QCOM_WDT_BARK_INT_ID UL(0x23) + #endif /* TARGET_CONFIG_H */ diff --git a/core/arch/arm/plat-qcom/bobcat/ipq96xx/target_config.h b/core/arch/arm/plat-qcom/bobcat/ipq96xx/target_config.h index b3eb10732..50697cfd8 100644 --- a/core/arch/arm/plat-qcom/bobcat/ipq96xx/target_config.h +++ b/core/arch/arm/plat-qcom/bobcat/ipq96xx/target_config.h @@ -19,4 +19,7 @@ #define IMEM_BASE UL(0x8600000) #define IMEM_SIZE UL(0x20000) +#define QCOM_WDT_TMR_BASE UL(0x0F411000) +#define QCOM_WDT_BARK_INT_ID UL(0x36) + #endif /* TARGET_CONFIG_H */ diff --git a/core/arch/arm/plat-qcom/bobcat/qcom-arch.mk b/core/arch/arm/plat-qcom/bobcat/qcom-arch.mk new file mode 100644 index 000000000..a0544ac11 --- /dev/null +++ b/core/arch/arm/plat-qcom/bobcat/qcom-arch.mk @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + +CFG_QCOM_SEC_WDOG ?= y + +# XPU protection for TZDRAM and the OP-TEE DIAG log buffer +CFG_QCOM_XPUV4 ?= y diff --git a/core/arch/arm/plat-qcom/bruin/arch_config.h b/core/arch/arm/plat-qcom/bruin/arch_config.h new file mode 100644 index 000000000..79212dcd9 --- /dev/null +++ b/core/arch/arm/plat-qcom/bruin/arch_config.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef ARCH_CONFIG_H +#define ARCH_CONFIG_H + +#define GICD_BASE UL(0x0f200000) +#define GICR_BASE UL(0x0f260000) + +#endif /* ARCH_CONFIG_H */ diff --git a/core/arch/arm/plat-qcom/bruin/qcom-arch.mk b/core/arch/arm/plat-qcom/bruin/qcom-arch.mk new file mode 100644 index 000000000..4625fb293 --- /dev/null +++ b/core/arch/arm/plat-qcom/bruin/qcom-arch.mk @@ -0,0 +1,11 @@ +# BRUIN architecture configuration + +include core/arch/arm/cpu/cortex-armv8-0.mk +$(call force,CFG_TEE_CORE_NB_CORE,4) +$(call force,CFG_ARM_GICV3,y) + +CFG_TZDRAM_START ?= 0xa1400000 +CFG_TEE_RAM_VA_SIZE ?= 0x400000 +CFG_TA_RAM_VA_SIZE ?= 0x2100000 +CFG_TZDRAM_SIZE ?= (CFG_TEE_RAM_VA_SIZE + CFG_TA_RAM_VA_SIZE) +CFG_NUM_THREADS ?= 4 diff --git a/core/arch/arm/plat-qcom/bruin/shikra/target.mk b/core/arch/arm/plat-qcom/bruin/shikra/target.mk new file mode 100644 index 000000000..14ae1120a --- /dev/null +++ b/core/arch/arm/plat-qcom/bruin/shikra/target.mk @@ -0,0 +1 @@ +# Placeholder for target specific configs. diff --git a/core/arch/arm/plat-qcom/bruin/shikra/target_config.h b/core/arch/arm/plat-qcom/bruin/shikra/target_config.h new file mode 100644 index 000000000..e2a4aeb39 --- /dev/null +++ b/core/arch/arm/plat-qcom/bruin/shikra/target_config.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef TARGET_CONFIG_H +#define TARGET_CONFIG_H + +#define DRAM0_BASE UL(0x80000000) +#define DRAM0_SIZE UL(0x80000000) + +#define GENI_UART_REG_BASE UL(0x04a80000) + +#define IMEM_BASE UL(0x0c100000) +#define IMEM_SIZE UL(0x00020000) + +#endif /* TARGET_CONFIG_H */ diff --git a/core/arch/arm/plat-qcom/bruin/sub.mk b/core/arch/arm/plat-qcom/bruin/sub.mk new file mode 100644 index 000000000..a1d7b817d --- /dev/null +++ b/core/arch/arm/plat-qcom/bruin/sub.mk @@ -0,0 +1 @@ +# Placeholder for Qcom architecture specific makefile diff --git a/core/arch/arm/plat-qcom/conf.mk b/core/arch/arm/plat-qcom/conf.mk index 40395ff32..4cff65fbc 100644 --- a/core/arch/arm/plat-qcom/conf.mk +++ b/core/arch/arm/plat-qcom/conf.mk @@ -31,7 +31,8 @@ supported-ta-targets ?= ta_arm64 # Architecture family mapping HOYA_ARCH_CHIPSETS := kodiak lemans BOBCAT_ARCH_CHIPSETS := ipq96xx ipq52xx -WILDCAT_ARCH_CHIPSETS := nord +WILDCAT_ARCH_CHIPSETS := nord cacao +BRUIN_ARCH_CHIPSETS := shikra ifneq (,$(filter $(PLATFORM_FLAVOR),$(HOYA_ARCH_CHIPSETS))) QCOM_ARCH_FAMILY := hoya @@ -39,6 +40,8 @@ else ifneq (,$(filter $(PLATFORM_FLAVOR),$(BOBCAT_ARCH_CHIPSETS))) QCOM_ARCH_FAMILY := bobcat else ifneq (,$(filter $(PLATFORM_FLAVOR),$(WILDCAT_ARCH_CHIPSETS))) QCOM_ARCH_FAMILY := wildcat +else ifneq (,$(filter $(PLATFORM_FLAVOR),$(BRUIN_ARCH_CHIPSETS))) +QCOM_ARCH_FAMILY := bruin else $(error Unsupported PLATFORM_FLAVOR: $(PLATFORM_FLAVOR)) endif diff --git a/core/arch/arm/plat-qcom/hoya/arch_config.h b/core/arch/arm/plat-qcom/hoya/arch_config.h index 8848825cb..11fc5ab44 100644 --- a/core/arch/arm/plat-qcom/hoya/arch_config.h +++ b/core/arch/arm/plat-qcom/hoya/arch_config.h @@ -11,7 +11,7 @@ #define GICR_BASE UL(0x17a60000) #define RAMBLUR_PIMEM_REG_BASE UL(0x610000) -#define SEC_PRNG_REG_BASE UL(0x010D1000) +#define QCOM_RNG_REG_BASE UL(0x010D1000) #define AOP_MSG_RAM_BASE UL(0x0C300000) #define AOP_MSG_RAM_SIZE UL(0x00100000) @@ -25,6 +25,9 @@ #define TCSR_MUTEX_BASE UL(0x01F40000) #define TCSR_MUTEX_SIZE UL(0x40000) +#define HWKM_MASTER_BASE UL(0x010c0000) +#define HWKM_MASTER_SIZE UL(0x00020000) + #define IMEM_DIAG_OFFSET UL(0x720) #define DIAG_SIZE UL(0x3000) #define DIAG_BASE (IMEM_BASE + IMEM_SIZE - DIAG_SIZE) diff --git a/core/arch/arm/plat-qcom/hoya/lemans/target.mk b/core/arch/arm/plat-qcom/hoya/lemans/target.mk index c339ac0e5..d82eecb50 100644 --- a/core/arch/arm/plat-qcom/hoya/lemans/target.mk +++ b/core/arch/arm/plat-qcom/hoya/lemans/target.mk @@ -12,3 +12,14 @@ $(call force,CFG_QCOM_CMD_DB,y) $(call force,CFG_QCOM_RPMH_CLIENT,y) $(call force,CFG_QCOM_QFPROM,y) endif + +CFG_QCOM_PAS_PTA ?= y + +ifeq ($(CFG_QCOM_PAS_PTA),y) +# PAS subsystems map their controller windows at runtime from the reserved VA +# pool (never released). The six DSP windows total ~146.5 MB; the 60 MB default +# fits only one, so reserve 256 MB with headroom. +CFG_RESERVED_VASPACE_SIZE ?= (256 * 1024 * 1024) +CFG_IN_TREE_EARLY_TAS += qcom_pas/cff7d191-7ca0-4784-af13-48223b9a4fbe +endif +CFG_QCOM_HWKM ?= y diff --git a/core/arch/arm/plat-qcom/hoya/lemans/target_config.h b/core/arch/arm/plat-qcom/hoya/lemans/target_config.h index fda237478..757c67c61 100644 --- a/core/arch/arm/plat-qcom/hoya/lemans/target_config.h +++ b/core/arch/arm/plat-qcom/hoya/lemans/target_config.h @@ -30,4 +30,68 @@ #define IMEM_BASE UL(0x14680000) #define IMEM_SIZE UL(0x32000) +#define TURING_0_BASE UL(0x24000000) +#define TURING_0_SIZE UL(0x03000000) + +#define TURING_1_BASE UL(0x28000000) +#define TURING_1_SIZE UL(0x03000000) + +/* + * GP-DSP0 / GP-DSP1 (TURINGGDSP / TURINGGDSP1) subsystems. The window covers + * every GP-DSP sub-block the PTA and clock driver touch (GDSP_CC 0x808000, PUB + * 0xc00000, PLL 0xc40000, CORE_CC 0xc48000). + */ +#define TURING_GDSP_0_BASE UL(0x20000000) +#define TURING_GDSP_0_SIZE UL(0x01000000) + +#define TURING_GDSP_1_BASE UL(0x21000000) +#define TURING_GDSP_1_SIZE UL(0x01000000) + +/* + * LPASS / ADSP (QDSP6 v68/v69) subsystem window, covering every sub-block the + * PTA and clock driver touch (PUB, PLL, CORE_CC, AON_CC, MCC, TOP_CC). + */ +#define LPASS_BASE UL(0x02c00000) +#define LPASS_SIZE ULL(0x01080000) + +/* + * IRIS video-codec subsystem. The window covers the VCODEC_IRIS_WRAPPER_TOP + * (IRIS+0xb0000) and WRAPPER_TZ (IRIS+0xc0000) blocks the bring-up path + * touches. + */ +#define IRIS_BASE UL(0x0aa00000) +#define IRIS_SIZE ULL(0x00200000) + +/* CDSP0 content-protection shared channel (secure DDR); no CDSP1 equivalent. */ +#define CDSP_SECCHANNEL_BASE UL(0xdb1dc000) +#define CDSP_SECCHANNEL_SIZE UL(0x2000) + +/* + * Global register blocks for the Turing/NSP reset sequence, under AOSS_BASE + * (0x0b000000). TCSR_MUTEX_BASE/SIZE is already defined in arch_config.h. + */ +#define AOSS_CC_BASE UL(0x0c2a8000) +#define AOSS_CC_SIZE UL(0x00050000) + +#define RPMH_PDC_GLOBAL_BASE UL(0x0b5e0000) +#define RPMH_PDC_GLOBAL_SIZE UL(0x00002000) + +#define RPMH_PDC_COMPUTE_BASE UL(0x0b2c0000) +#define RPMH_PDC_COMPUTE_SIZE UL(0x00002000) + +#define RPMH_PDC_NSP_BASE UL(0x0b2f0000) +#define RPMH_PDC_NSP_SIZE UL(0x00002000) + +/* + * RPMH PDC blocks for the GP-DSP subsystem reset sequence. These live under + * AOSS_BASE (0x0b000000), at offsets 0x240000 / 0x2d0000. + */ +#define RPMH_PDC_GPDSP0_BASE UL(0x0b240000) +#define RPMH_PDC_GPDSP0_SIZE UL(0x00002000) + +#define RPMH_PDC_GPDSP1_BASE UL(0x0b2d0000) +#define RPMH_PDC_GPDSP1_SIZE UL(0x00002000) + +#define TITAN_SS_BASE UL(0x0ac00000) +#define TITAN_SS_SIZE UL(0x00200000) #endif /* TARGET_CONFIG_H */ diff --git a/core/arch/arm/plat-qcom/hoya/qcom-arch.mk b/core/arch/arm/plat-qcom/hoya/qcom-arch.mk index 59e372983..091471168 100644 --- a/core/arch/arm/plat-qcom/hoya/qcom-arch.mk +++ b/core/arch/arm/plat-qcom/hoya/qcom-arch.mk @@ -6,7 +6,8 @@ $(call force,CFG_TEE_CORE_NB_CORE,8) $(call force,CFG_QCOM_RAMBLUR_PIMEM_V3,y) CFG_QCOM_RAMBLUR_TA_WINDOW_ID ?= 2 -$(call force,CFG_QCOM_PRNG,y) +$(call force,CFG_QCOM_CSRNG,y) +$(call force,CFG_WITH_SOFTWARE_PRNG,n) $(call force,CFG_ARM_GICV3,y) CFG_TZDRAM_START ?= 0x1c300000 diff --git a/core/arch/arm/plat-qcom/wildcat/arch_config.h b/core/arch/arm/plat-qcom/wildcat/arch_config.h index 1ee2c9ae2..490346af0 100644 --- a/core/arch/arm/plat-qcom/wildcat/arch_config.h +++ b/core/arch/arm/plat-qcom/wildcat/arch_config.h @@ -6,7 +6,4 @@ #ifndef ARCH_CONFIG_H #define ARCH_CONFIG_H -#define GICD_BASE UL(0x17000000) -#define GICR_BASE UL(0x17080000) - #endif /* ARCH_CONFIG_H */ diff --git a/core/arch/arm/plat-qcom/wildcat/cacao/target.mk b/core/arch/arm/plat-qcom/wildcat/cacao/target.mk new file mode 100644 index 000000000..510871be3 --- /dev/null +++ b/core/arch/arm/plat-qcom/wildcat/cacao/target.mk @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + +# Qualcomm Cacao platform configuration. + +$(call force,CFG_TEE_CORE_NB_CORE,8) + +# DARE-TZ secure memory regions. DARE is an in-line memory encryption +# IP on Wildcat; it is set up by the TME root-of-trust before OP-TEE +# runs, so no specific OP-TEE driver is needed. +CFG_TZDRAM_START ?= 0x80fcd000 +CFG_TEE_RAM_VA_SIZE ?= 0x147000 +CFG_TA_RAM_VA_SIZE ?= 0x300000 diff --git a/core/arch/arm/plat-qcom/wildcat/cacao/target_config.h b/core/arch/arm/plat-qcom/wildcat/cacao/target_config.h new file mode 100644 index 000000000..612777a48 --- /dev/null +++ b/core/arch/arm/plat-qcom/wildcat/cacao/target_config.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef TARGET_CONFIG_H +#define TARGET_CONFIG_H + +#define TCSR_BOOT_MISC_DETECT UL(0x1FD3000) + +#define IMEM_BASE UL(0x14680000) +#define IMEM_SIZE UL(0x19000) + +#define GICD_BASE UL(0x17200000) +#define GICR_BASE UL(0x17260000) + +#define GCC_BASE UL(0x00100000) +#define GCC_SIZE UL(0x001f0000) + +#define DRAM0_BASE UL(0x80000000) +#define DRAM0_SIZE UL(0x10000000) + +#define GENI_UART_REG_BASE UL(0xa94000) + +#endif /* TARGET_CONFIG_H */ diff --git a/core/arch/arm/plat-qcom/wildcat/nord/target.mk b/core/arch/arm/plat-qcom/wildcat/nord/target.mk index d3a3f2329..c774f510f 100644 --- a/core/arch/arm/plat-qcom/wildcat/nord/target.mk +++ b/core/arch/arm/plat-qcom/wildcat/nord/target.mk @@ -3,3 +3,11 @@ # Threads are expensive in OP-TEE, so they don't have # to be same as number of cores. $(call force,CFG_TEE_CORE_NB_CORE,18) + +# DARE-TZ secure memory regions. DARE is another in-line +# memory encryption IP similar to pIMEM but on wildcat arch +# it is setup by TME root-of-trust, no specific driver needed +# in OP-TEE for that. +CFG_TZDRAM_START ?= 0xBC280000 +CFG_TEE_RAM_VA_SIZE ?= 0x00200000 +CFG_TA_RAM_VA_SIZE ?= 0x07B80000 diff --git a/core/arch/arm/plat-qcom/wildcat/nord/target_config.h b/core/arch/arm/plat-qcom/wildcat/nord/target_config.h index 5e0c0fad2..dca3d4c76 100644 --- a/core/arch/arm/plat-qcom/wildcat/nord/target_config.h +++ b/core/arch/arm/plat-qcom/wildcat/nord/target_config.h @@ -8,6 +8,9 @@ #define GENI_UART_REG_BASE UL(0x884000) +#define GICD_BASE UL(0x17000000) +#define GICR_BASE UL(0x17080000) + #define DRAM0_BASE UL(0x80000000) #define DRAM0_SIZE UL(0x380000000) #define DRAM1_BASE ULL(0x800000000) diff --git a/core/arch/arm/plat-qcom/wildcat/qcom-arch.mk b/core/arch/arm/plat-qcom/wildcat/qcom-arch.mk index 8d2aebe01..b48b4093c 100644 --- a/core/arch/arm/plat-qcom/wildcat/qcom-arch.mk +++ b/core/arch/arm/plat-qcom/wildcat/qcom-arch.mk @@ -1,15 +1,11 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + # Wildcat architecture configuration include core/arch/arm/cpu/cortex-armv8-0.mk $(call force,CFG_ARM_GICV4,y) -# DARE-TZ secure memory regions. DARE is another in-line -# memory encryption IP similar to pIMEM but on wildcat arch -# it is setup by TME root-of-trust, no specific driver needed -# in OP-TEE for that. -CFG_TZDRAM_START ?= 0xBC280000 -CFG_TEE_RAM_VA_SIZE ?= 0x00200000 -CFG_TA_RAM_VA_SIZE ?= 0x07B80000 CFG_TZDRAM_SIZE ?= (CFG_TEE_RAM_VA_SIZE + CFG_TA_RAM_VA_SIZE) CFG_NUM_THREADS ?= 8 diff --git a/core/drivers/clk/qcom/clock-qcom.c b/core/drivers/clk/qcom/clock-qcom.c index b1e9c6fe2..a84964842 100644 --- a/core/drivers/clk/qcom/clock-qcom.c +++ b/core/drivers/clk/qcom/clock-qcom.c @@ -15,6 +15,41 @@ register_phys_mem(MEM_AREA_IO_NSEC, GCC_BASE, GCC_SIZE); #define CBCR_HW_CTL_ENABLE_BIT BIT(1) #define CBCR_BRANCH_OFF_BIT BIT(31) +/* Lucid-EVO PLL register offsets, relative to the PLL register block base. */ +#define PLL_MODE 0x0 +#define PLL_OPMODE 0x4 +#define PLL_L_VAL 0x10 +#define PLL_ALPHA_VAL 0x14 +#define PLL_USER_CTL 0x18 +#define PLL_USER_CTL_U 0x1c +#define PLL_CONFIG_CTL 0x20 +#define PLL_CONFIG_CTL_U 0x24 +#define PLL_CONFIG_CTL_U1 0x28 + +/* PLL_MODE fields */ +#define PLL_MODE_OUTCTRL BIT(0) +#define PLL_MODE_RESET_N BIT(2) +#define PLL_MODE_LOCK_DET BIT(31) + +/* PLL_OPMODE values */ +#define PLL_OPMODE_RUN 0x1 + +/* PLL_L_VAL fields */ +#define PLL_L_VAL_L_MASK 0x0000ffff +#define PLL_L_VAL_CAL_L_SHIFT 16 +#define PLL_L_VAL_CAL_L_MASK 0xffff0000 + +/* PLL_USER_CTL fields */ +#define PLL_USER_CTL_PLLOUT_MAIN_EN BIT(0) +#define PLL_USER_CTL_PRE_DIV_SHIFT 22 +#define PLL_USER_CTL_PRE_DIV_MASK 0x01c00000 +#define PLL_USER_CTL_POST_DIV_ODD_MASK 0x0003c000 +#define PLL_USER_CTL_POST_DIV_EVEN_MASK 0x00003c00 +#define PLL_USER_CTL_FRAC_FORMAT_SEL BIT(28) + +/* PLL_USER_CTL_U fields */ +#define PLL_USER_CTL_U_FINE_LOCK_DET BIT(0) + static inline bool cbcr_branch_on(uint32_t val) { return !(val & CBCR_BRANCH_OFF_BIT); @@ -26,6 +61,14 @@ TEE_Result qcom_clock_enable_cbc(vaddr_t cbcr) io_setbits32(cbcr, CBCR_BRANCH_ENABLE_BIT); + /* + * In hardware clock-control mode (HW_CTL set) CLK_OFF is driven by HW, + * not the software CLK_ENABLE write, so skip the poll to avoid + * spinning. + */ + if (io_read32(cbcr) & CBCR_HW_CTL_ENABLE_BIT) + return TEE_SUCCESS; + REG_POLL_TIMEOUT(cbcr, 10 * 1000, 10, &ret, cbcr_branch_on); if (ret < 0) @@ -34,6 +77,68 @@ TEE_Result qcom_clock_enable_cbc(vaddr_t cbcr) return TEE_SUCCESS; } +static inline bool pll_locked(uint32_t val) +{ + return val & PLL_MODE_LOCK_DET; +} + +TEE_Result qcom_lucidevo_pll_enable(vaddr_t pll_base, + const struct qcom_lucidevo_pll_config *cfg) +{ + uint32_t user_val = 0; + int ret = 0; + + /* Reg settings: program the static PLL trim/config registers. */ + io_write32(pll_base + PLL_CONFIG_CTL, cfg->config_ctl); + io_write32(pll_base + PLL_CONFIG_CTL_U, cfg->config_ctl_u); + io_write32(pll_base + PLL_CONFIG_CTL_U1, cfg->config_ctl_u1); + io_write32(pll_base + PLL_USER_CTL, cfg->user_ctl); + io_write32(pll_base + PLL_USER_CTL_U, cfg->user_ctl_u); + + /* ConfigPLL: program L value and fractional value. */ + io_mask32(pll_base + PLL_L_VAL, cfg->l_val, PLL_L_VAL_L_MASK); + io_write32(pll_base + PLL_ALPHA_VAL, cfg->alpha_val); + + /* Select fractional format and program the pre-/post-div ratios. */ + user_val = io_read32(pll_base + PLL_USER_CTL); + if (cfg->frac_mode_mn) + user_val |= PLL_USER_CTL_FRAC_FORMAT_SEL; + else + user_val &= ~PLL_USER_CTL_FRAC_FORMAT_SEL; + + user_val &= ~(PLL_USER_CTL_PRE_DIV_MASK | + PLL_USER_CTL_POST_DIV_ODD_MASK | + PLL_USER_CTL_POST_DIV_EVEN_MASK); + if (cfg->pre_div >= 1 && cfg->pre_div <= 8) + user_val |= SHIFT_U32(cfg->pre_div - 1, + PLL_USER_CTL_PRE_DIV_SHIFT) & + PLL_USER_CTL_PRE_DIV_MASK; + io_write32(pll_base + PLL_USER_CTL, user_val); + + /* Always use fine-grained lock detection. */ + io_setbits32(pll_base + PLL_USER_CTL_U, PLL_USER_CTL_U_FINE_LOCK_DET); + + /* SetCalConfig: program the calibration L value. */ + io_mask32(pll_base + PLL_L_VAL, + SHIFT_U32(cfg->cal_l_val, PLL_L_VAL_CAL_L_SHIFT), + PLL_L_VAL_CAL_L_MASK); + + /* Enable: select RUN opmode and take the PLL out of reset. */ + io_write32(pll_base + PLL_OPMODE, PLL_OPMODE_RUN); + io_setbits32(pll_base + PLL_MODE, PLL_MODE_RESET_N); + + /* Wait for the PLL to lock. */ + REG_POLL_TIMEOUT(pll_base + PLL_MODE, 10 * 1000, 10, &ret, pll_locked); + if (ret < 0) + return TEE_ERROR_TIMEOUT; + + /* Enable PLL outputs and the main output. */ + io_setbits32(pll_base + PLL_MODE, PLL_MODE_OUTCTRL); + io_setbits32(pll_base + PLL_USER_CTL, PLL_USER_CTL_PLLOUT_MAIN_EN); + + return TEE_SUCCESS; +} + TEE_Result qcom_clock_set_rate(vaddr_t cfg_rcgr, vaddr_t cmd_rcgr, uint32_t cfg_value) { @@ -53,8 +158,11 @@ TEE_Result qcom_clock_enable(enum qcom_clk_group group) { switch (group) { case QCOM_CLKS_TURING: + case QCOM_CLKS_TURING1: case QCOM_CLKS_LPASS: case QCOM_CLKS_WPSS: + case QCOM_CLKS_GPDSP0: + case QCOM_CLKS_GPDSP1: return qcom_clock_enable_pas(group); default: EMSG("Unsupported clock group %d\n", group); diff --git a/core/drivers/clk/qcom/clock-qcom-pas.c b/core/drivers/clk/qcom/platform/kodiak/clock-qcom-pas.c similarity index 92% rename from core/drivers/clk/qcom/clock-qcom-pas.c rename to core/drivers/clk/qcom/platform/kodiak/clock-qcom-pas.c index d664beef3..2aa66ca28 100644 --- a/core/drivers/clk/qcom/clock-qcom-pas.c +++ b/core/drivers/clk/qcom/platform/kodiak/clock-qcom-pas.c @@ -6,8 +6,6 @@ #include #include - -#ifdef CFG_QCOM_PAS_PTA #include #include #include @@ -122,6 +120,18 @@ static int lpass_gdsc_enable(void) return qcom_clock_enable_cbc(gdsc_base + TOP_CC_LPI_Q6_AXIM_HS_CLK); } +TEE_Result qcom_clock_enable_pas_processor(enum qcom_clk_group group __unused) +{ + /* The DSP core is released entirely within the PTA fw_start path. */ + return TEE_SUCCESS; +} + +TEE_Result qcom_clock_pas_reset(enum qcom_clk_group group __unused) +{ + /* The PTA fw_start path brings the DSP up from a known state. */ + return TEE_SUCCESS; +} + TEE_Result qcom_clock_enable_pas(enum qcom_clk_group group) { struct io_pa_va base = { .pa = GCC_BASE }; @@ -167,10 +177,3 @@ TEE_Result qcom_clock_enable_pas(enum qcom_clk_group group) EMSG("Timeout trying to enable clock group %d\n", group); return TEE_ERROR_TIMEOUT; } - -#else -TEE_Result qcom_clock_enable_pas(enum qcom_clk_group group __unused) -{ - return TEE_ERROR_NOT_SUPPORTED; -} -#endif /* ! CFG_QCOM_PAS_PTA */ diff --git a/core/drivers/clk/qcom/platform/lemans/clock-qcom-pas.c b/core/drivers/clk/qcom/platform/lemans/clock-qcom-pas.c new file mode 100644 index 000000000..244750925 --- /dev/null +++ b/core/drivers/clk/qcom/platform/lemans/clock-qcom-pas.c @@ -0,0 +1,605 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clock_group_qcom.h" + +#define CBCR_BRANCH_ENABLE_BIT BIT(0) +#define CBCR_HW_CTL_ENABLE_BIT BIT(1) +#define CBCR_BRANCH_OFF_BIT BIT(31) + +register_phys_mem(MEM_AREA_IO_NSEC, AOSS_CC_BASE, AOSS_CC_SIZE); +register_phys_mem(MEM_AREA_IO_NSEC, RPMH_PDC_GLOBAL_BASE, RPMH_PDC_GLOBAL_SIZE); +register_phys_mem(MEM_AREA_IO_NSEC, RPMH_PDC_COMPUTE_BASE, + RPMH_PDC_COMPUTE_SIZE); +register_phys_mem(MEM_AREA_IO_NSEC, RPMH_PDC_NSP_BASE, RPMH_PDC_NSP_SIZE); +register_phys_mem(MEM_AREA_IO_NSEC, RPMH_PDC_GPDSP0_BASE, RPMH_PDC_GPDSP0_SIZE); +register_phys_mem(MEM_AREA_IO_NSEC, RPMH_PDC_GPDSP1_BASE, RPMH_PDC_GPDSP1_SIZE); +register_phys_mem(MEM_AREA_IO_NSEC, TCSR_MUTEX_BASE, TCSR_MUTEX_SIZE); + +static TEE_Result cdsp_enable(paddr_t turing_base) +{ + struct io_pa_va turing_cc_io = { + .pa = turing_base + TURINGNSP_CC_OFFSET + }; + vaddr_t cc_base = io_pa_or_va(&turing_cc_io, 0x50000); + uint64_t timeout = timeout_init_us(10000); + TEE_Result res = TEE_SUCCESS; + + res = qcom_clock_enable_cbc(cc_base + TURINGNSP_Q6SS_AHBS_AON); + if (res != TEE_SUCCESS) + return res; + + res = qcom_clock_enable_cbc(cc_base + TURINGNSP_Q6SS_ALT_RESET_AON); + if (res != TEE_SUCCESS) + return res; + + io_clrbits32(cc_base + TURINGNSP_Q6SS_ALT_RESET_CTL, + CBCR_BRANCH_ENABLE_BIT); + io_clrbits32(cc_base + TURINGNSP_Q6SS_ALT_RESET_AON, + CBCR_BRANCH_ENABLE_BIT); + + io_setbits32(cc_base + TURINGNSP_NSPNOC, + CBCR_BRANCH_ENABLE_BIT); + + /* Retention flop */ + io_clrbits32(cc_base + TURINGNSP_VAPSS_GDSCR, 0x1); + while (!timeout_elapsed(timeout)) { + if (io_read32(cc_base + TURINGNSP_VAPSS_GDSCR) & 0x80000000) + goto out; + + udelay(10); + } + + return TEE_ERROR_TIMEOUT; +out: + io_setbits32(cc_base + TURINGNSP_VAPSS_GDSCR, 0x801); + + return TEE_SUCCESS; +} + +static const struct qcom_lucidevo_pll_config q6_pll_cfg = { + .l_val = TURINGNSP_Q6_PLL_L_VAL, + .cal_l_val = TURINGNSP_Q6_PLL_CAL_L_VAL, + .pre_div = 1, + .config_ctl = TURINGNSP_Q6_PLL_CONFIG_CTL, + .config_ctl_u = TURINGNSP_Q6_PLL_CONFIG_CTL_U, + .config_ctl_u1 = TURINGNSP_Q6_PLL_CONFIG_CTL_U1, + .user_ctl = TURINGNSP_Q6_PLL_USER_CTL, + .user_ctl_u = TURINGNSP_Q6_PLL_USER_CTL_U, + /* alpha (default) fractional mode */ +}; + +/* + * Bring the QDSP6 out of reset after the boot FSM completes: lock the Q6 PLL, + * switch the core RCG onto it, then release the core. Runs after fw_start() + * since the Q6 PLL registers must not be touched until the FSM is done. + */ +static TEE_Result cdsp_enable_processor(paddr_t turing_base) +{ + struct io_pa_va proc_io = { + .pa = turing_base + TURINGNSP_BOOT_OFFSET + }; + vaddr_t boot_base = io_pa_or_va(&proc_io, TURINGNSP_PROC_WINDOW_SIZE); + vaddr_t pll_base = boot_base - TURINGNSP_BOOT_OFFSET + + TURINGNSP_Q6_PLL_OFFSET; + vaddr_t core_cc = boot_base - TURINGNSP_BOOT_OFFSET + + TURINGNSP_CORE_CC_OFFSET; + TEE_Result res = TEE_SUCCESS; + + res = qcom_lucidevo_pll_enable(pll_base, &q6_pll_cfg); + if (res != TEE_SUCCESS) + return res; + + res = qcom_clock_set_rate(core_cc + QDSP6SS_CORE_CFG_RCGR, + core_cc + QDSP6SS_CORE_CMD_RCGR, + Q6RCG_CFG_VALUE); + if (res != TEE_SUCCESS) + return res; + + /* Release the core only after the PLL has been initialised. */ + io_setbits32(boot_base + QDSP6SS_BOOT_CORE_START, BIT(0)); + + return TEE_SUCCESS; +} + +static const struct qcom_lucidevo_pll_config lpass_q6_pll_cfg = { + .l_val = LPASS_Q6_PLL_L_VAL, + .cal_l_val = LPASS_Q6_PLL_CAL_L_VAL, + .pre_div = 1, + .config_ctl = LPASS_Q6_PLL_CONFIG_CTL, + .config_ctl_u = LPASS_Q6_PLL_CONFIG_CTL_U, + .config_ctl_u1 = LPASS_Q6_PLL_CONFIG_CTL_U1, + .user_ctl = LPASS_Q6_PLL_USER_CTL, + .user_ctl_u = LPASS_Q6_PLL_USER_CTL_U, + /* alpha (default) fractional mode */ +}; + +/* + * Set up clocks for the LPASS / ADSP QDSP6. Unlike the Turing NSP, the Q6 PLL + * and core RCG are configured here, before the boot FSM in lpass_fw_start. + */ +static TEE_Result lpass_setup(void) +{ + struct io_pa_va gcc_io = { .pa = GCC_BASE }; + vaddr_t gcc_base = io_pa_or_va(&gcc_io, GCC_SIZE); + struct io_pa_va lpass_io = { .pa = LPASS_BASE }; + vaddr_t lpass_base = io_pa_or_va(&lpass_io, LPASS_SIZE); + vaddr_t aon_cc = lpass_base + LPASS_AON_CC_OFFSET; + vaddr_t top_cc = lpass_base + LPASS_TOP_CC_OFFSET; + vaddr_t core_cc = lpass_base + LPASS_CORE_CC_OFFSET; + vaddr_t pll_base = lpass_base + LPASS_PLL_OFFSET; + TEE_Result res = TEE_SUCCESS; + + if (!gcc_base || !lpass_base) + return TEE_ERROR_GENERIC; + + /* 4. Enable LPASS access from the config NoC. */ + res = qcom_clock_enable_cbc(gcc_base + GCC_CFG_NOC_LPASS_CBCR); + if (res != TEE_SUCCESS) + return res; + + /* AHB master/slave clocks, required to reach the QDSP6SS registers. */ + res = qcom_clock_enable_cbc(aon_cc + LPASS_AON_CC_Q6_AHBM_CBCR); + if (res != TEE_SUCCESS) + return res; + + res = qcom_clock_enable_cbc(aon_cc + LPASS_AON_CC_Q6_AHBS_CBCR); + if (res != TEE_SUCCESS) + return res; + + /* LPASS interface clock. */ + res = qcom_clock_enable_cbc(top_cc + LPASS_TOP_CC_LPI_Q6_AXIM_HS_CBCR); + if (res != TEE_SUCCESS) + return res; + + /* Enable the QDSP6 core clock branch. */ + res = qcom_clock_enable_cbc(core_cc + LPASS_QDSP6SS_CORE_CBCR); + if (res != TEE_SUCCESS) + return res; + + /* Configure and lock the Q6 PLL, then switch the core RCG onto it. */ + res = qcom_lucidevo_pll_enable(pll_base, &lpass_q6_pll_cfg); + if (res != TEE_SUCCESS) + return res; + + return qcom_clock_set_rate(core_cc + LPASS_QDSP6SS_CORE_CFG_RCGR, + core_cc + LPASS_QDSP6SS_CORE_CMD_RCGR, + Q6RCG_CFG_VALUE); +} + +static const struct qcom_lucidevo_pll_config gpdsp_q6_pll_cfg = { + .l_val = GPDSP_Q6_PLL_L_VAL, + .cal_l_val = GPDSP_Q6_PLL_CAL_L_VAL, + .pre_div = 1, + .config_ctl = GPDSP_Q6_PLL_CONFIG_CTL, + .config_ctl_u = GPDSP_Q6_PLL_CONFIG_CTL_U, + .config_ctl_u1 = GPDSP_Q6_PLL_CONFIG_CTL_U1, + .user_ctl = GPDSP_Q6_PLL_USER_CTL, + .user_ctl_u = GPDSP_Q6_PLL_USER_CTL_U, + /* alpha (default) fractional mode */ +}; + +/* + * Set up clocks for a GP-DSP (TURINGGDSP) QDSP6. Like LPASS, the Q6 PLL and + * core RCG are configured here, before the boot FSM in gpdspN_fw_start. + */ +static TEE_Result gpdsp_setup(paddr_t gdsp_base, uint32_t gcc_cfg_ahb_cbcr, + uint32_t gcc_aggre_axi_cbcr) +{ + struct io_pa_va gcc_io = { .pa = GCC_BASE }; + vaddr_t gcc_base = io_pa_or_va(&gcc_io, GCC_SIZE); + struct io_pa_va gdsp_io = { .pa = gdsp_base }; + vaddr_t base = io_pa_or_va(&gdsp_io, TURING_GDSP_0_SIZE); + vaddr_t gdsp_cc = base + TURINGGDSP_GDSP_CC_OFFSET; + vaddr_t core_cc = base + TURINGGDSP_CORE_CC_OFFSET; + vaddr_t pll_base = base + TURINGGDSP_PLL_OFFSET; + vaddr_t pub = base + TURINGGDSP_PUB_OFFSET; + TEE_Result res = TEE_SUCCESS; + + if (!gcc_base || !base) + return TEE_ERROR_GENERIC; + + /* Turing slave-way bus clock branch, also on NIU socket. */ + res = qcom_clock_enable_cbc(gcc_base + gcc_cfg_ahb_cbcr); + if (res != TEE_SUCCESS) + return res; + + res = qcom_clock_enable_cbc(gcc_base + gcc_aggre_axi_cbcr); + if (res != TEE_SUCCESS) + return res; + + /* Q6SS slave clock, required to reach the QDSP6SS registers. */ + res = qcom_clock_enable_cbc(gdsp_cc + TURINGGDSP_Q6SS_AHBS_AON_CBCR); + if (res != TEE_SUCCESS) + return res; + + /* Program the debug config register, then enable core clock. */ + io_write32(pub + TURINGGDSP_QDSP6SS_DBG_CFG, 0); + io_setbits32(core_cc + TURINGGDSP_QDSP6SS_CORE_CBCR, + CBCR_BRANCH_ENABLE_BIT); + + /* Configure and lock the Q6 PLL, then switch the core RCG onto it. */ + res = qcom_lucidevo_pll_enable(pll_base, &gpdsp_q6_pll_cfg); + if (res != TEE_SUCCESS) + return res; + + return qcom_clock_set_rate(core_cc + TURINGGDSP_QDSP6SS_CORE_CFG_RCGR, + core_cc + TURINGGDSP_QDSP6SS_CORE_CMD_RCGR, + Q6RCG_CFG_VALUE); +} + +TEE_Result qcom_clock_enable_pas_processor(enum qcom_clk_group group) +{ + switch (group) { + case QCOM_CLKS_TURING: + return cdsp_enable_processor(TURING_0_BASE); + case QCOM_CLKS_TURING1: + return cdsp_enable_processor(TURING_1_BASE); + case QCOM_CLKS_LPASS: + /* + * LPASS configures its Q6 PLL and core RCG in lpass_setup + * (before the boot FSM) and releases the core in + * lpass_fw_start, so there is no post-boot step here. + */ + return TEE_SUCCESS; + case QCOM_CLKS_GPDSP0: + case QCOM_CLKS_GPDSP1: + /* + * Like LPASS, the GP-DSP Q6 PLL and core RCG are configured in + * gpdsp_setup and the core released in gpdspN_fw_start, so + * there is no post-boot step here. + */ + return TEE_SUCCESS; + default: + return TEE_ERROR_NOT_SUPPORTED; + } +} + +/* + * Per-instance register selection for the Turing/NSP reset sequence: CDSP0 and + * CDSP1 share the Turing-CC offsets but differ in the GCC/TCSR/PDC/AOSS fields. + */ +struct cdsp_reset_regs { + paddr_t turing_base; + uint32_t gcc_cfg_ahb_cbcr; /* offset within GCC window */ + uint32_t tcsr_haltreq; /* offsets within TCSR mutex window */ + uint32_t tcsr_haltack; + uint32_t tcsr_master_idle; + uint32_t tcsr_pwr_on; + paddr_t pdc_status_base; /* RPMH PDC block for the busy check */ + uint32_t pdc_status_size; + uint32_t pdc_sync_reset_bit; /* field within RPMH_PDC_SYNC_RESET */ + uint32_t computess_restart_bit; /* bit in AOSS_CC_COMPUTESS_RESTART */ + uint32_t ret_cfg_settle_us; /* settle us after RET_CFG, CDSP0 */ +}; + +static const struct cdsp_reset_regs cdsp0_reset_regs = { + .turing_base = TURING_0_BASE, + .gcc_cfg_ahb_cbcr = GCC_TURING_0_CFG_AHB_CBCR, + .tcsr_haltreq = TCSR_TURING_HALTREQ, + .tcsr_haltack = TCSR_TURING_HALTACK, + .tcsr_master_idle = TCSR_TURING_MASTER_IDLE, + .tcsr_pwr_on = TCSR_TURING_PWR_ON, + .pdc_status_base = RPMH_PDC_COMPUTE_BASE, + .pdc_status_size = RPMH_PDC_COMPUTE_SIZE, + .pdc_sync_reset_bit = PDC_SYNC_RESET_COMPUTE_BIT, + .computess_restart_bit = COMPUTESS_RESTART_SS_0_BIT, + .ret_cfg_settle_us = 2000, +}; + +static const struct cdsp_reset_regs cdsp1_reset_regs = { + .turing_base = TURING_1_BASE, + .gcc_cfg_ahb_cbcr = GCC_TURING_1_CFG_AHB_CBCR, + .tcsr_haltreq = TCSR_TURING1_HALT_REQ, + .tcsr_haltack = TCSR_TURING1_HALT_ACK, + .tcsr_master_idle = TCSR_TURING1_MASTER_IDLE, + .tcsr_pwr_on = TCSR_TURING1_PWR_ON, + .pdc_status_base = RPMH_PDC_NSP_BASE, + .pdc_status_size = RPMH_PDC_NSP_SIZE, + .pdc_sync_reset_bit = PDC_SYNC_RESET_NSP_BIT, + .computess_restart_bit = COMPUTESS_RESTART_SS_1_BIT, + .ret_cfg_settle_us = 0, +}; + +/* HALT_ACK polls for up to 1s (200000 * 5us), matching the reference. */ +#define CDSP_HALT_ACK_TIMEOUT_US (200000 * 5) + +/* + * Put the QDSP6/NSP through a full subsystem reset (AOSS_CC_COMPUTESS_RESTART + * and PDC sync reset) before bring-up, so the Q6 does not come out of reset + * from a stale state left by an earlier boot stage. + */ +static TEE_Result cdsp_reset_processor(const struct cdsp_reset_regs *r) +{ + struct io_pa_va turing_cc_io = { .pa = r->turing_base + + TURINGNSP_CC_OFFSET }; + vaddr_t cc_base = io_pa_or_va(&turing_cc_io, + TURINGNSP_PROC_WINDOW_SIZE); + struct io_pa_va pub_io = { .pa = r->turing_base + + TURINGNSP_BOOT_OFFSET }; + vaddr_t pub_base = io_pa_or_va(&pub_io, TURINGNSP_PROC_WINDOW_SIZE); + struct io_pa_va gcc_io = { .pa = GCC_BASE }; + vaddr_t gcc_base = io_pa_or_va(&gcc_io, GCC_SIZE); + struct io_pa_va aoss_io = { .pa = AOSS_CC_BASE }; + vaddr_t aoss_cc = io_pa_or_va(&aoss_io, AOSS_CC_SIZE); + struct io_pa_va pdc_g_io = { .pa = RPMH_PDC_GLOBAL_BASE }; + vaddr_t pdc_global = io_pa_or_va(&pdc_g_io, RPMH_PDC_GLOBAL_SIZE); + struct io_pa_va pdc_s_io = { .pa = r->pdc_status_base }; + vaddr_t pdc_status = io_pa_or_va(&pdc_s_io, r->pdc_status_size); + struct io_pa_va tcsr_io = { .pa = TCSR_MUTEX_BASE }; + vaddr_t tcsr = io_pa_or_va(&tcsr_io, TCSR_MUTEX_SIZE); + uint64_t timeout = 0; + TEE_Result res = TEE_SUCCESS; + + /* Bail if the PDC sequencer is mid-transition. */ + if (io_read32(pdc_status + RPMH_PDC_MODE_STATUS_DRV0) & + PDC_MODE_STATUS_SEQ_BUSY_BIT) + return TEE_ERROR_BUSY; + + /* Activate a full QDSP6 reset before the SSR. */ + res = qcom_clock_enable_cbc(cc_base + TURINGNSP_Q6SS_ALT_RESET_AON); + if (res != TEE_SUCCESS) + return res; + io_setbits32(cc_base + TURINGNSP_Q6SS_ALT_RESET_CTL, + Q6SS_ALT_RESET_CTL_ALT_ARES_BYPASS_BIT); + + /* + * Reset the retention logic; CDSP0 waits for the write to settle + * (CDSP1 omits this), captured by ret_cfg_settle_us. + */ + io_setbits32(pub_base + TURINGNSP_QDSP6SS_RET_CFG, + QDSP6SS_RET_CFG_RET_ARES_ENA_BIT); + if (r->ret_cfg_settle_us) { + dsb(); + udelay(r->ret_cfg_settle_us); + } + + /* Retain the NSP_AUX registers across the reset. */ + io_setbits32(cc_base + TURINGNSP_NSPAUX_XO_CBCR, CBCR_CLK_ENABLE_BIT); + io_setbits32(cc_base + TURINGNSP_NSPAUX_GDSCR, + NSPAUX_GDSCR_RETAIN_FF_ENABLE_BIT); + + /* Disconnect the SWAY NIU socket to halt config-NoC traffic. */ + io_clrbits32(gcc_base + r->gcc_cfg_ahb_cbcr, CBCR_CLK_ENABLE_BIT); + + /* If powered on and the master port is busy, halt mem-NoC traffic. */ + if ((io_read32(tcsr + r->tcsr_pwr_on) & TCSR_TURING_BIT) && + !(io_read32(tcsr + r->tcsr_master_idle) & TCSR_TURING_BIT)) { + io_setbits32(tcsr + r->tcsr_haltreq, TCSR_TURING_BIT); + + timeout = timeout_init_us(CDSP_HALT_ACK_TIMEOUT_US); + while (!(io_read32(tcsr + r->tcsr_haltack) & + TCSR_TURING_BIT)) { + if (timeout_elapsed(timeout)) + break; + udelay(5); + } + } + + /* Assert the PDC reset, then pulse the subsystem restart. */ + io_setbits32(pdc_global + RPMH_PDC_SYNC_RESET, r->pdc_sync_reset_bit); + + io_setbits32(aoss_cc + AOSS_CC_COMPUTESS_RESTART, + r->computess_restart_bit); + udelay(200); + io_clrbits32(aoss_cc + AOSS_CC_COMPUTESS_RESTART, + r->computess_restart_bit); + dsb(); + udelay(200); + + /* De-assert the PDC reset and clear the halt request. */ + io_clrbits32(pdc_global + RPMH_PDC_SYNC_RESET, r->pdc_sync_reset_bit); + io_clrbits32(tcsr + r->tcsr_haltreq, TCSR_TURING_BIT); + udelay(100); + + return TEE_SUCCESS; +} + +/* + * Per-instance register selection for the GP-DSP reset sequence: GDSP0 and + * GDSP1 share the QDSP6 PUB offsets but differ in the GCC/TCSR/PDC/AOSS fields. + */ +struct gpdsp_reset_regs { + paddr_t gdsp_base; + uint32_t gcc_cfg_ahb_cbcr; /* offset within GCC window */ + uint32_t tcsr_haltreq; /* offsets within TCSR mutex window */ + uint32_t tcsr_haltack; + uint32_t tcsr_il0_master_idle; + uint32_t tcsr_il1_master_idle; + uint32_t tcsr_pwr_on; + paddr_t pdc_status_base; /* RPMH PDC block for the busy check */ + uint32_t pdc_status_size; + uint32_t pdc_sync_reset_bit; /* field within RPMH_PDC_SYNC_RESET */ + uint32_t gpdsp_restart_bit; /* field within AOSS_CC_GPDSP_RESTART */ +}; + +static const struct gpdsp_reset_regs gpdsp0_reset_regs = { + .gdsp_base = TURING_GDSP_0_BASE, + .gcc_cfg_ahb_cbcr = GCC_GPDSP_0_CFG_AHB_CBCR, + .tcsr_haltreq = TCSR_GPDSP0_HALT_REQ, + .tcsr_haltack = TCSR_GPDSP0_HALT_ACK, + .tcsr_il0_master_idle = TCSR_GPDSP0_IL0_MASTER_IDLE, + .tcsr_il1_master_idle = TCSR_GPDSP0_IL1_MASTER_IDLE, + .tcsr_pwr_on = TCSR_GPDSP0_PWR_ON, + .pdc_status_base = RPMH_PDC_GPDSP0_BASE, + .pdc_status_size = RPMH_PDC_GPDSP0_SIZE, + .pdc_sync_reset_bit = PDC_SYNC_RESET_GPDSP0_BIT, + .gpdsp_restart_bit = GPDSP_RESTART_SS_0_BIT, +}; + +static const struct gpdsp_reset_regs gpdsp1_reset_regs = { + .gdsp_base = TURING_GDSP_1_BASE, + .gcc_cfg_ahb_cbcr = GCC_GPDSP_1_CFG_AHB_CBCR, + .tcsr_haltreq = TCSR_GPDSP1_HALT_REQ, + .tcsr_haltack = TCSR_GPDSP1_HALT_ACK, + .tcsr_il0_master_idle = TCSR_GPDSP1_IL0_MASTER_IDLE, + .tcsr_il1_master_idle = TCSR_GPDSP1_IL1_MASTER_IDLE, + .tcsr_pwr_on = TCSR_GPDSP1_PWR_ON, + .pdc_status_base = RPMH_PDC_GPDSP1_BASE, + .pdc_status_size = RPMH_PDC_GPDSP1_SIZE, + .pdc_sync_reset_bit = PDC_SYNC_RESET_GPDSP1_BIT, + .gpdsp_restart_bit = GPDSP_RESTART_SS_1_BIT, +}; + +/* HALT_ACK polls for up to 1s (200000 * 5us), matching the reference. */ +#define GPDSP_HALT_ACK_TIMEOUT_US (200000 * 5) + +/* + * Put a GP-DSP QDSP6 through a full subsystem reset (AOSS_CC_GPDSP_RESTART and + * PDC sync reset) before bring-up. Unlike the Turing NSP there is no + * NSPAUX/ALT_RESET retention handling and the idle check covers two ports. + */ +static TEE_Result gpdsp_reset_processor(const struct gpdsp_reset_regs *r) +{ + struct io_pa_va gdsp_io = { .pa = r->gdsp_base }; + vaddr_t base = io_pa_or_va(&gdsp_io, TURING_GDSP_0_SIZE); + vaddr_t pub = base + TURINGGDSP_PUB_OFFSET; + struct io_pa_va gcc_io = { .pa = GCC_BASE }; + vaddr_t gcc_base = io_pa_or_va(&gcc_io, GCC_SIZE); + struct io_pa_va aoss_io = { .pa = AOSS_CC_BASE }; + vaddr_t aoss_cc = io_pa_or_va(&aoss_io, AOSS_CC_SIZE); + struct io_pa_va pdc_g_io = { .pa = RPMH_PDC_GLOBAL_BASE }; + vaddr_t pdc_global = io_pa_or_va(&pdc_g_io, RPMH_PDC_GLOBAL_SIZE); + struct io_pa_va pdc_s_io = { .pa = r->pdc_status_base }; + vaddr_t pdc_status = io_pa_or_va(&pdc_s_io, r->pdc_status_size); + struct io_pa_va tcsr_io = { .pa = TCSR_MUTEX_BASE }; + vaddr_t tcsr = io_pa_or_va(&tcsr_io, TCSR_MUTEX_SIZE); + uint64_t timeout = 0; + + if (!base || !gcc_base || !aoss_cc || !pdc_global || !pdc_status || + !tcsr) + return TEE_ERROR_GENERIC; + + /* Bail if the PDC sequencer is mid-transition. */ + if (io_read32(pdc_status + RPMH_PDC_MODE_STATUS_DRV0) & + PDC_MODE_STATUS_SEQ_BUSY_BIT) + return TEE_ERROR_BUSY; + + /* Reset the retention logic and let the write settle. */ + io_setbits32(pub + TURINGGDSP_QDSP6SS_RET_CFG, + QDSP6SS_RET_CFG_RET_ARES_ENA_BIT); + dsb(); + udelay(2000); + + /* Disconnect the SWAY NIU socket to halt config-NoC traffic. */ + io_clrbits32(gcc_base + r->gcc_cfg_ahb_cbcr, CBCR_CLK_ENABLE_BIT); + + /* + * If powered on and either master port (IL0 or IL1) is busy, halt + * mem-NoC traffic and wait for the acknowledge. + */ + if (io_read32(tcsr + r->tcsr_pwr_on) & TCSR_TURING_BIT) { + if (!(io_read32(tcsr + r->tcsr_il0_master_idle) & + TCSR_TURING_BIT) || + !(io_read32(tcsr + r->tcsr_il1_master_idle) & + TCSR_TURING_BIT)) { + io_setbits32(tcsr + r->tcsr_haltreq, TCSR_TURING_BIT); + + timeout = timeout_init_us(GPDSP_HALT_ACK_TIMEOUT_US); + while (!(io_read32(tcsr + r->tcsr_haltack) & + TCSR_TURING_BIT)) { + if (timeout_elapsed(timeout)) + break; + udelay(5); + } + } + } + + /* Assert the PDC reset, then pulse the subsystem restart. */ + io_setbits32(pdc_global + RPMH_PDC_SYNC_RESET, r->pdc_sync_reset_bit); + + io_setbits32(aoss_cc + AOSS_CC_GPDSP_RESTART, r->gpdsp_restart_bit); + udelay(200); + io_clrbits32(aoss_cc + AOSS_CC_GPDSP_RESTART, r->gpdsp_restart_bit); + dsb(); + udelay(200); + + /* De-assert the PDC reset and clear the halt request. */ + io_clrbits32(pdc_global + RPMH_PDC_SYNC_RESET, r->pdc_sync_reset_bit); + io_clrbits32(tcsr + r->tcsr_haltreq, TCSR_TURING_BIT); + udelay(100); + + return TEE_SUCCESS; +} + +TEE_Result qcom_clock_pas_reset(enum qcom_clk_group group) +{ + switch (group) { + case QCOM_CLKS_TURING: + return cdsp_reset_processor(&cdsp0_reset_regs); + case QCOM_CLKS_TURING1: + return cdsp_reset_processor(&cdsp1_reset_regs); + case QCOM_CLKS_GPDSP0: + return gpdsp_reset_processor(&gpdsp0_reset_regs); + case QCOM_CLKS_GPDSP1: + return gpdsp_reset_processor(&gpdsp1_reset_regs); + case QCOM_CLKS_LPASS: + /* + * The LPASS subsystem reset is the SSR / tear-down path; + * cold bring-up starts from a known state with the LPASS + * core domain already powered. + */ + return TEE_SUCCESS; + default: + return TEE_ERROR_NOT_SUPPORTED; + } +} + +TEE_Result qcom_clock_enable_pas(enum qcom_clk_group group) +{ + struct io_pa_va base = { .pa = GCC_BASE }; + vaddr_t gcc_base = io_pa_or_va(&base, GCC_SIZE); + TEE_Result res = 0; + + switch (group) { + case QCOM_CLKS_TURING: + /* Turing bus clock branch connected to the NIU socket */ + res = qcom_clock_enable_cbc(gcc_base + + GCC_TURING_0_CFG_AHB_CLK); + if (res) + goto timeout; + + res = cdsp_enable(TURING_0_BASE); + if (res != TEE_SUCCESS) + goto timeout; + break; + case QCOM_CLKS_TURING1: + /* Turing bus clock branch connected to the NIU socket */ + res = qcom_clock_enable_cbc(gcc_base + + GCC_TURING_1_CFG_AHB_CLK); + if (res) + goto timeout; + + res = cdsp_enable(TURING_1_BASE); + if (res != TEE_SUCCESS) + goto timeout; + break; + case QCOM_CLKS_LPASS: + return lpass_setup(); + case QCOM_CLKS_GPDSP0: + return gpdsp_setup(TURING_GDSP_0_BASE, GCC_GPDSP_0_CFG_AHB_CBCR, + GCC_AGGRE_NOC_GPDSP_0_AXI_CBCR); + case QCOM_CLKS_GPDSP1: + return gpdsp_setup(TURING_GDSP_1_BASE, GCC_GPDSP_1_CFG_AHB_CBCR, + GCC_AGGRE_NOC_GPDSP_1_AXI_CBCR); + default: + return TEE_ERROR_NOT_SUPPORTED; + } + + return TEE_SUCCESS; +timeout: + EMSG("Timeout trying to enable clock group %d\n", group); + return TEE_ERROR_TIMEOUT; +} diff --git a/core/drivers/clk/qcom/platform/lemans/clock_group_qcom.h b/core/drivers/clk/qcom/platform/lemans/clock_group_qcom.h index b29f8aa72..8dd0bcd14 100644 --- a/core/drivers/clk/qcom/platform/lemans/clock_group_qcom.h +++ b/core/drivers/clk/qcom/platform/lemans/clock_group_qcom.h @@ -9,4 +9,219 @@ #define GCC_SEC_CTRL_CMD_RCGR 0x39034 #define QFPROM_CLOCK_DIVIDE 0x7 +#define GCC_TURING_0_CFG_AHB_CLK 0x41028 +#define GCC_TURING_1_CFG_AHB_CLK 0x12028 + +/* + * Turing/NSP clock-controller register offsets, identical for both NSP + * instances; only the subsystem base differs (TURING_0_BASE / TURING_1_BASE). + */ +#define TURINGNSP_CC_OFFSET 0x02008000 +#define TURINGNSP_Q6SS_ALT_RESET_AON 0x418 +#define TURINGNSP_Q6SS_AHBS_AON 0x414 +#define TURINGNSP_Q6SS_ALT_RESET_CTL 0x10034 +#define TURINGNSP_NSPNOC 0x22c +#define TURINGNSP_VAPSS_GDSCR 0x80 + +/* + * Additional Turing CC / QDSP6 PUB register offsets used by the reset sequence + * (within the Turing CC and QDSP6 PUB blocks respectively). + */ +#define TURINGNSP_NSPAUX_XO_CBCR 0x40 +#define TURINGNSP_NSPAUX_GDSCR 0x200 +#define TURINGNSP_QDSP6SS_RET_CFG 0x1c + +#define NSPAUX_GDSCR_RETAIN_FF_ENABLE_BIT BIT(11) +#define Q6SS_ALT_RESET_CTL_ALT_ARES_BYPASS_BIT BIT(0) +#define QDSP6SS_RET_CFG_RET_ARES_ENA_BIT BIT(0) + +/* + * Global blocks involved in the Turing reset (offsets within each window); + * the GCC config-NoC AHB CBCRs gate the SWAY NIU socket. + */ +#define GCC_TURING_0_CFG_AHB_CBCR 0x41028 +#define GCC_TURING_1_CFG_AHB_CBCR 0x12028 +#define CBCR_CLK_ENABLE_BIT BIT(0) + +/* AOSS_CC compute-subsystem restart (within AOSS_CC window). */ +#define AOSS_CC_COMPUTESS_RESTART 0x4f030 +#define COMPUTESS_RESTART_SS_0_BIT BIT(0) +#define COMPUTESS_RESTART_SS_1_BIT BIT(1) + +/* RPMH PDC global sync-reset (within RPMH_PDC_GLOBAL window). */ +#define RPMH_PDC_SYNC_RESET 0x1000 +#define PDC_SYNC_RESET_COMPUTE_BIT BIT(9) +#define PDC_SYNC_RESET_NSP_BIT BIT(12) + +/* RPMH PDC per-block mode status, drv0 (within each PDC window). */ +#define RPMH_PDC_MODE_STATUS_DRV0 0x1030 +#define PDC_MODE_STATUS_SEQ_BUSY_BIT BIT(0) + +/* + * TCSR Turing master-halt / power registers (offsets within the TCSR mutex + * window); the CDSP1 block sits 0x18 above CDSP0. + */ +#define TCSR_TURING_HALTREQ 0x34000 +#define TCSR_TURING_HALTACK 0x34004 +#define TCSR_TURING_MASTER_IDLE 0x34008 +#define TCSR_TURING_PWR_ON 0x3400c +#define TCSR_TURING1_HALT_REQ 0x34018 +#define TCSR_TURING1_HALT_ACK 0x3401c +#define TCSR_TURING1_MASTER_IDLE 0x34020 +#define TCSR_TURING1_PWR_ON 0x34028 +#define TCSR_TURING_BIT BIT(0) + +/* + * QDSP6 boot / PLL / core CC blocks relative to the subsystem base; the + * enable-processor window at TURINGNSP_BOOT_OFFSET (0x50000) covers all three. + */ +#define TURINGNSP_BOOT_OFFSET 0x02300000 +#define TURINGNSP_PROC_WINDOW_SIZE 0x50000 +#define TURINGNSP_Q6_PLL_OFFSET 0x02340000 +#define TURINGNSP_CORE_CC_OFFSET 0x02348000 + +/* Offsets within the boot block (TURINGNSP_BOOT_OFFSET). */ +#define QDSP6SS_BOOT_CORE_START 0x400 + +/* Offsets within the core clock-controller block (TURINGNSP_CORE_CC_OFFSET). */ +#define QDSP6SS_CORE_CMD_RCGR 0x20 +#define QDSP6SS_CORE_CFG_RCGR 0x24 + +/* + * Q6 core RCG: source select = Q6 PLL, divider = 1. CFG_RCGR holds SRC_SEL at + * bits [10:8] and SRC_DIV at bits [4:0]. + */ +#define Q6RCG_SRC_SEL 0x2 +#define Q6RCG_SRC_SEL_SHIFT 8 +#define Q6RCG_SRC_DIV 0x1 +#define Q6RCG_CFG_VALUE (((Q6RCG_SRC_SEL) << \ + (Q6RCG_SRC_SEL_SHIFT)) | \ + (Q6RCG_SRC_DIV)) + +/* Q6 Lucid-EVO PLL settings, identical for both NSP instances. */ +#define TURINGNSP_Q6_PLL_L_VAL 0x32 +#define TURINGNSP_Q6_PLL_CAL_L_VAL 0x44 +#define TURINGNSP_Q6_PLL_CONFIG_CTL 0x20485699 +#define TURINGNSP_Q6_PLL_CONFIG_CTL_U 0x00182261 +#define TURINGNSP_Q6_PLL_CONFIG_CTL_U1 0x32AA299C +#define TURINGNSP_Q6_PLL_USER_CTL 0x00000000 +#define TURINGNSP_Q6_PLL_USER_CTL_U 0x00400805 + +/* + * LPASS / ADSP (QDSP6 v68/v69). All offsets are relative to LPASS_BASE; the + * subsystem window is mapped once by the PAS PTA (pas_platform_mem_setup), so + * the clock driver only derives sub-block bases as LPASS_BASE + offset. + */ +#define LPASS_PUB_OFFSET 0x00400000 +#define LPASS_PLL_OFFSET 0x00440000 +#define LPASS_CORE_CC_OFFSET 0x00448000 +#define LPASS_AON_CC_OFFSET 0x00808000 +#define LPASS_MCC_OFFSET 0x008d0000 +#define LPASS_TOP_CC_OFFSET 0x01000000 + +/* Offsets within the QDSP6 PUB block (LPASS_PUB_OFFSET). */ +#define LPASS_QDSP6SS_RST_EVB 0x10 +#define LPASS_QDSP6SS_BOOT_CORE_START 0x400 +#define LPASS_QDSP6SS_BOOT_CMD 0x404 +#define LPASS_QDSP6SS_BOOT_STATUS 0x408 + +/* Offset within the MCC block (LPASS_MCC_OFFSET). */ +#define LPASS_EFUSE_Q6SS_EVB_SEL 0xb000 + +/* Offsets within the core clock-controller block (LPASS_CORE_CC_OFFSET). */ +#define LPASS_QDSP6SS_CORE_CMD_RCGR 0x0 +#define LPASS_QDSP6SS_CORE_CFG_RCGR 0x4 +#define LPASS_QDSP6SS_CORE_CBCR 0x20 + +/* Offsets within the always-on clock-controller block (LPASS_AON_CC_OFFSET). */ +#define LPASS_AON_CC_Q6_AHBM_CBCR 0x101c +#define LPASS_AON_CC_Q6_AHBS_CBCR 0x1020 + +/* Offset within the LPASS top clock-controller block (LPASS_TOP_CC_OFFSET). */ +#define LPASS_TOP_CC_LPI_Q6_AXIM_HS_CBCR 0x4000 + +/* GCC config-NoC LPASS access branch (offset within the GCC window). */ +#define GCC_CFG_NOC_LPASS_CBCR 0x43024 + +/* + * LPASS Q6 Lucid-EVO PLL settings, taken from the reference clock driver + * HALclkPLLSettings.h (HAL_CLK_LPASS_AON_CC_LPASS_QDSP6SS_PLL_*). Identical to + * the Turing Q6 PLL except for the L value. + */ +#define LPASS_Q6_PLL_L_VAL 0x2C +#define LPASS_Q6_PLL_CAL_L_VAL 0x44 +#define LPASS_Q6_PLL_CONFIG_CTL 0x20485699 +#define LPASS_Q6_PLL_CONFIG_CTL_U 0x00182261 +#define LPASS_Q6_PLL_CONFIG_CTL_U1 0x32AA299C +#define LPASS_Q6_PLL_USER_CTL 0x00000000 +#define LPASS_Q6_PLL_USER_CTL_U 0x00400805 + +/* + * GP-DSP0 / GP-DSP1 (TURINGGDSP / TURINGGDSP1, QDSP6 v68/v69) sub-block offsets + * relative to TURING_GDSP_{0,1}_BASE; identical for both instances. + */ +#define TURINGGDSP_GDSP_CC_OFFSET 0x00808000 +#define TURINGGDSP_PUB_OFFSET 0x00c00000 +#define TURINGGDSP_PLL_OFFSET 0x00c40000 +#define TURINGGDSP_CORE_CC_OFFSET 0x00c48000 + +/* Offsets within the GDSP_CC block (TURINGGDSP_GDSP_CC_OFFSET). */ +#define TURINGGDSP_Q6SS_AHBS_AON_CBCR 0x10 + +/* Offsets within the QDSP6 PUB block (TURINGGDSP_PUB_OFFSET). */ +#define TURINGGDSP_QDSP6SS_RST_EVB 0x10 +#define TURINGGDSP_QDSP6SS_DBG_CFG 0x18 +#define TURINGGDSP_QDSP6SS_RET_CFG 0x1c +#define TURINGGDSP_QDSP6SS_BOOT_CORE_START 0x400 +#define TURINGGDSP_QDSP6SS_BOOT_CMD 0x404 +#define TURINGGDSP_QDSP6SS_BOOT_STATUS 0x408 + +/* Offsets in the core clock-controller block (TURINGGDSP_CORE_CC_OFFSET). */ +#define TURINGGDSP_QDSP6SS_CORE_CMD_RCGR 0x0 +#define TURINGGDSP_QDSP6SS_CORE_CFG_RCGR 0x4 +#define TURINGGDSP_QDSP6SS_CORE_CBCR 0x20 + +/* GCC config-NoC AHB / aggre-NoC AXI branches (within GCC window). */ +#define GCC_GPDSP_0_CFG_AHB_CBCR 0x16008 +#define GCC_AGGRE_NOC_GPDSP_0_AXI_CBCR 0x16004 +#define GCC_GPDSP_1_CFG_AHB_CBCR 0x15008 +#define GCC_AGGRE_NOC_GPDSP_1_AXI_CBCR 0x15004 + +/* AOSS_CC GP-DSP subsystem restart (within AOSS_CC window). */ +#define AOSS_CC_GPDSP_RESTART 0x4f034 +#define GPDSP_RESTART_SS_0_BIT BIT(0) +#define GPDSP_RESTART_SS_1_BIT BIT(1) + +/* RPMH PDC global sync-reset bits for GP-DSP (in RPMH_PDC_GLOBAL window). */ +#define PDC_SYNC_RESET_GPDSP0_BIT BIT(1) +#define PDC_SYNC_RESET_GPDSP1_BIT BIT(10) + +/* + * TCSR GP-DSP master-halt / power registers (offsets within the TCSR mutex + * window). The GDSP1 block sits 0x14 above the GDSP0 block. Unlike the Turing + * NSP, the reset sequence checks two master-idle bits (IL0 and IL1). + */ +#define TCSR_GPDSP0_HALT_REQ 0x32000 +#define TCSR_GPDSP0_HALT_ACK 0x32004 +#define TCSR_GPDSP0_IL0_MASTER_IDLE 0x32008 +#define TCSR_GPDSP0_IL1_MASTER_IDLE 0x3200c +#define TCSR_GPDSP0_PWR_ON 0x32010 +#define TCSR_GPDSP1_HALT_REQ 0x32014 +#define TCSR_GPDSP1_HALT_ACK 0x32018 +#define TCSR_GPDSP1_IL0_MASTER_IDLE 0x3201c +#define TCSR_GPDSP1_IL1_MASTER_IDLE 0x32020 +#define TCSR_GPDSP1_PWR_ON 0x32024 + +/* + * GP-DSP Q6 Lucid-EVO PLL settings, identical for both instances; differs from + * the Turing NSP Q6 PLL only in the L value. + */ +#define GPDSP_Q6_PLL_L_VAL 0x3A +#define GPDSP_Q6_PLL_CAL_L_VAL 0x44 +#define GPDSP_Q6_PLL_CONFIG_CTL 0x20485699 +#define GPDSP_Q6_PLL_CONFIG_CTL_U 0x00182261 +#define GPDSP_Q6_PLL_CONFIG_CTL_U1 0x32AA299C +#define GPDSP_Q6_PLL_USER_CTL 0x00000000 +#define GPDSP_Q6_PLL_USER_CTL_U 0x00400805 + #endif /* _CLOCK_GROUP_QCOM_H_ */ diff --git a/core/drivers/clk/qcom/sub.mk b/core/drivers/clk/qcom/sub.mk index 5e8b39c30..f47622b46 100644 --- a/core/drivers/clk/qcom/sub.mk +++ b/core/drivers/clk/qcom/sub.mk @@ -1,5 +1,8 @@ global-incdirs-y += . global-incdirs-y += platform/$(PLATFORM_FLAVOR) -srcs-y += clock-qcom.c clock-qcom-pas.c +srcs-y += clock-qcom.c +srcs-$(CFG_QCOM_PAS_PTA) += platform/$(PLATFORM_FLAVOR)/clock-qcom-pas.c + incdirs-y += . +incdirs-$(CFG_QCOM_PAS_PTA) += platform/$(PLATFORM_FLAVOR) diff --git a/core/drivers/crypto/qcom/hwkm.c b/core/drivers/crypto/qcom/hwkm.c new file mode 100644 index 000000000..6d3d7e01c --- /dev/null +++ b/core/drivers/crypto/qcom/hwkm.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +register_phys_mem_pgdir(MEM_AREA_IO_SEC, HWKM_MASTER_BASE, HWKM_MASTER_SIZE); + +static_assert(HW_UNIQUE_KEY_LENGTH <= HWKM_MAX_KEY_SIZE); + +#define HWKM_BBAC_BIT(slot) BIT((slot) % 32) + +#define HWKM_BANK0_BBAC_0 \ + (HWKM_BBAC_BIT(HWKM_SLOT_TZ_NKDK_L2) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TZ_PKDK_L2) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TZ_SKDK_L2) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TZ_UKDK_L2) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TPKEY_SLOT) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TPKEY_ODD_SLOT) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TZ_SWAP_KEY_SLOT) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TZ_SWAP_KEY_ODD_SLOT) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TZ_WRAP_KEY_SLOT) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TZ_WRAP_KEY_ODD_SLOT) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TZ_GENERAL_PURPOSE_SLOT1) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TZ_GENERAL_PURPOSE_SLOT2) | \ + HWKM_BBAC_BIT(HWKM_SLOT_PERSISTENT_SHARED_SLOT_PAIR1) | \ + HWKM_BBAC_BIT(HWKM_SLOT_PERSISTENT_SHARED_SLOT_PAIR1_ODD) | \ + HWKM_BBAC_BIT(HWKM_SLOT_PERSISTENT_SHARED_SLOT_PAIR2) | \ + HWKM_BBAC_BIT(HWKM_SLOT_PERSISTENT_SHARED_SLOT_PAIR2_ODD) | \ + HWKM_BBAC_BIT(HWKM_SLOT_TZ_MIXING_KEY_SLOT)) + +static struct hwkm_drv_ctx hwkm_ctx = { + .hwkm_lock = MUTEX_INITIALIZER, +}; + +struct hwkm_drv_ctx *hwkm_get_context(void) +{ + return hwkm_ctx.initialized ? &hwkm_ctx : NULL; +} + +struct hwkm_transaction *hwkm_transaction_alloc(void) +{ + return calloc(1, sizeof(struct hwkm_transaction)); +} + +void hwkm_transaction_free(struct hwkm_transaction *t) +{ + free_wipe(t); +} + +#define HWKM_ERR_ENTRY(m) { .status = (m), .name = #m } + +static const struct { uint32_t status; const char *name; } hwkm_err_table[] = { + /* Common errors. */ + HWKM_ERR_ENTRY(HWKM_ERR_RSP_FIFO_UNDERFLOW), + HWKM_ERR_ENTRY(HWKM_ERR_CMD_FIFO_OVERFLOW), + HWKM_ERR_ENTRY(HWKM_ERR_OPCODE_UNSUPPORTED), + HWKM_ERR_ENTRY(HWKM_ERR_INVALID_OPCODE), + HWKM_ERR_ENTRY(HWKM_ERR_INCORRECT_CMD_LENGTH), + HWKM_ERR_ENTRY(HWKM_ERR_CRC_CHECK), + HWKM_ERR_ENTRY(HWKM_ERR_BBAC_ACCESS), + /* NIST_KEYGEN errors. */ + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_KEYSLOT_ID_OUT_OF_RANGE), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_UNSUPPORTED_KEY_SIZE), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_KT_PARITY), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_INVALID_KEY_TYPE), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_INVALID_ALG_ALLOWED), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_INVALID_KEY_ATTRIB), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_INVALID_TPKEY_ATTRIB), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_INVALID_KSK_ATTRIB), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_INVALID_KWK_ATTRIB), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_INVALID_KDF_DEPTH), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_INVALID_SECURITY_LEVEL), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_DKS_SLOT_NOT_EMPTY), + HWKM_ERR_ENTRY(HWKM_NIST_KEYGEN_ERR_ACCESS_VIOLATION), + /* KEY_SLOT_RDWR errors. */ + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_KEYSLOT_ID_OUT_OF_RANGE), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_UNSUPPORTED_KEY_SIZE), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_KT_PARITY), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_INVALID_SECURITY_LEVEL), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_INVALID_KEY_TYPE), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_INVALID_ALG_ALLOWED), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_INVALID_KEY_ATTRIB), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_INVALID_TPKEY_ATTRIB), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_INVALID_KSK_ATTRIB), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_INVALID_KWK_ATTRIB), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_INVALID_KDF_DEPTH), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_SECURITY_LEVEL_VIOLATION), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_SKS_SLOT_EMPTY), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_DKS_SLOT_NOT_EMPTY), + HWKM_ERR_ENTRY(HWKM_KEY_SLOT_RDWR_ERR_ACCESS_VIOLATION), + /* SYSTEM_KDF errors. */ + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_FR_RD_ERR_ON_SLAVE), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_MKS_L1L2_NOT_ALLOWED), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_SEC_CTRL_ACCESS), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_KT_PARITY), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_BSVE_BIT_NOT_SUPPORTED), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_INVALID_SECURITY_LEVEL), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_INVALID_KEY_TYPE), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_INVALID_ALG_ALLOWED), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_SWAP_EXPORT_NOT_ALLOWED), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_KEYPOLICY_CONSISTENCY), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_ENCRYPT_NOT_ALLOWED), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_UNEXPECTED_ALG_ALLOWED), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_UNEXPECTED_KEY_TYPE), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_KDF_DEPTH_ERROR), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_KDK_TYPE), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_KEY_SIZE), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_KEYSLOT_SLOT), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_KEYSLOT_OUT_OF_RANGE), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_DOUBLE_KEY_SLOT_NOT_EVEN), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_ACCESS_VIOLATION), + HWKM_ERR_ENTRY(HWKM_SYSTEM_KDF_ERR_SECURITY_LEVEL_VIOLATION), + /* KEY_WRAP_EXPORT errors. */ + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_KWK_DOUBLE_KEY_ODD_SLOT), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_ENCRYPT_NOT_ALLOWED), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_SKS_SIZE_ERROR), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_SKS_SLOT_OUT_OF_RANGE), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_KWK_SIZE_ERROR), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_KWK_SLOT_OUT_OF_RANGE), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_KT_PARITY), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_WRAP_WITH_TPKEY_NOT_ALLOWED), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_SWAP_EXPORT_NOT_ALLOWED), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_WRAP_EXPORT_NOT_ALLOWED), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_UNEXPECTED_ALG_ALLOWED), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_SECURITY_LEVEL_ERROR), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_UNEXPECTED_KEY_TYPE), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_KWK_SLOT_EMPTY), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_SKS_SLOT_EMPTY), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_SKS_ACCESS_VIOLATION), + HWKM_ERR_ENTRY(HWKM_EXPORT_ERR_KWK_ACCESS_VIOLATION), + /* KEY_UNWRAP_IMPORT errors. */ + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_UNWRAP_FAILED), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_KWK_DOUBLE_KEY_ODD_SLOT), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_KWK_SIZE_ERROR), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_DKS_SIZE_ERROR), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_DKS_OUT_OF_RANGE), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_KWK_SLOT_OUT_OF_RANGE), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_KT_PARITY), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_SECURITY_LEVEL_ERROR), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_INVALID_SECURITY_LEVEL), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_INVALID_KEY_TYPE), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_INVALID_ALG_ALLOWED), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_CONSISTENCY_CHECK_FAILED), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_INVALID_TPKEY_ATTRIB), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_INVALID_KSK_ATTRIB), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_INVALID_KWK_ATTRIB), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_INVALID_KDF_DEPTH), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_DECRYPT_NOT_ALLOWED), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_UNEXPECTED_ALG_ALLOWED), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_UNEXPECTED_KEY_TYPE), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_KWK_SLOT_EMPTY), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_DKS_SLOT_NOT_EMPTY), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_DKS_ACCESS_VIOLATION), + HWKM_ERR_ENTRY(HWKM_IMPORT_ERR_KWK_ACCESS_VIOLATION), + /* KEY_SLOT_CLEAR errors. */ + HWKM_ERR_ENTRY(HWKM_CLEAR_ERR_KEYSLOT_ID_NOT_ACCESSIBLE), + HWKM_ERR_ENTRY(HWKM_CLEAR_ERR_KEYSLOT_ID_OUT_OF_RANGE), + HWKM_ERR_ENTRY(HWKM_CLEAR_ERR_KEY_SIZE), + HWKM_ERR_ENTRY(HWKM_CLEAR_ERR_DOUBLE_KEY_DKS_SLOT_NOT_EVEN), + HWKM_ERR_ENTRY(HWKM_CLEAR_ERR_DKS_SLOT_EMPTY), + HWKM_ERR_ENTRY(HWKM_CLEAR_ERR_ACCESS_VIOLATION), + /* SET_TPKEY errors. */ + HWKM_ERR_ENTRY(HWKM_TPKEY_ERR_KT_PARITY), + HWKM_ERR_ENTRY(HWKM_TPKEY_ERR_DOUBLE_KEY_SLOT_NOT_EVEN), + HWKM_ERR_ENTRY(HWKM_TPKEY_ERR_WRONG_KEY_SIZE), + HWKM_ERR_ENTRY(HWKM_TPKEY_ERR_KEYSLOT_ID_OUT_OF_RANGE), + HWKM_ERR_ENTRY(HWKM_TPKEY_ERR_UNEXPECTED_KEY_TYPE), + HWKM_ERR_ENTRY(HWKM_TPKEY_ERR_SKS_SLOT_EMPTY), + HWKM_ERR_ENTRY(HWKM_TPKEY_ERR_ACCESS_VIOLATION), +}; + +const char *hwkm_err2str(uint32_t status) +{ + size_t i = 0; + + for (i = 0; i < ARRAY_SIZE(hwkm_err_table); i++) + if (hwkm_err_table[i].status == status) + return hwkm_err_table[i].name; + + return "Unknown"; +} + +static TEE_Result hwkm_init(void) +{ + uint32_t status = 0; + vaddr_t base = 0; + + base = (vaddr_t)phys_to_virt(HWKM_MASTER_BASE, MEM_AREA_IO_SEC, + HWKM_MASTER_SIZE); + if (!base) + return TEE_ERROR_GENERIC; + + /* Check the hardware self-test status. */ + status = io_read32_off(base, HWKM_TZ_KM_STATUS); + if (status & (HWKM_TZ_KM_STATUS_BIST_ERROR | + HWKM_TZ_KM_STATUS_CRYPTO_LIB_BIST_ERROR)) { + EMSG("hwkm: BIST failed, status=0x%08"PRIx32, status); + return TEE_ERROR_GENERIC; + } + + /* Disable CRC checking on command packets. */ + io_write32_off_field(base, HWKM_TZ_KM_CTL, + HWKM_TZ_KM_CTL_CRC_CHECK_EN, 0); + + io_write32_off(base, HWKM_BANK0_AC + HWKM_BANKn_AC_BBAC_0, + HWKM_BANK0_BBAC_0); + io_write32_off(base, HWKM_BANK0_AC + HWKM_BANKn_AC_BBAC_1, 0); + io_write32_off(base, HWKM_BANK0_AC + HWKM_BANKn_AC_BBAC_2, 0); + io_write32_off(base, HWKM_BANK0_AC + HWKM_BANKn_AC_BBAC_3, 0); + io_write32_off(base, HWKM_BANK0_AC + HWKM_BANKn_AC_BBAC_4, 0); + + /* + * Clear the spurious RSP_FIFO_FULL sticky bit. + * HW errata QCTDD06252768: RSP_FIFO_FULL may be set after reset even + * though the FIFO is empty. Write 1 to clear it unconditionally so + * it does not interfere with CMD_DONE polling in + * master_run_transaction(). + */ + io_write32_off(base, HWKM_BANK0_KM_IRQ_STATUS, + HWKM_BANK0_KM_IRQ_STATUS_RSP_FIFO_FULL); + + hwkm_ctx.base = base; + hwkm_ctx.initialized = true; + + return TEE_SUCCESS; +} + +static TEE_Result hwkm_driver_init(void) +{ + struct tee_hw_unique_key huk = { }; + TEE_Result res = TEE_ERROR_GENERIC; + + res = hwkm_init(); + if (res) { + EMSG("hwkm: init failed: 0x%08"PRIx32, res); + return res; + } + + res = tee_otp_get_hw_unique_key(&huk); + if (res) { + EMSG("hwkm: HUK derivation failed: 0x%08"PRIx32, res); + panic("HWKM HUK derivation failure"); + } + + memzero_explicit(&huk, sizeof(huk)); + + return TEE_SUCCESS; +} + +service_init(hwkm_driver_init); diff --git a/core/drivers/crypto/qcom/hwkm_huk.c b/core/drivers/crypto/qcom/hwkm_huk.c new file mode 100644 index 000000000..81d71e642 --- /dev/null +++ b/core/drivers/crypto/qcom/hwkm_huk.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define HWKM_HUK_MKS_CTX "OPTEE_HUK_HWKM_V1_MKS" +#define HWKM_HUK_L3_CTX "OPTEE_HUK_HWKM_V1_L3" +#define HWKM_HUK_L4_CTX "OPTEE_HUK_HWKM_V1_L4" + +#define HWKM_SCRATCH_SLOT_MKS HWKM_SLOT_TZ_MIXING_KEY_SLOT +#define HWKM_SCRATCH_SLOT_A HWKM_SLOT_TZ_GENERAL_PURPOSE_SLOT1 +#define HWKM_SCRATCH_SLOT_B HWKM_SLOT_TZ_GENERAL_PURPOSE_SLOT2 + +static void hwkm_setup_kdf(struct hwkm_transaction *t, + uint8_t dks, uint8_t kdk, uint8_t mks, + const struct hwkm_key_policy *policy, + const struct hwkm_bsve *bsve, + const char *ctx, size_t ctx_len) +{ + t->cmd.op = HWKM_OP_SYSTEM_KDF; + t->cmd.kdf.dks = dks; + t->cmd.kdf.kdk = kdk; + t->cmd.kdf.mks = mks; + t->cmd.kdf.policy = *policy; + t->cmd.kdf.bsve = *bsve; + t->cmd.kdf.ctx_len = ctx_len; + memcpy(t->cmd.kdf.ctx, ctx, ctx_len); +} + +/* + * hwkm_huk_derive_mks() - Derive the SKDK L3 mixing key into the MKS slot. + * + * TZ_SKDK_L2 is an L2 static key and cannot be used directly as the MKS + * argument in SYSTEM_KDF (hardware rejects L1/L2 slots with + * HWKM_SYSTEM_KDF_ERR_MKS_L1L2_NOT_ALLOWED). This function produces a stable + * L3 generic key from TZ_SKDK_L2 and loads it into HWKM_SCRATCH_SLOT_MKS. + * + * Return: TEE_SUCCESS on success, or a TEE_ERROR_* code on failure. + */ +static TEE_Result hwkm_huk_derive_mks(void) +{ + /* SKDK L3 mixing key: kdf_depth = 0 so it cannot be used as a KDK. */ + const struct hwkm_key_policy mks_policy = { + .km_by_tz_allowed = true, + .alg_allowed = HWKM_ALGO_AES256_CMAC, + .enc_allowed = true, + .dec_allowed = true, + .key_type = HWKM_KEY_TYPE_GENERIC_KEY, + .security_lvl = HWKM_KEY_SECURITY_LVL_SW_KEY, + .hw_destination = HWKM_KEY_DEST_KM_MASTER, + }; + const struct hwkm_bsve mks_bsve = { + .enabled = true, + .km_swc_en = true, + .km_apps_secure_en = true, + .km_fuse_region_sha_digest_en = + UINT64_C(CFG_HWKM_HUK_FUSE_REGION_DIGEST), + }; + struct hwkm_transaction *t_clear = NULL; + struct hwkm_transaction *t_kdf = NULL; + TEE_Result res = TEE_SUCCESS; + int rc = 0; + + t_clear = hwkm_transaction_alloc(); + t_kdf = hwkm_transaction_alloc(); + if (!t_clear || !t_kdf) { + res = TEE_ERROR_OUT_OF_MEMORY; + goto out; + } + + t_clear->cmd.op = HWKM_OP_KEY_SLOT_CLEAR; + t_clear->cmd.clear.dks = HWKM_SCRATCH_SLOT_MKS; + t_clear->cmd.clear.is_double_key = false; + hwkm_setup_kdf(t_kdf, HWKM_SCRATCH_SLOT_MKS, HWKM_SLOT_TZ_SKDK_L2, + 0, &mks_policy, &mks_bsve, + HWKM_HUK_MKS_CTX, sizeof(HWKM_HUK_MKS_CTX) - 1); + + rc = hwkm_run_transactions(HWKM_KEY_DEST_KM_MASTER, 2, + (struct hwkm_transaction *const[]){ + t_clear, t_kdf }); + if (rc) { + res = hwkm_to_optee(rc); + goto out_clear; + } + + if (t_clear->rsp.status != HWKM_RSP_ERR_SUCCESS && + t_clear->rsp.status != HWKM_CLEAR_ERR_DKS_SLOT_EMPTY) { + res = TEE_ERROR_GENERIC; + goto out_clear; + } + + if (t_kdf->rsp.status != HWKM_RSP_ERR_SUCCESS) { + EMSG("hwkm: SYSTEM_KDF MKS failed: %s", + hwkm_err2str(t_kdf->rsp.status)); + res = TEE_ERROR_GENERIC; + goto out_clear; + } + + goto out; + +out_clear: + /* Ensure the MKS slot is clean before surfacing the error. */ + t_clear->hdl = NULL; + hwkm_run_transaction(HWKM_KEY_DEST_KM_MASTER, t_clear); + +out: + hwkm_transaction_free(t_clear); + hwkm_transaction_free(t_kdf); + return res; +} + +/* + * hwkm_huk_derive_keys() - Run the two-level UKDK KDF and read out the HUK. + * @huk: Output buffer receiving the derived hardware unique key. + * + * Derives the UKDK L3 KDK into HWKM_SCRATCH_SLOT_A with the SKDK L3 mixing + * key in HWKM_SCRATCH_SLOT_MKS bound via BSVE.MKS_EN, then derives the final + * L4 HUK from slot A into slot B, reads it out, and clears all three scratch + * slots. + * + * Return: TEE_SUCCESS on success, or a TEE_ERROR_* code on failure. + * All three scratch slots are cleared on any failure before returning. + */ +static TEE_Result hwkm_huk_derive_keys(uint8_t huk[HW_UNIQUE_KEY_LENGTH]) +{ + /* L3: intermediate KDK derived from TZ_UKDK_L2. */ + const struct hwkm_key_policy l3_policy = { + .km_by_tz_allowed = true, + .alg_allowed = HWKM_ALGO_AES256_CMAC, + .enc_allowed = true, + .dec_allowed = true, + .key_type = HWKM_KEY_TYPE_KDK, + .kdf_depth = 1, + .security_lvl = HWKM_KEY_SECURITY_LVL_HW_KEY, + .hw_destination = HWKM_KEY_DEST_KM_MASTER, + }; + /* L4: final SW-readable HUK derived from the L3 KDK. */ + const struct hwkm_key_policy l4_policy = { + .km_by_tz_allowed = true, + .alg_allowed = HWKM_ALGO_AES256_CMAC, + .enc_allowed = true, + .dec_allowed = true, + .key_type = HWKM_KEY_TYPE_GENERIC_KEY, + .security_lvl = HWKM_KEY_SECURITY_LVL_SW_KEY, + .hw_destination = HWKM_KEY_DEST_KM_MASTER, + }; + const struct hwkm_bsve huk_bsve = { + .enabled = true, + .km_swc_en = true, + .km_apps_secure_en = true, + .km_mks_en = IS_ENABLED(CFG_HWKM_HUK_MIX_SKDK), + .km_fuse_region_sha_digest_en = + UINT64_C(CFG_HWKM_HUK_FUSE_REGION_DIGEST), + }; + struct hwkm_transaction *t_clear_a = NULL; + struct hwkm_transaction *t_clear_b = NULL; + struct hwkm_transaction *t_clear_mks = NULL; + struct hwkm_transaction *t_kdf_l3 = NULL; + struct hwkm_transaction *t_kdf_l4 = NULL; + struct hwkm_transaction *t_read = NULL; + TEE_Result res = TEE_SUCCESS; + int rc = 0; + + t_clear_a = hwkm_transaction_alloc(); + t_clear_b = hwkm_transaction_alloc(); + t_clear_mks = hwkm_transaction_alloc(); + t_kdf_l3 = hwkm_transaction_alloc(); + t_kdf_l4 = hwkm_transaction_alloc(); + t_read = hwkm_transaction_alloc(); + if (!t_clear_a || !t_clear_b || !t_clear_mks || + !t_kdf_l3 || !t_kdf_l4 || !t_read) { + res = TEE_ERROR_OUT_OF_MEMORY; + goto out; + } + + t_clear_a->cmd.op = HWKM_OP_KEY_SLOT_CLEAR; + t_clear_a->cmd.clear.dks = HWKM_SCRATCH_SLOT_A; + t_clear_a->cmd.clear.is_double_key = false; + t_clear_b->cmd.op = HWKM_OP_KEY_SLOT_CLEAR; + t_clear_b->cmd.clear.dks = HWKM_SCRATCH_SLOT_B; + t_clear_b->cmd.clear.is_double_key = false; + t_clear_mks->cmd.op = HWKM_OP_KEY_SLOT_CLEAR; + t_clear_mks->cmd.clear.dks = HWKM_SCRATCH_SLOT_MKS; + t_clear_mks->cmd.clear.is_double_key = false; + hwkm_setup_kdf(t_kdf_l3, HWKM_SCRATCH_SLOT_A, HWKM_SLOT_TZ_UKDK_L2, + HWKM_SCRATCH_SLOT_MKS, &l3_policy, &huk_bsve, + HWKM_HUK_L3_CTX, sizeof(HWKM_HUK_L3_CTX) - 1); + hwkm_setup_kdf(t_kdf_l4, HWKM_SCRATCH_SLOT_B, HWKM_SCRATCH_SLOT_A, + HWKM_SCRATCH_SLOT_MKS, &l4_policy, &huk_bsve, + HWKM_HUK_L4_CTX, sizeof(HWKM_HUK_L4_CTX) - 1); + + /* Clear A and B, derive UKDK L3 into A, derive L4 HUK into B. */ + rc = hwkm_run_transactions(HWKM_KEY_DEST_KM_MASTER, 4, + (struct hwkm_transaction *const[]){ + t_clear_a, t_clear_b, + t_kdf_l3, t_kdf_l4 }); + if (rc) { + res = hwkm_to_optee(rc); + goto out_clear; + } + + if ((t_clear_a->rsp.status != HWKM_RSP_ERR_SUCCESS && + t_clear_a->rsp.status != HWKM_CLEAR_ERR_DKS_SLOT_EMPTY) || + (t_clear_b->rsp.status != HWKM_RSP_ERR_SUCCESS && + t_clear_b->rsp.status != HWKM_CLEAR_ERR_DKS_SLOT_EMPTY)) { + res = TEE_ERROR_GENERIC; + goto out_clear; + } + + if (t_kdf_l3->rsp.status != HWKM_RSP_ERR_SUCCESS) { + EMSG("hwkm: SYSTEM_KDF L3 failed: %s", + hwkm_err2str(t_kdf_l3->rsp.status)); + res = TEE_ERROR_GENERIC; + goto out_clear; + } + + if (t_kdf_l4->rsp.status != HWKM_RSP_ERR_SUCCESS) { + EMSG("hwkm: SYSTEM_KDF L4 failed: %s", + hwkm_err2str(t_kdf_l4->rsp.status)); + res = TEE_ERROR_GENERIC; + goto out_clear; + } + + /* Read L4 HUK from slot B, then clear A, B and MKS. */ + t_read->cmd.op = HWKM_OP_KEY_SLOT_RDWR; + t_read->cmd.rdwr.slot = HWKM_SCRATCH_SLOT_B; + t_read->cmd.rdwr.is_write = false; + + rc = hwkm_run_transactions(HWKM_KEY_DEST_KM_MASTER, 4, + (struct hwkm_transaction *const[]){ + t_read, t_clear_a, + t_clear_b, t_clear_mks }); + if (rc) { + res = hwkm_to_optee(rc); + goto out_clear; + } + + if (t_read->rsp.status != HWKM_RSP_ERR_SUCCESS) { + EMSG("hwkm: KEY_SLOT_RDWR read failed: %s", + hwkm_err2str(t_read->rsp.status)); + res = TEE_ERROR_GENERIC; + goto out_clear; + } + + if (t_clear_a->rsp.status != HWKM_RSP_ERR_SUCCESS || + t_clear_b->rsp.status != HWKM_RSP_ERR_SUCCESS || + t_clear_mks->rsp.status != HWKM_RSP_ERR_SUCCESS) { + res = TEE_ERROR_GENERIC; + goto out; + } + + memcpy(huk, t_read->rsp.rdwr.key, HW_UNIQUE_KEY_LENGTH); + goto out; + +out_clear: + t_clear_a->hdl = NULL; + t_clear_b->hdl = NULL; + t_clear_mks->hdl = NULL; + hwkm_run_transaction(HWKM_KEY_DEST_KM_MASTER, t_clear_a); + hwkm_run_transaction(HWKM_KEY_DEST_KM_MASTER, t_clear_b); + hwkm_run_transaction(HWKM_KEY_DEST_KM_MASTER, t_clear_mks); + +out: + hwkm_transaction_free(t_clear_a); + hwkm_transaction_free(t_clear_b); + hwkm_transaction_free(t_clear_mks); + hwkm_transaction_free(t_kdf_l3); + hwkm_transaction_free(t_kdf_l4); + hwkm_transaction_free(t_read); + return res; +} + +TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey) +{ + struct hwkm_drv_ctx *drv = NULL; + TEE_Result res = TEE_SUCCESS; + + if (!hwkey) + return TEE_ERROR_BAD_PARAMETERS; + + drv = hwkm_get_context(); + if (!drv) + return TEE_ERROR_NOT_SUPPORTED; + + mutex_lock(&drv->hwkm_lock); + + if (drv->hwkm_huk_ready) { + memcpy(hwkey->data, drv->hwkm_huk, HW_UNIQUE_KEY_LENGTH); + goto out; + } + + if (IS_ENABLED(CFG_HWKM_HUK_MIX_SKDK)) { + res = hwkm_huk_derive_mks(); + if (res) + goto out; + } + + res = hwkm_huk_derive_keys(drv->hwkm_huk); + if (res) + goto out; + + drv->hwkm_huk_ready = true; + memcpy(hwkey->data, drv->hwkm_huk, HW_UNIQUE_KEY_LENGTH); + +out: + mutex_unlock(&drv->hwkm_lock); + return res; +} diff --git a/core/drivers/crypto/qcom/hwkm_transaction.c b/core/drivers/crypto/qcom/hwkm_transaction.c new file mode 100644 index 000000000..37ca1ca93 --- /dev/null +++ b/core/drivers/crypto/qcom/hwkm_transaction.c @@ -0,0 +1,858 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Command packet format: + * Each command starts with a CMD[0] operation-info word that encodes the + * opcode, slot indices, flags, and total packet length. Subsequent words + * carry the policy, BSVE, software context, and a CRC word (always 0 while + * CRC checking is disabled). + */ + +static_assert(HWKM_OP_NIST_KEYGEN == 0x0); +static_assert(HWKM_OP_SYSTEM_KDF == 0x1); +static_assert(HWKM_OP_KEY_WRAP_EXPORT == 0x3); +static_assert(HWKM_OP_KEY_UNWRAP_IMPORT == 0x4); +static_assert(HWKM_OP_KEY_SLOT_CLEAR == 0x5); +static_assert(HWKM_OP_KEY_SLOT_RDWR == 0x6); +static_assert(HWKM_OP_SET_TPKEY == 0x7); + +#define HWKM_OPERATION_INFO_WORDS 1 + +/* Command and response formats. */ + +/* Shared macros: */ + +#define HWKM_KEY_POLICY_WORDS 2 +#define HWKM_BSVE_WORDS 3 +#define HWKM_KEY_BLOB_WORDS 17 +#define HWKM_SOFTWARE_CONTEXT_WORDS 16 +#define HWKM_KEY_RDWR_WORDS 8 + +static_assert(HWKM_KEY_BLOB_WORDS * sizeof(uint32_t) == HWKM_MAX_BLOB_SIZE); +static_assert(HWKM_SOFTWARE_CONTEXT_WORDS * sizeof(uint32_t) == + HWKM_MAX_CTX_SIZE); +static_assert(HWKM_KEY_RDWR_WORDS * sizeof(uint32_t) == HWKM_MAX_KEY_SIZE); + +/* + * HWKM_OP_NIST_KEYGEN - Generate a fresh key into a slot via hardware PRNG. + * + * CMD[0] = Operation info. + * CMD[1:2] = Policy. + * CMD[3] = CRC (disabled). + * + * RSP[0] = Unused. + * RSP[HWKM_OP_NIST_KEYGEN_RSP_ERR_IDX] = Error status. + */ +#define HWKM_OP_NIST_KEYGEN_CMD_WORDS 4 /* CMD[0] + policy + CRC. */ +#define HWKM_OP_NIST_KEYGEN_RSP_WORDS 2 /* RSP[0:1]. */ +#define HWKM_OP_NIST_KEYGEN_RSP_ERR_IDX 1 + +/* + * HWKM_OP_SYSTEM_KDF - Derive a child key from a KDK slot via hardware KDF. + * + * CMD[0] = Operation info. + * CMD[1:2] = Policy. + * CMD[3] = BSVE[0] if bsve is enabled, 0 otherwise. + * CMD[4:5] = BSVE[1:2] only if bsve is enabled. + * CMD[n:n + m] = Software Context (SC), where n = 4 or 6 depending on BSVE, + * and m is SC length. + * CMD[n + m + 1] = CRC (disabled). + * + * RSP[0] = Unused. + * RSP[HWKM_OP_SYSTEM_KDF_RSP_ERR_IDX] = Error status. + */ +/* CMD[0] + policy + BSVE[0] + CRC (minimum, excluding context). */ +#define HWKM_OP_SYSTEM_KDF_CMD_WORDS 4 +#define HWKM_OP_SYSTEM_KDF_RSP_WORDS 2 /* RSP[0:1]. */ +#define HWKM_OP_SYSTEM_KDF_RSP_ERR_IDX 1 + +/* + * HWKM_OP_KEY_WRAP_EXPORT - Encrypt a slot under a KWK/KSK and return the blob. + * + * CMD[0] = Operation info. + * CMD[1:3] = BSVE. + * CMD[4] = CRC (disabled). + * + * RSP[0] = Unused. + * RSP[1] = Error status. + * RSP[HWKM_OP_KEY_WRAP_EXPORT_RSP_BLOB_IDX: + * HWKM_OP_KEY_WRAP_EXPORT_RSP_BLOB_IDX + HWKM_KEY_BLOB_WORDS - 1] + * = Wrapped Key Blob. + */ +/* CMD[0] + BSVE + CRC. */ +#define HWKM_OP_KEY_WRAP_EXPORT_CMD_WORDS 5 +#define HWKM_OP_KEY_WRAP_EXPORT_RSP_WORDS 19 /* RSP[0:1] + blob. */ +#define HWKM_OP_KEY_WRAP_EXPORT_RSP_ERR_IDX 1 +#define HWKM_OP_KEY_WRAP_EXPORT_RSP_BLOB_IDX 2 + +/* + * HWKM_OP_KEY_UNWRAP_IMPORT - Decrypt a wrapped blob and write the key + * into a slot. + * + * CMD[0] = Operation info. + * CMD[1:17] = Wrapped Key Blob. + * CMD[18] = CRC (disabled). + * + * RSP[0] = Unused. + * RSP[HWKM_OP_KEY_UNWRAP_IMPORT_RSP_ERR_IDX] = Error status. + */ +/* CMD[0] + blob + CRC. */ +#define HWKM_OP_KEY_UNWRAP_IMPORT_CMD_WORDS 19 +#define HWKM_OP_KEY_UNWRAP_IMPORT_RSP_WORDS 2 /* RSP[0:1]. */ +#define HWKM_OP_KEY_UNWRAP_IMPORT_RSP_ERR_IDX 1 + +/* + * HWKM_OP_KEY_SLOT_CLEAR - Zeroize a slot and invalidate its policy word. + * + * CMD[0] = Operation info. + * CMD[1] = CRC (disabled). + * + * RSP[0] = Unused. + * RSP[HWKM_OP_KEY_SLOT_CLEAR_RSP_ERR_IDX] = Error status + */ +#define HWKM_OP_KEY_SLOT_CLEAR_CMD_WORDS 2 /* CMD[0] + CRC. */ +#define HWKM_OP_KEY_SLOT_CLEAR_RSP_WORDS 2 /* RSP[0:1]. */ +#define HWKM_OP_KEY_SLOT_CLEAR_RSP_ERR_IDX 1 + +/* + * HWKM_OP_KEY_SLOT_RDWR - Read or write raw key material for a SW_KEY slot. + * + * CMD[0] = Operation info. + * CMD[1:2] = Written policy (0 if read). + * CMD[3:10] = Written key value (0 if read). + * CMD[11] = CRC (disabled). + * + * RSP[0] = Unused. + * RSP[HWKM_OP_KEY_SLOT_RDWR_RSP_ERR_IDX] = Error status. + * RSP[HWKM_OP_KEY_SLOT_RDWR_RSP_POLICY_IDX: + * HWKM_OP_KEY_SLOT_RDWR_RSP_POLICY_IDX + HWKM_KEY_POLICY_WORDS - 1] + * = Read policy (0 if write). + * RSP[HWKM_OP_KEY_SLOT_RDWR_RSP_READ_KEY_IDX: + * HWKM_OP_KEY_SLOT_RDWR_RSP_READ_KEY_IDX + HWKM_KEY_RDWR_WORDS -1] + * = Read key value (0 if write). + */ +/* CMD[0] + policy + key + CRC. */ +#define HWKM_OP_KEY_SLOT_RDWR_CMD_WORDS 12 +/* RSP[0:1] + policy + key. */ +#define HWKM_OP_KEY_SLOT_RDWR_RSP_WORDS 12 +#define HWKM_OP_KEY_SLOT_RDWR_RSP_ERR_IDX 1 +#define HWKM_OP_KEY_SLOT_RDWR_RSP_POLICY_IDX 2 +#define HWKM_OP_KEY_SLOT_RDWR_RSP_READ_KEY_IDX 4 + +/* + * HWKM_OP_SET_TPKEY - Install a slot as the active transport protection key. + * + * CMD[0] = Operation info. + * CMD[1] = CRC (disabled). + * + * RSP[0] = Unused. + * RSP[HWKM_OP_SET_TPKEY_RSP_ERR_IDX] = Error status. + */ +#define HWKM_OP_SET_TPKEY_CMD_WORDS 2 /* CMD[0] + CRC. */ +#define HWKM_OP_SET_TPKEY_RSP_WORDS 2 /* RSP[0:1]. */ +#define HWKM_OP_SET_TPKEY_RSP_ERR_IDX 1 + +/* PACK and UNPACK. */ + +/* Set one field of @reg to @val, positioned by @mask's lowest set bit. */ +#define hwkm_pack(reg, val, mask) \ + ((reg) = set_field_u32((reg), (mask), (val))) +/* Store the field of @reg selected by @mask, right-justified, into @dst. */ +#define hwkm_unpack(dst, reg, mask) \ + ((dst) = (typeof(dst))get_field_u32((reg), (mask))) + +/* Operation info - HWKM_OPERATION_INFO_WORDS word. */ +#define HWKM_OP_INFO_OP_MASK GENMASK_32(3, 0) +#define HWKM_OP_INFO_SLOT1_DESC_MASK GENMASK_32(12, 5) +#define HWKM_OP_INFO_SLOT2_DESC_MASK GENMASK_32(20, 13) +#define HWKM_OP_INFO_OP_FLAG BIT(21) +#define HWKM_OP_INFO_CONTEXT_LEN_MASK GENMASK_32(26, 22) +#define HWKM_OP_INFO_LEN_MASK GENMASK_32(31, 27) + +/* Key policy - HWKM_KEY_POLICY_WORDS words. */ +#define HWKM_KEY_POL_WRAP_WITH_TPKEY BIT(2) +#define HWKM_KEY_POL_HW_DEST_MASK GENMASK_32(6, 3) +#define HWKM_KEY_POL_SEC_LVL_MASK GENMASK_32(10, 9) +#define HWKM_KEY_POL_SWAP_EXPORT BIT(11) +#define HWKM_KEY_POL_WRAP_EXPORT BIT(12) +#define HWKM_KEY_POL_KEY_TYPE_MASK GENMASK_32(15, 13) +#define HWKM_KEY_POL_KDF_DEPTH_MASK GENMASK_32(23, 16) +#define HWKM_KEY_POL_DECRYPT BIT(24) +#define HWKM_KEY_POL_ENCRYPT BIT(25) +#define HWKM_KEY_POL_ALG_MASK GENMASK_32(31, 26) +#define HWKM_KEY_POL_KM_BY_TZ BIT(0) +#define HWKM_KEY_POL_KM_BY_NSEC BIT(1) +#define HWKM_KEY_POL_KM_BY_MODEM BIT(2) +#define HWKM_KEY_POL_KM_BY_SPU BIT(3) + +/* Wrapping BSVE - HWKM_BSVE_WORDS words, word 0 only (words 1:2 reserved). */ +#define HWKM_WRAP_BSVE_KEY_POL_VER BIT(0) +#define HWKM_WRAP_BSVE_APPS_SEC BIT(1) +#define HWKM_WRAP_BSVE_MSA_SEC BIT(2) +#define HWKM_WRAP_BSVE_LCM_FUSE_ROW BIT(3) +#define HWKM_WRAP_BSVE_BOOT_STAGE_OTP BIT(4) + +/* KDF BSVE - HWKM_BSVE_WORDS words. */ +#define HWKM_KDF_BSVE_MKS GENMASK_32(7, 0) +#define HWKM_KDF_BSVE_KEY_POL_VER BIT(8) +#define HWKM_KDF_BSVE_APPS_SEC BIT(9) +#define HWKM_KDF_BSVE_MSA_SEC BIT(10) +#define HWKM_KDF_BSVE_LCM_FUSE_ROW BIT(11) +#define HWKM_KDF_BSVE_BOOT_STAGE_OTP BIT(12) +#define HWKM_KDF_BSVE_SWC BIT(13) +#define HWKM_KDF_BSVE_CHILD_KEY_POL BIT(14) +#define HWKM_KDF_BSVE_MKS_EN BIT(15) + +/* + * hwkm_pack_op_info() - Pack the CMD[0] operation-info word. + * @dst: Destination word. + * @op: Opcode [3:0]. + * @slot1_desc: DKS or SKS depending on opcode. + * @slot2_desc: KDK, KWK, or 0 depending on opcode. + * @op_flag: Flag whose meaning depends on opcode. + * @context_len: Software context length in words, KDF only. + * @len: Total command length in words. + */ +static void hwkm_pack_op_info(uint32_t *dst, uint32_t op, uint8_t slot1_desc, + uint8_t slot2_desc, bool op_flag, + uint32_t context_len, uint32_t len) +{ + *dst = op & HWKM_OP_INFO_OP_MASK; + + hwkm_pack(*dst, slot1_desc, HWKM_OP_INFO_SLOT1_DESC_MASK); + hwkm_pack(*dst, slot2_desc, HWKM_OP_INFO_SLOT2_DESC_MASK); + hwkm_pack(*dst, op_flag, HWKM_OP_INFO_OP_FLAG); + hwkm_pack(*dst, context_len, HWKM_OP_INFO_CONTEXT_LEN_MASK); + hwkm_pack(*dst, len, HWKM_OP_INFO_LEN_MASK); +} + +static void hwkm_pack_key_policy(uint32_t dst[HWKM_KEY_POLICY_WORDS], + const struct hwkm_key_policy *src) +{ + memset(dst, 0, HWKM_KEY_POLICY_WORDS * sizeof(uint32_t)); + /* Word 0: */ + hwkm_pack(dst[0], src->wrap_with_tpkey_allowed, + HWKM_KEY_POL_WRAP_WITH_TPKEY); + hwkm_pack(dst[0], src->hw_destination, HWKM_KEY_POL_HW_DEST_MASK); + hwkm_pack(dst[0], src->security_lvl, HWKM_KEY_POL_SEC_LVL_MASK); + hwkm_pack(dst[0], src->swap_export_allowed, HWKM_KEY_POL_SWAP_EXPORT); + hwkm_pack(dst[0], src->wrap_export_allowed, HWKM_KEY_POL_WRAP_EXPORT); + hwkm_pack(dst[0], src->key_type, HWKM_KEY_POL_KEY_TYPE_MASK); + hwkm_pack(dst[0], src->kdf_depth, HWKM_KEY_POL_KDF_DEPTH_MASK); + hwkm_pack(dst[0], src->dec_allowed, HWKM_KEY_POL_DECRYPT); + hwkm_pack(dst[0], src->enc_allowed, HWKM_KEY_POL_ENCRYPT); + hwkm_pack(dst[0], src->alg_allowed, HWKM_KEY_POL_ALG_MASK); + /* Word 1: */ + hwkm_pack(dst[1], src->km_by_tz_allowed, HWKM_KEY_POL_KM_BY_TZ); + hwkm_pack(dst[1], src->km_by_nsec_allowed, HWKM_KEY_POL_KM_BY_NSEC); + hwkm_pack(dst[1], src->km_by_modem_allowed, HWKM_KEY_POL_KM_BY_MODEM); + hwkm_pack(dst[1], src->km_by_spu_allowed, HWKM_KEY_POL_KM_BY_SPU); +} + +static void hwkm_unpack_key_policy(struct hwkm_key_policy *dst, + const uint32_t src[HWKM_KEY_POLICY_WORDS]) +{ + memset(dst, 0, sizeof(*dst)); + /* Word 0: */ + hwkm_unpack(dst->wrap_with_tpkey_allowed, src[0], + HWKM_KEY_POL_WRAP_WITH_TPKEY); + hwkm_unpack(dst->hw_destination, src[0], HWKM_KEY_POL_HW_DEST_MASK); + hwkm_unpack(dst->security_lvl, src[0], HWKM_KEY_POL_SEC_LVL_MASK); + hwkm_unpack(dst->swap_export_allowed, src[0], HWKM_KEY_POL_SWAP_EXPORT); + hwkm_unpack(dst->wrap_export_allowed, src[0], HWKM_KEY_POL_WRAP_EXPORT); + hwkm_unpack(dst->key_type, src[0], HWKM_KEY_POL_KEY_TYPE_MASK); + hwkm_unpack(dst->kdf_depth, src[0], HWKM_KEY_POL_KDF_DEPTH_MASK); + hwkm_unpack(dst->dec_allowed, src[0], HWKM_KEY_POL_DECRYPT); + hwkm_unpack(dst->enc_allowed, src[0], HWKM_KEY_POL_ENCRYPT); + hwkm_unpack(dst->alg_allowed, src[0], HWKM_KEY_POL_ALG_MASK); + /* Word 1: */ + hwkm_unpack(dst->km_by_tz_allowed, src[1], HWKM_KEY_POL_KM_BY_TZ); + hwkm_unpack(dst->km_by_nsec_allowed, src[1], HWKM_KEY_POL_KM_BY_NSEC); + hwkm_unpack(dst->km_by_modem_allowed, src[1], HWKM_KEY_POL_KM_BY_MODEM); + hwkm_unpack(dst->km_by_spu_allowed, src[1], HWKM_KEY_POL_KM_BY_SPU); +} + +/* Leaves @dst zeroed (BSVE disabled) if @src->enabled is false. */ +static void hwkm_pack_wrap_bsve(uint32_t dst[HWKM_BSVE_WORDS], + const struct hwkm_bsve *src) +{ + memset(dst, 0, HWKM_BSVE_WORDS * sizeof(uint32_t)); + + if (!src->enabled) + return; + + hwkm_pack(dst[0], src->km_key_policy_ver_en, + HWKM_WRAP_BSVE_KEY_POL_VER); + hwkm_pack(dst[0], src->km_apps_secure_en, HWKM_WRAP_BSVE_APPS_SEC); + hwkm_pack(dst[0], src->km_msa_secure_en, HWKM_WRAP_BSVE_MSA_SEC); + hwkm_pack(dst[0], src->km_lcm_fuse_en, HWKM_WRAP_BSVE_LCM_FUSE_ROW); + hwkm_pack(dst[0], src->km_boot_stage_otp_en, + HWKM_WRAP_BSVE_BOOT_STAGE_OTP); +} + +/* Leaves @dst zeroed (BSVE disabled) if @src->enabled is false. */ +static void hwkm_pack_kdf_bsve(uint32_t dst[HWKM_BSVE_WORDS], + const struct hwkm_bsve *src, uint8_t mks) +{ + uint64_t digest = 0; + + memset(dst, 0, HWKM_BSVE_WORDS * sizeof(uint32_t)); + + if (!src->enabled) + return; + + digest = src->km_fuse_region_sha_digest_en; + /* Word 0: */ + hwkm_pack(dst[0], mks, HWKM_KDF_BSVE_MKS); + hwkm_pack(dst[0], src->km_key_policy_ver_en, HWKM_KDF_BSVE_KEY_POL_VER); + hwkm_pack(dst[0], src->km_apps_secure_en, HWKM_KDF_BSVE_APPS_SEC); + hwkm_pack(dst[0], src->km_msa_secure_en, HWKM_KDF_BSVE_MSA_SEC); + hwkm_pack(dst[0], src->km_lcm_fuse_en, HWKM_KDF_BSVE_LCM_FUSE_ROW); + hwkm_pack(dst[0], src->km_boot_stage_otp_en, + HWKM_KDF_BSVE_BOOT_STAGE_OTP); + hwkm_pack(dst[0], src->km_swc_en, HWKM_KDF_BSVE_SWC); + /* Digest bits [17:0] -> word 0 [31:14]. */ + dst[0] |= (uint32_t)(digest & GENMASK_64(17, 0)) << 14; + /* Word 1: */ + /* Digest bits [49:18] -> word 1 [31:0]. */ + dst[1] = (uint32_t)((digest >> 18) & GENMASK_64(31, 0)); + /* Word 2: */ + /* Digest bits [63:50] -> word 2 [13:0]. */ + dst[2] |= (uint32_t)((digest >> 50) & GENMASK_64(13, 0)); + hwkm_pack(dst[2], src->km_child_key_policy_en, + HWKM_KDF_BSVE_CHILD_KEY_POL); + hwkm_pack(dst[2], src->km_mks_en, HWKM_KDF_BSVE_MKS_EN); +} + +/* + * hwkm_reverse_bytes() - Reverse @len bytes of @buf in-place. + * + * The HWKM hardware stores and returns key material in the opposite byte order + * to the canonical software representation. Apply this function before writing + * a key into a command packet and after reading a key from a response packet. + */ +static void hwkm_reverse_bytes(uint8_t *buf, size_t len) +{ + size_t left = 0; + size_t right = len - 1; + + assert(len > 0); + + while (left < right) { + uint8_t tmp = buf[left]; + + buf[left++] = buf[right]; + buf[right--] = tmp; + } +} + +/* + * hwkm_reorder_kdf_ctx() - Reverse the context bytes in 8-byte chunks. + * + * To satisfy NIST SP800-108 KAT compliance the hardware expects the software + * context to have its byte order swapped on each 8-byte (64-bit) boundary + * before being written to the command packet. + * + * Example: 00 01 02 03 04 05 06 07 -> 07 06 05 04 03 02 01 00 + */ +static void hwkm_reorder_kdf_ctx(uint8_t *buf, size_t len) +{ + size_t i = 0; + + for (i = 0; i < len; i += sizeof(uint64_t)) + hwkm_reverse_bytes(buf + i, MIN(sizeof(uint64_t), len - i)); +} + +/* RUN TRANSACTION. */ + +#define HWKM_MASTER_MAX_RETRIES 100000U + +static int hwkm_fifo_wait(vaddr_t base, uint32_t reg, uint32_t mask) +{ + uint32_t retries = 0; + + while (!io_read32_off_field(base, reg, mask)) { + if (++retries > HWKM_MASTER_MAX_RETRIES) + return HWKM_ERR_FIFO_TIMEOUT; + udelay(10); + } + + return HWKM_SUCCESS; +} + +/* + * master_run_transaction() - Submit one command packet to the master HWKM. + * @cmd: Command packet words to write into the command FIFO. + * @cmd_words: Number of 32-bit words in @cmd. + * @rsp: Response buffer filled from the response FIFO. + * @rsp_words: Number of 32-bit words expected in @rsp. + * + * Return: HWKM_SUCCESS on success, or a HWKM_ERR_* code on failure. + */ +static int master_run_transaction(const uint32_t *cmd, size_t cmd_words, + uint32_t *rsp, size_t rsp_words) +{ + struct hwkm_drv_ctx *ctx = NULL; + int rc = HWKM_ERR_GENERIC; + vaddr_t base = 0; + size_t i = 0; + + if (!cmd || !cmd_words || !rsp || !rsp_words) + return HWKM_ERR_INVALID_ARG; + + ctx = hwkm_get_context(); + if (!ctx) + return HWKM_ERR_INVALID_ARG; + + base = ctx->base; + + /* Flush any stale command FIFO contents. */ + io_write32_off_field(base, HWKM_BANK0_KM_CTL, + HWKM_BANK0_KM_CTL_CMD_FIFO_CLEAR, 1); + io_write32_off_field(base, HWKM_BANK0_KM_CTL, + HWKM_BANK0_KM_CTL_CMD_FIFO_CLEAR, 0); + + /* Clear stale error state from the previous transaction. */ + io_write32_off(base, HWKM_BANK0_KM_ESR, + io_read32_off(base, HWKM_BANK0_KM_ESR)); + + /* Enable command processing. */ + io_write32_off_field(base, HWKM_BANK0_KM_CTL, + HWKM_BANK0_KM_CTL_CMD_ENABLE, 1); + + /* Confirm the FIFO clear bit has deasserted. */ + if (io_read32_off_field(base, HWKM_BANK0_KM_CTL, + HWKM_BANK0_KM_CTL_CMD_FIFO_CLEAR)) + return HWKM_ERR_FIFO_NOT_EMPTY; + + /* Push the command packet one word at a time. */ + for (i = 0; i < cmd_words; i++) { + rc = hwkm_fifo_wait(base, HWKM_BANK0_KM_STATUS, + HWKM_BANK0_KM_STATUS_CMD_AVAIL_SPACE); + if (rc) + return rc; + + io_write32_off(base, HWKM_BANK0_KM_CMD_FIFO, cmd[i]); + } + + /* Pull the response packet one word at a time. */ + for (i = 0; i < rsp_words; i++) { + rc = hwkm_fifo_wait(base, HWKM_BANK0_KM_STATUS, + HWKM_BANK0_KM_STATUS_RSP_AVAIL_DATA); + if (rc) + return rc; + + rsp[i] = io_read32_off(base, HWKM_BANK0_KM_RSP_FIFO); + } + + /* The hardware must report completion after the response is read. */ + if (!io_read32_off_field(base, HWKM_BANK0_KM_IRQ_STATUS, + HWKM_BANK0_KM_IRQ_STATUS_CMD_DONE)) + return HWKM_ERR_RSP_OVERFLOW; + + /* Acknowledge completion. */ + io_write32_off(base, HWKM_BANK0_KM_IRQ_STATUS, + HWKM_BANK0_KM_IRQ_STATUS_CMD_DONE); + + return HWKM_SUCCESS; +} + +static int run_transaction(const struct hwkm_transaction *t, + const uint32_t *cmd, size_t cmd_words, + uint32_t *rsp, size_t rsp_words) +{ + switch (t->hdl->dest) { + case HWKM_KEY_DEST_KM_MASTER: + return master_run_transaction(cmd, cmd_words, rsp, rsp_words); + default: + return HWKM_ERR_INVALID_DEST; + } +} + +/* Command handlers. */ + +static int hwkm_nist_keygen_handle(struct hwkm_transaction *t) +{ + uint32_t cmd[HWKM_OP_NIST_KEYGEN_CMD_WORDS] = { }; + uint32_t rsp[HWKM_OP_NIST_KEYGEN_RSP_WORDS] = { }; + int rc = HWKM_ERR_GENERIC; + + if (!t || !t->hdl) + return HWKM_ERR_INVALID_ARG; + + /* CMD[0]: */ + hwkm_pack_op_info(&cmd[0], HWKM_OP_NIST_KEYGEN, t->cmd.keygen.dks, + 0, false, 0, ARRAY_SIZE(cmd)); + /* CMD[1:2]: */ + hwkm_pack_key_policy(&cmd[HWKM_OPERATION_INFO_WORDS], + &t->cmd.keygen.policy); + + rc = run_transaction(t, cmd, ARRAY_SIZE(cmd), rsp, ARRAY_SIZE(rsp)); + /* On success, RSP[1]: */ + if (rc == HWKM_SUCCESS) + t->rsp.status = rsp[HWKM_OP_NIST_KEYGEN_RSP_ERR_IDX]; + + memzero_explicit(cmd, sizeof(cmd)); + memzero_explicit(rsp, sizeof(rsp)); + + return rc; +} + +static int hwkm_system_kdf_handle(struct hwkm_transaction *t) +{ + uint32_t cmd[HWKM_OP_SYSTEM_KDF_CMD_WORDS + + HWKM_BSVE_WORDS + HWKM_SOFTWARE_CONTEXT_WORDS] = { }; + uint32_t rsp[HWKM_OP_SYSTEM_KDF_RSP_WORDS] = { }; + int rc = HWKM_ERR_GENERIC; + size_t ctx_words = 0; + size_t cmd_words = 0; + size_t ctx_idx = 0; + + if (!t || !t->hdl) + return HWKM_ERR_INVALID_ARG; + + if (t->cmd.kdf.ctx_len > sizeof(t->cmd.kdf.ctx)) + return HWKM_ERR_INVALID_ARG; + + ctx_words = ROUNDUP_DIV(t->cmd.kdf.ctx_len, sizeof(uint32_t)); + ctx_idx = HWKM_OPERATION_INFO_WORDS + HWKM_KEY_POLICY_WORDS + + (t->cmd.kdf.bsve.enabled ? HWKM_BSVE_WORDS : 1); + + /* Total command length. */ + cmd_words = ctx_idx + ctx_words + 1 /* CRC */; + if (cmd_words > ARRAY_SIZE(cmd)) + return HWKM_ERR_INVALID_ARG; + + /* CMD[0]: */ + hwkm_pack_op_info(&cmd[0], HWKM_OP_SYSTEM_KDF, t->cmd.kdf.dks, + t->cmd.kdf.kdk, t->cmd.kdf.bsve.enabled, ctx_words, + /* incl. CRC, excl. context. */ + ctx_idx + 1); + /* CMD[1:2]: */ + hwkm_pack_key_policy(&cmd[HWKM_OPERATION_INFO_WORDS], + &t->cmd.kdf.policy); + + if (t->cmd.kdf.bsve.enabled) { + /* CMD[3:5]: */ + hwkm_pack_kdf_bsve(&cmd[HWKM_OPERATION_INFO_WORDS + + HWKM_KEY_POLICY_WORDS], + &t->cmd.kdf.bsve, t->cmd.kdf.mks); + } + + if (t->cmd.kdf.ctx_len) { + /* CMD[n:], if software context exists: */ + memcpy(&cmd[ctx_idx], t->cmd.kdf.ctx, t->cmd.kdf.ctx_len); + hwkm_reorder_kdf_ctx((uint8_t *)&cmd[ctx_idx], + t->cmd.kdf.ctx_len); + } + + rc = run_transaction(t, cmd, cmd_words, rsp, ARRAY_SIZE(rsp)); + /* On success, RSP[1]: */ + if (rc == HWKM_SUCCESS) + t->rsp.status = rsp[HWKM_OP_SYSTEM_KDF_RSP_ERR_IDX]; + + memzero_explicit(cmd, sizeof(cmd)); + memzero_explicit(rsp, sizeof(rsp)); + + return rc; +} + +static int hwkm_key_wrap_export_handle(struct hwkm_transaction *t) +{ + uint32_t cmd[HWKM_OP_KEY_WRAP_EXPORT_CMD_WORDS] = { }; + uint32_t rsp[HWKM_OP_KEY_WRAP_EXPORT_RSP_WORDS] = { }; + int rc = HWKM_ERR_GENERIC; + + if (!t || !t->hdl) + return HWKM_ERR_INVALID_ARG; + + /* CMD[0]: */ + hwkm_pack_op_info(&cmd[0], HWKM_OP_KEY_WRAP_EXPORT, t->cmd.wrap.sks, + t->cmd.wrap.kwk, false, 0, ARRAY_SIZE(cmd)); + /* CMD[1:3]: */ + hwkm_pack_wrap_bsve(&cmd[HWKM_OPERATION_INFO_WORDS], + &t->cmd.wrap.bsve); + + rc = run_transaction(t, cmd, ARRAY_SIZE(cmd), rsp, ARRAY_SIZE(rsp)); + /* On success, RSP[1]: */ + if (rc == HWKM_SUCCESS) { + t->rsp.status = rsp[HWKM_OP_KEY_WRAP_EXPORT_RSP_ERR_IDX]; + /* On operation success, RSP[2:18]: */ + if (!t->rsp.status) { + memcpy(t->rsp.wrap.wkb, + &rsp[HWKM_OP_KEY_WRAP_EXPORT_RSP_BLOB_IDX], + HWKM_MAX_BLOB_SIZE); + } + } + + memzero_explicit(cmd, sizeof(cmd)); + memzero_explicit(rsp, sizeof(rsp)); + + return rc; +} + +static int hwkm_key_unwrap_import_handle(struct hwkm_transaction *t) +{ + uint32_t cmd[HWKM_OP_KEY_UNWRAP_IMPORT_CMD_WORDS] = { }; + uint32_t rsp[HWKM_OP_KEY_UNWRAP_IMPORT_RSP_WORDS] = { }; + int rc = HWKM_ERR_GENERIC; + + if (!t || !t->hdl) + return HWKM_ERR_INVALID_ARG; + + /* CMD[0]: */ + hwkm_pack_op_info(&cmd[0], HWKM_OP_KEY_UNWRAP_IMPORT, + t->cmd.unwrap.dks, t->cmd.unwrap.kwk, false, 0, + ARRAY_SIZE(cmd)); + /* CMD[1:17]: */ + memcpy(&cmd[HWKM_OPERATION_INFO_WORDS], t->cmd.unwrap.wkb, + HWKM_MAX_BLOB_SIZE); + + rc = run_transaction(t, cmd, ARRAY_SIZE(cmd), rsp, ARRAY_SIZE(rsp)); + /* On success, RSP[1]: */ + if (rc == HWKM_SUCCESS) + t->rsp.status = rsp[HWKM_OP_KEY_UNWRAP_IMPORT_RSP_ERR_IDX]; + + memzero_explicit(cmd, sizeof(cmd)); + memzero_explicit(rsp, sizeof(rsp)); + + return rc; +} + +static int hwkm_key_slot_clear_handle(struct hwkm_transaction *t) +{ + uint32_t cmd[HWKM_OP_KEY_SLOT_CLEAR_CMD_WORDS] = { }; + uint32_t rsp[HWKM_OP_KEY_SLOT_CLEAR_RSP_WORDS] = { }; + int rc = HWKM_ERR_GENERIC; + + if (!t || !t->hdl) + return HWKM_ERR_INVALID_ARG; + + /* CMD[0]: */ + hwkm_pack_op_info(&cmd[0], HWKM_OP_KEY_SLOT_CLEAR, t->cmd.clear.dks, + 0, t->cmd.clear.is_double_key, 0, ARRAY_SIZE(cmd)); + + rc = run_transaction(t, cmd, ARRAY_SIZE(cmd), rsp, ARRAY_SIZE(rsp)); + /* On success, RSP[1]: */ + if (rc == HWKM_SUCCESS) + t->rsp.status = rsp[HWKM_OP_KEY_SLOT_CLEAR_RSP_ERR_IDX]; + + memzero_explicit(cmd, sizeof(cmd)); + memzero_explicit(rsp, sizeof(rsp)); + + return rc; +} + +static int hwkm_key_slot_rdwr_handle(struct hwkm_transaction *t) +{ + uint32_t cmd[HWKM_OP_KEY_SLOT_RDWR_CMD_WORDS] = { }; + uint32_t rsp[HWKM_OP_KEY_SLOT_RDWR_RSP_WORDS] = { }; + int rc = HWKM_ERR_GENERIC; + + if (!t || !t->hdl) + return HWKM_ERR_INVALID_ARG; + + /* CMD[0]: */ + hwkm_pack_op_info(&cmd[0], HWKM_OP_KEY_SLOT_RDWR, t->cmd.rdwr.slot, + 0, t->cmd.rdwr.is_write, 0, ARRAY_SIZE(cmd)); + + if (t->cmd.rdwr.is_write) { + /* CMD[1:2]: */ + hwkm_pack_key_policy(&cmd[HWKM_OPERATION_INFO_WORDS], + &t->cmd.rdwr.policy); + /* CMD[3:10]: */ + memcpy(&cmd[HWKM_OPERATION_INFO_WORDS + HWKM_KEY_POLICY_WORDS], + t->cmd.rdwr.key, HWKM_MAX_KEY_SIZE); + hwkm_reverse_bytes((uint8_t *)&cmd[HWKM_OPERATION_INFO_WORDS + + HWKM_KEY_POLICY_WORDS], + HWKM_MAX_KEY_SIZE); + } + + rc = run_transaction(t, cmd, ARRAY_SIZE(cmd), rsp, ARRAY_SIZE(rsp)); + /* On success, RSP[1]: */ + if (rc == HWKM_SUCCESS) { + t->rsp.status = rsp[HWKM_OP_KEY_SLOT_RDWR_RSP_ERR_IDX]; + if (!t->cmd.rdwr.is_write && !t->rsp.status) { + uint32_t *rsp_policy = + &rsp[HWKM_OP_KEY_SLOT_RDWR_RSP_POLICY_IDX]; + + /* RSP[2:3]: */ + hwkm_unpack_key_policy(&t->rsp.rdwr.policy, rsp_policy); + /* RSP[4:11]: */ + memcpy(t->rsp.rdwr.key, + &rsp[HWKM_OP_KEY_SLOT_RDWR_RSP_READ_KEY_IDX], + HWKM_MAX_KEY_SIZE); + hwkm_reverse_bytes(t->rsp.rdwr.key, HWKM_MAX_KEY_SIZE); + } + } + + memzero_explicit(cmd, sizeof(cmd)); + memzero_explicit(rsp, sizeof(rsp)); + + return rc; +} + +static int hwkm_set_tpkey_handle(struct hwkm_transaction *t) +{ + uint32_t cmd[HWKM_OP_SET_TPKEY_CMD_WORDS] = { }; + uint32_t rsp[HWKM_OP_SET_TPKEY_RSP_WORDS] = { }; + int rc = HWKM_ERR_GENERIC; + + if (!t || !t->hdl) + return HWKM_ERR_INVALID_ARG; + + if (t->hdl->dest != HWKM_KEY_DEST_KM_MASTER) + return HWKM_ERR_INVALID_DEST; + + /* CMD[0]: */ + hwkm_pack_op_info(&cmd[0], HWKM_OP_SET_TPKEY, t->cmd.set_tpkey.sks, + 0, false, 0, ARRAY_SIZE(cmd)); + + rc = run_transaction(t, cmd, ARRAY_SIZE(cmd), rsp, ARRAY_SIZE(rsp)); + /* On success, RSP[1]: */ + if (rc == HWKM_SUCCESS) + t->rsp.status = rsp[HWKM_OP_SET_TPKEY_RSP_ERR_IDX]; + + memzero_explicit(cmd, sizeof(cmd)); + memzero_explicit(rsp, sizeof(rsp)); + + return rc; +} + +static int hwkm_transaction_dispatch(struct hwkm_transaction *t) +{ + switch (t->cmd.op) { + case HWKM_OP_NIST_KEYGEN: + return hwkm_nist_keygen_handle(t); + case HWKM_OP_SYSTEM_KDF: + return hwkm_system_kdf_handle(t); + case HWKM_OP_KEY_WRAP_EXPORT: + return hwkm_key_wrap_export_handle(t); + case HWKM_OP_KEY_UNWRAP_IMPORT: + return hwkm_key_unwrap_import_handle(t); + case HWKM_OP_KEY_SLOT_CLEAR: + return hwkm_key_slot_clear_handle(t); + case HWKM_OP_KEY_SLOT_RDWR: + return hwkm_key_slot_rdwr_handle(t); + case HWKM_OP_SET_TPKEY: + return hwkm_set_tpkey_handle(t); + default: + return HWKM_ERR_NOT_SUPPORTED; + } +} + +/* Command queue. */ + +int hwkm_handle_init(struct hwkm_handle *hdl, enum hwkm_key_destination dest) +{ + switch (dest) { + case HWKM_KEY_DEST_KM_MASTER: + break; + default: + return HWKM_ERR_INVALID_DEST; + } + + hdl->dest = dest; + STAILQ_INIT(&hdl->queue); + + return HWKM_SUCCESS; +} + +int hwkm_enqueue(struct hwkm_handle *hdl, struct hwkm_transaction *t) +{ + if (!t) + return HWKM_ERR_INVALID_ARG; + + if (t->hdl) + return HWKM_ERR_INVALID_ARG; + + t->hdl = hdl; + STAILQ_INSERT_TAIL(&hdl->queue, t, link); + + return HWKM_SUCCESS; +} + +/* + * hwkm_enqueue_many() - Enqueue multiple transactions on one handle. + * @hdl: Handle that owns the queue. + * @num_t: Number of transactions in @trans. + * @trans: Array of transaction pointers to enqueue in FIFO order. + * + * Enqueues all transactions in @trans onto @hdl using hwkm_enqueue(). + * If enqueueing any transaction fails, all transactions already queued by + * this call are removed again and their ownership is cleared, so the caller + * sees all-or-nothing behavior. + * + * Return: HWKM_SUCCESS on success, or a HWKM_ERR_* code on failure. + */ +int hwkm_enqueue_many(struct hwkm_handle *hdl, size_t num_t, + struct hwkm_transaction *const trans[]) +{ + int rc = HWKM_ERR_GENERIC; + size_t i = 0; + + if (!hdl || (num_t && !trans)) + return HWKM_ERR_INVALID_ARG; + + for (i = 0; i < num_t; i++) { + rc = hwkm_enqueue(hdl, trans[i]); + if (rc) + goto rollback; + } + + return HWKM_SUCCESS; + +rollback: + while (i > 0) { + struct hwkm_transaction *t = trans[--i]; + + /* Release the ownership. */ + STAILQ_REMOVE(&hdl->queue, t, hwkm_transaction, link); + t->hdl = NULL; + } + + return rc; +} + +/* + * hwkm_run_cmd_queue() - Execute queued transactions. + * @hdl: Handle containing queued transactions + * + * Executes all transactions queued on @hdl in FIFO order by calling + * hwkm_transaction_dispatch() for each transaction. Execution stops at the + * first error and that error is returned to the caller. + * + * On return, transactions that were processed are removed from the queue and + * their ownership is cleared (to be reused). + * + * Return: HWKM_SUCCESS on success, or a HWKM_ERR_* code on failure. + */ +int hwkm_run_cmd_queue(struct hwkm_handle *hdl) +{ + struct hwkm_transaction *t = NULL; + int rc = HWKM_SUCCESS; + + while (!STAILQ_EMPTY(&hdl->queue)) { + t = STAILQ_FIRST(&hdl->queue); + rc = hwkm_transaction_dispatch(t); + /* Release the ownership. */ + STAILQ_REMOVE_HEAD(&hdl->queue, link); + t->hdl = NULL; + + if (rc != HWKM_SUCCESS) + break; + } + + return rc; +} diff --git a/core/drivers/crypto/qcom/include/hwkm.h b/core/drivers/crypto/qcom/include/hwkm.h new file mode 100644 index 000000000..ff4c84be1 --- /dev/null +++ b/core/drivers/crypto/qcom/include/hwkm.h @@ -0,0 +1,377 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. + */ + +#ifndef __HWKM_H__ +#define __HWKM_H__ + +#include +#include +#include +#include + +#define HWKM_MAX_KEY_SIZE 32 /* bytes */ +#define HWKM_MAX_CTX_SIZE 64 /* bytes */ +#define HWKM_MAX_BLOB_SIZE 68 /* bytes */ + +enum hwkm_key_destination { + HWKM_KEY_DEST_KM_MASTER = 0, +}; + +enum hwkm_key_security_lvl { + HWKM_KEY_SECURITY_LVL_SW_KEY = 0, + HWKM_KEY_SECURITY_LVL_MANAGED_KEY, + HWKM_KEY_SECURITY_LVL_HW_KEY, +}; + +enum hwkm_key_type { + HWKM_KEY_TYPE_KDK = 0, /* Key derivation key. */ + HWKM_KEY_TYPE_KWK, /* Key wrapping key. */ + HWKM_KEY_TYPE_KSK, /* Key swap key. */ + HWKM_KEY_TYPE_TPKEY, /* Transport protection key. */ + HWKM_KEY_TYPE_GENERIC_KEY, +}; + +/* Master key slot assignments. */ +enum hwkm_master_key_slots { + /* L1 KDKs - HW-only: */ + HWKM_SLOT_NKDK_L1 = 0, + HWKM_SLOT_PKDK_L1 = 1, + HWKM_SLOT_SKDK_L1 = 2, + HWKM_SLOT_UKDK_L1 = 3, + /* L2 KDKs. */ + HWKM_SLOT_TZ_NKDK_L2 = 4, + HWKM_SLOT_TZ_PKDK_L2 = 5, + HWKM_SLOT_TZ_SKDK_L2 = 6, + HWKM_SLOT_MODEM_PKDK_L2 = 7, + HWKM_SLOT_MODEM_SKDK_L2 = 8, + HWKM_SLOT_TZ_UKDK_L2 = 9, + /* TPKEY pair. */ + HWKM_SLOT_TPKEY_SLOT = 10, + HWKM_SLOT_TPKEY_ODD_SLOT = 11, + /* Swap key pair. */ + HWKM_SLOT_TZ_SWAP_KEY_SLOT = 12, + HWKM_SLOT_TZ_SWAP_KEY_ODD_SLOT = 13, + /* Wrap key pair. */ + HWKM_SLOT_TZ_WRAP_KEY_SLOT = 14, + HWKM_SLOT_TZ_WRAP_KEY_ODD_SLOT = 15, + /* General purpose scratch. */ + HWKM_SLOT_TZ_GENERAL_PURPOSE_SLOT1 = 16, + HWKM_SLOT_TZ_GENERAL_PURPOSE_SLOT2 = 17, + /* Persistent shared pairs. */ + HWKM_SLOT_PERSISTENT_SHARED_SLOT_PAIR1 = 18, + HWKM_SLOT_PERSISTENT_SHARED_SLOT_PAIR1_ODD = 19, + HWKM_SLOT_PERSISTENT_SHARED_SLOT_PAIR2 = 20, + HWKM_SLOT_PERSISTENT_SHARED_SLOT_PAIR2_ODD = 21, + /* Mixing key. */ + HWKM_SLOT_TZ_MIXING_KEY_SLOT = 22, +}; + +enum hwkm_algo { + HWKM_ALGO_AES128_ECB = 0, + HWKM_ALGO_AES256_ECB = 1, + HWKM_ALGO_AES128_CBC = 4, + HWKM_ALGO_AES256_CBC = 5, + HWKM_ALGO_AES256_SIV = 12, + HWKM_ALGO_AES128_CTR = 13, + HWKM_ALGO_AES256_CTR = 14, + HWKM_ALGO_AES128_XTS = 15, + HWKM_ALGO_AES256_XTS = 16, + HWKM_ALGO_AES128_CMAC = 19, + HWKM_ALGO_AES256_CMAC = 20, +}; + +struct hwkm_key_policy { + /* TZ may issue commands against this slot. */ + bool km_by_tz_allowed; + /* Non-secure world may use this slot. */ + bool km_by_nsec_allowed; + /* Modem may use this slot. */ + bool km_by_modem_allowed; + /* SPU may use this slot. */ + bool km_by_spu_allowed; + /* Only algorithm permitted for this key. */ + enum hwkm_algo alg_allowed; + /* Key may be used for encryption. */ + bool enc_allowed; + /* Key may be used for decryption. */ + bool dec_allowed; + /* Functional role. */ + enum hwkm_key_type key_type; + /* Remaining KDF derivation hops. */ + uint8_t kdf_depth; + /* Key may be exported via KEY_WRAP_EXPORT. */ + bool wrap_export_allowed; + /* Key may be delivered via key-swap. */ + bool swap_export_allowed; + /* SW_KEY, MANAGED_KEY, or HW_KEY. */ + enum hwkm_key_security_lvl security_lvl; + /* Hardware destination. */ + enum hwkm_key_destination hw_destination; + /* Allow wrapping under TPKEY. */ + bool wrap_with_tpkey_allowed; +}; + +struct hwkm_bsve { + /* Master enable for all BSVE checks. */ + bool enabled; + /* Enforce key policy version field. */ + bool km_key_policy_ver_en; + /* Require apps processor to be in secure state. */ + bool km_apps_secure_en; + /* Require modem to be in secure state. */ + bool km_msa_secure_en; + /* Bind derivation to life-cycle fuse state. */ + bool km_lcm_fuse_en; + /* Bind derivation to boot-stage OTP value. */ + bool km_boot_stage_otp_en; + /* Enforce software component version check. */ + bool km_swc_en; + /* Child key policy must be subset of parent. */ + bool km_child_key_policy_en; + /* Include the mixing-key slot value in the KDF. */ + bool km_mks_en; + /* Fuse regions hashed into KDF. */ + uint64_t km_fuse_region_sha_digest_en; +}; + +/* Command and response structs. */ + +enum hwkm_op { + /* Generate a key via HW PRNG. */ + HWKM_OP_NIST_KEYGEN = 0, + /* Derive a child key from a KDK slot. */ + HWKM_OP_SYSTEM_KDF = 1, + /* Opcode 2 is reserved. */ + /* Wrap a slot under a KWK/KSK. */ + HWKM_OP_KEY_WRAP_EXPORT = 3, + /* Unwrap a blob into a destination slot. */ + HWKM_OP_KEY_UNWRAP_IMPORT = 4, + /* Clear a slot and invalidate its policy. */ + HWKM_OP_KEY_SLOT_CLEAR = 5, + /* Read or write raw key material. */ + HWKM_OP_KEY_SLOT_RDWR = 6, + /* Install a slot as the active TPKEY. */ + HWKM_OP_SET_TPKEY = 7, +}; + +struct hwkm_keygen_cmd { + uint8_t dks; /* Destination key slot. */ + struct hwkm_key_policy policy; +}; + +struct hwkm_rdwr_cmd { + uint8_t slot; + bool is_write; + struct hwkm_key_policy policy; + uint8_t key[HWKM_MAX_KEY_SIZE]; +}; + +struct hwkm_kdf_cmd { + uint8_t dks; /* Destination key slot. */ + uint8_t kdk; /* Parent KDK slot. */ + uint8_t mks; /* Mixing-key slot selector. */ + struct hwkm_key_policy policy; + struct hwkm_bsve bsve; + uint8_t ctx[HWKM_MAX_CTX_SIZE]; + size_t ctx_len; +}; + +struct hwkm_set_tpkey_cmd { + uint8_t sks; /* Source key slot. */ +}; + +struct hwkm_unwrap_cmd { + uint8_t dks; /* Destination key slot. */ + uint8_t kwk; /* Wrapping key slot. */ + uint8_t wkb[HWKM_MAX_BLOB_SIZE]; +}; + +struct hwkm_wrap_cmd { + uint8_t sks; /* Source key slot. */ + uint8_t kwk; /* Wrapping key slot. */ + struct hwkm_bsve bsve; +}; + +struct hwkm_clear_cmd { + uint8_t dks; /* Destination key slot. */ + bool is_double_key; +}; + +struct hwkm_cmd { + enum hwkm_op op; + union { + struct hwkm_keygen_cmd keygen; + struct hwkm_rdwr_cmd rdwr; + struct hwkm_kdf_cmd kdf; + struct hwkm_set_tpkey_cmd set_tpkey; + struct hwkm_unwrap_cmd unwrap; + struct hwkm_wrap_cmd wrap; + struct hwkm_clear_cmd clear; + }; +}; + +struct hwkm_rdwr_rsp { + struct hwkm_key_policy policy; + uint8_t key[HWKM_MAX_KEY_SIZE]; +}; + +struct hwkm_wrap_rsp { + uint8_t wkb[HWKM_MAX_BLOB_SIZE]; +}; + +struct hwkm_rsp { + uint32_t status; + union { + struct hwkm_rdwr_rsp rdwr; + struct hwkm_wrap_rsp wrap; + }; +}; + +/* PUBLIC API. */ + +#define HWKM_SUCCESS 0 +#define HWKM_ERR_GENERIC 1 +#define HWKM_ERR_INVALID_ARG 2 +#define HWKM_ERR_INVALID_DEST 3 +#define HWKM_ERR_FIFO_NOT_EMPTY 4 +#define HWKM_ERR_FIFO_TIMEOUT 5 +#define HWKM_ERR_RSP_OVERFLOW 6 +#define HWKM_ERR_NOT_SUPPORTED 7 + +static inline TEE_Result hwkm_to_optee(int rc) +{ + switch (rc) { + case HWKM_SUCCESS: + return TEE_SUCCESS; + case HWKM_ERR_INVALID_ARG: + case HWKM_ERR_INVALID_DEST: + return TEE_ERROR_BAD_PARAMETERS; + case HWKM_ERR_NOT_SUPPORTED: + return TEE_ERROR_NOT_SUPPORTED; + default: + return TEE_ERROR_GENERIC; + } +} + +struct hwkm_handle; + +struct hwkm_drv_ctx { + vaddr_t base; + struct mutex hwkm_lock; /* Serializes all HWKM operations. */ + bool hwkm_huk_ready; + uint8_t hwkm_huk[HWKM_MAX_KEY_SIZE]; + bool initialized; +}; + +struct hwkm_drv_ctx *hwkm_get_context(void); + +/* + * struct hwkm_transaction - queued HWKM command and response. + * @cmd: Command to submit. + * @rsp: Response filled by the driver. + * @hdl: Owning handle when the transaction is queued. + * @link: Queue link. + * + * A transaction contains one HWKM command and its corresponding response. + * Transactions are queued on a handle and executed in FIFO order by + * hwkm_run_cmd_queue(). + */ +struct hwkm_transaction { + struct hwkm_cmd cmd; + struct hwkm_rsp rsp; + struct hwkm_handle *hdl; + + STAILQ_ENTRY(hwkm_transaction) link; +}; + +STAILQ_HEAD(hwkm_transaction_queue, hwkm_transaction); + +/* + * struct hwkm_handle - HWKM command queue handle. + * @dest: Target hardware engine. + * @queue: Queued transactions. + * + * A handle groups one or more HWKM commands targeting the same destination. + * Initialize it with hwkm_handle_init(), enqueue transactions with + * hwkm_enqueue() / hwkm_enqueue_many(), then execute them with + * hwkm_run_cmd_queue(). + * + * Example: + * + * struct hwkm_transaction t_kdf = { + * .cmd = { + * .op = HWKM_OP_SYSTEM_KDF, + * }, + * }; + * + * struct hwkm_transaction t_clear = { + * .cmd = { + * .op = HWKM_OP_KEY_SLOT_CLEAR, + * }, + * }; + * + * struct hwkm_handle h = { }; + * + * hwkm_handle_init(&h, HWKM_KEY_DEST_KM_MASTER); + * hwkm_enqueue(&h, &t_kdf); + * hwkm_enqueue(&h, &t_clear); + * hwkm_run_cmd_queue(&h); + * + * The responses are returned in t_kdf.rsp and t_clear.rsp. + */ +struct hwkm_handle { + enum hwkm_key_destination dest; + struct hwkm_transaction_queue queue; +}; + +struct hwkm_transaction *hwkm_transaction_alloc(void); +void hwkm_transaction_free(struct hwkm_transaction *t); + +int hwkm_handle_init(struct hwkm_handle *hdl, enum hwkm_key_destination dest); +int hwkm_enqueue(struct hwkm_handle *hdl, struct hwkm_transaction *t); +int hwkm_enqueue_many(struct hwkm_handle *hdl, size_t num_t, + struct hwkm_transaction *const trans[]); +int hwkm_run_cmd_queue(struct hwkm_handle *hdl); + +/* + * hwkm_run_transactions() - Init a handle, enqueue @num_t transactions, and + * execute them in one call. + * @dest: Target hardware engine. + * @num_t: Number of entries in @trans. + * @trans: Array of transaction pointers executed in FIFO order. + * + * Convenience wrapper around hwkm_handle_init() + hwkm_enqueue_many() + + * hwkm_run_cmd_queue(). Use when all transactions target the same destination + * and no handle needs to survive the call. + * + * Return: HWKM_SUCCESS on success, or a HWKM_ERR_* code on failure. + */ +static inline int hwkm_run_transactions(enum hwkm_key_destination dest, + size_t num_t, + struct hwkm_transaction *const trans[]) +{ + struct hwkm_handle hdl = { }; + int rc = HWKM_ERR_GENERIC; + + rc = hwkm_handle_init(&hdl, dest); + if (rc) + return rc; + + rc = hwkm_enqueue_many(&hdl, num_t, trans); + if (rc) + return rc; + + return hwkm_run_cmd_queue(&hdl); +} + +/* Execute a single transaction. */ +static inline int hwkm_run_transaction(enum hwkm_key_destination dest, + struct hwkm_transaction *t) +{ + return hwkm_run_transactions(dest, 1, + (struct hwkm_transaction *const[]){ t }); +} + +#endif /* __HWKM_H__ */ diff --git a/core/drivers/crypto/qcom/include/hwkm_errno.h b/core/drivers/crypto/qcom/include/hwkm_errno.h new file mode 100644 index 000000000..f8f3998a2 --- /dev/null +++ b/core/drivers/crypto/qcom/include/hwkm_errno.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. + * + * Hardware Key Manager (HWKM) response-error bit definitions. + */ + +#ifndef __HWKM_ERRNO_H__ +#define __HWKM_ERRNO_H__ + +#include + +/* Error status bitmap at RSP[*_RSP_ERR_IDX]. */ + +#define HWKM_RSP_ERR_SUCCESS 0U +/* Common errors (bits 0 - 7, present in every opcode response). */ +#define HWKM_ERR_RSP_FIFO_UNDERFLOW BIT(0) +#define HWKM_ERR_CMD_FIFO_OVERFLOW BIT(1) +#define HWKM_ERR_OPCODE_UNSUPPORTED BIT(2) +#define HWKM_ERR_INVALID_OPCODE BIT(3) +#define HWKM_ERR_INCORRECT_CMD_LENGTH BIT(4) +#define HWKM_ERR_CRC_CHECK BIT(5) +#define HWKM_ERR_BBAC_ACCESS BIT(6) + +/* NIST_KEYGEN specific errors (bits 8+). */ +#define HWKM_NIST_KEYGEN_ERR_KEYSLOT_ID_OUT_OF_RANGE BIT(8) +#define HWKM_NIST_KEYGEN_ERR_UNSUPPORTED_KEY_SIZE BIT(9) +#define HWKM_NIST_KEYGEN_ERR_KT_PARITY BIT(10) +#define HWKM_NIST_KEYGEN_ERR_INVALID_KEY_TYPE BIT(11) +#define HWKM_NIST_KEYGEN_ERR_INVALID_ALG_ALLOWED BIT(12) +#define HWKM_NIST_KEYGEN_ERR_INVALID_KEY_ATTRIB BIT(13) +#define HWKM_NIST_KEYGEN_ERR_INVALID_TPKEY_ATTRIB BIT(14) +#define HWKM_NIST_KEYGEN_ERR_INVALID_KSK_ATTRIB BIT(15) +#define HWKM_NIST_KEYGEN_ERR_INVALID_KWK_ATTRIB BIT(16) +#define HWKM_NIST_KEYGEN_ERR_INVALID_KDF_DEPTH BIT(17) +#define HWKM_NIST_KEYGEN_ERR_INVALID_SECURITY_LEVEL BIT(18) +#define HWKM_NIST_KEYGEN_ERR_DKS_SLOT_NOT_EMPTY BIT(19) +#define HWKM_NIST_KEYGEN_ERR_ACCESS_VIOLATION BIT(20) + +/* KEY_SLOT_RDWR specific errors (bits 8+). */ +#define HWKM_KEY_SLOT_RDWR_ERR_KEYSLOT_ID_OUT_OF_RANGE BIT(8) +#define HWKM_KEY_SLOT_RDWR_ERR_UNSUPPORTED_KEY_SIZE BIT(9) +#define HWKM_KEY_SLOT_RDWR_ERR_KT_PARITY BIT(10) +#define HWKM_KEY_SLOT_RDWR_ERR_INVALID_SECURITY_LEVEL BIT(11) +#define HWKM_KEY_SLOT_RDWR_ERR_INVALID_KEY_TYPE BIT(12) +#define HWKM_KEY_SLOT_RDWR_ERR_INVALID_ALG_ALLOWED BIT(13) +#define HWKM_KEY_SLOT_RDWR_ERR_INVALID_KEY_ATTRIB BIT(14) +#define HWKM_KEY_SLOT_RDWR_ERR_INVALID_TPKEY_ATTRIB BIT(15) +#define HWKM_KEY_SLOT_RDWR_ERR_INVALID_KSK_ATTRIB BIT(16) +#define HWKM_KEY_SLOT_RDWR_ERR_INVALID_KWK_ATTRIB BIT(17) +#define HWKM_KEY_SLOT_RDWR_ERR_INVALID_KDF_DEPTH BIT(18) +#define HWKM_KEY_SLOT_RDWR_ERR_SECURITY_LEVEL_VIOLATION BIT(19) +#define HWKM_KEY_SLOT_RDWR_ERR_SKS_SLOT_EMPTY BIT(20) +#define HWKM_KEY_SLOT_RDWR_ERR_DKS_SLOT_NOT_EMPTY BIT(21) +#define HWKM_KEY_SLOT_RDWR_ERR_ACCESS_VIOLATION BIT(22) + +/* SYSTEM_KDF specific errors (bits 8+). */ +#define HWKM_SYSTEM_KDF_ERR_FR_RD_ERR_ON_SLAVE BIT(8) +#define HWKM_SYSTEM_KDF_ERR_MKS_L1L2_NOT_ALLOWED BIT(9) +#define HWKM_SYSTEM_KDF_ERR_SEC_CTRL_ACCESS BIT(10) +#define HWKM_SYSTEM_KDF_ERR_KT_PARITY BIT(11) +#define HWKM_SYSTEM_KDF_ERR_BSVE_BIT_NOT_SUPPORTED BIT(12) +#define HWKM_SYSTEM_KDF_ERR_INVALID_SECURITY_LEVEL BIT(13) +#define HWKM_SYSTEM_KDF_ERR_INVALID_KEY_TYPE BIT(14) +#define HWKM_SYSTEM_KDF_ERR_INVALID_ALG_ALLOWED BIT(15) +#define HWKM_SYSTEM_KDF_ERR_SWAP_EXPORT_NOT_ALLOWED BIT(16) +#define HWKM_SYSTEM_KDF_ERR_KEYPOLICY_CONSISTENCY BIT(17) +#define HWKM_SYSTEM_KDF_ERR_ENCRYPT_NOT_ALLOWED BIT(18) +#define HWKM_SYSTEM_KDF_ERR_UNEXPECTED_ALG_ALLOWED BIT(19) +#define HWKM_SYSTEM_KDF_ERR_UNEXPECTED_KEY_TYPE BIT(20) +#define HWKM_SYSTEM_KDF_ERR_KDF_DEPTH_ERROR BIT(21) +#define HWKM_SYSTEM_KDF_ERR_KDK_TYPE BIT(22) +#define HWKM_SYSTEM_KDF_ERR_KEY_SIZE BIT(23) +#define HWKM_SYSTEM_KDF_ERR_KEYSLOT_SLOT BIT(24) +#define HWKM_SYSTEM_KDF_ERR_KEYSLOT_OUT_OF_RANGE BIT(25) +#define HWKM_SYSTEM_KDF_ERR_DOUBLE_KEY_SLOT_NOT_EVEN BIT(26) +#define HWKM_SYSTEM_KDF_ERR_ACCESS_VIOLATION BIT(27) +#define HWKM_SYSTEM_KDF_ERR_SECURITY_LEVEL_VIOLATION BIT(28) + +/* KEY_WRAP_EXPORT specific errors (bits 8+). */ +#define HWKM_EXPORT_ERR_KWK_DOUBLE_KEY_ODD_SLOT BIT(8) +#define HWKM_EXPORT_ERR_ENCRYPT_NOT_ALLOWED BIT(9) +#define HWKM_EXPORT_ERR_SKS_SIZE_ERROR BIT(10) +#define HWKM_EXPORT_ERR_SKS_SLOT_OUT_OF_RANGE BIT(11) +#define HWKM_EXPORT_ERR_KWK_SIZE_ERROR BIT(12) +#define HWKM_EXPORT_ERR_KWK_SLOT_OUT_OF_RANGE BIT(13) +#define HWKM_EXPORT_ERR_KT_PARITY BIT(14) +#define HWKM_EXPORT_ERR_WRAP_WITH_TPKEY_NOT_ALLOWED BIT(15) +#define HWKM_EXPORT_ERR_SWAP_EXPORT_NOT_ALLOWED BIT(16) +#define HWKM_EXPORT_ERR_WRAP_EXPORT_NOT_ALLOWED BIT(17) +#define HWKM_EXPORT_ERR_UNEXPECTED_ALG_ALLOWED BIT(18) +#define HWKM_EXPORT_ERR_SECURITY_LEVEL_ERROR BIT(19) +#define HWKM_EXPORT_ERR_UNEXPECTED_KEY_TYPE BIT(20) +#define HWKM_EXPORT_ERR_KWK_SLOT_EMPTY BIT(21) +#define HWKM_EXPORT_ERR_SKS_SLOT_EMPTY BIT(22) +#define HWKM_EXPORT_ERR_SKS_ACCESS_VIOLATION BIT(23) +#define HWKM_EXPORT_ERR_KWK_ACCESS_VIOLATION BIT(24) + +/* KEY_UNWRAP_IMPORT specific errors (bits 8+). */ +#define HWKM_IMPORT_ERR_UNWRAP_FAILED BIT(8) +#define HWKM_IMPORT_ERR_KWK_DOUBLE_KEY_ODD_SLOT BIT(9) +#define HWKM_IMPORT_ERR_KWK_SIZE_ERROR BIT(10) +#define HWKM_IMPORT_ERR_DKS_SIZE_ERROR BIT(11) +#define HWKM_IMPORT_ERR_DKS_OUT_OF_RANGE BIT(12) +#define HWKM_IMPORT_ERR_KWK_SLOT_OUT_OF_RANGE BIT(13) +#define HWKM_IMPORT_ERR_KT_PARITY BIT(14) +#define HWKM_IMPORT_ERR_SECURITY_LEVEL_ERROR BIT(15) +#define HWKM_IMPORT_ERR_INVALID_SECURITY_LEVEL BIT(16) +#define HWKM_IMPORT_ERR_INVALID_KEY_TYPE BIT(17) +#define HWKM_IMPORT_ERR_INVALID_ALG_ALLOWED BIT(18) +#define HWKM_IMPORT_ERR_CONSISTENCY_CHECK_FAILED BIT(19) +#define HWKM_IMPORT_ERR_INVALID_TPKEY_ATTRIB BIT(20) +#define HWKM_IMPORT_ERR_INVALID_KSK_ATTRIB BIT(21) +#define HWKM_IMPORT_ERR_INVALID_KWK_ATTRIB BIT(22) +#define HWKM_IMPORT_ERR_INVALID_KDF_DEPTH BIT(23) +#define HWKM_IMPORT_ERR_DECRYPT_NOT_ALLOWED BIT(24) +#define HWKM_IMPORT_ERR_UNEXPECTED_ALG_ALLOWED BIT(25) +#define HWKM_IMPORT_ERR_UNEXPECTED_KEY_TYPE BIT(26) +#define HWKM_IMPORT_ERR_KWK_SLOT_EMPTY BIT(27) +#define HWKM_IMPORT_ERR_DKS_SLOT_NOT_EMPTY BIT(28) +#define HWKM_IMPORT_ERR_DKS_ACCESS_VIOLATION BIT(29) +#define HWKM_IMPORT_ERR_KWK_ACCESS_VIOLATION BIT(30) + +/* KEY_SLOT_CLEAR specific errors (bits 8+). */ +#define HWKM_CLEAR_ERR_KEYSLOT_ID_NOT_ACCESSIBLE BIT(8) +#define HWKM_CLEAR_ERR_KEYSLOT_ID_OUT_OF_RANGE BIT(9) +#define HWKM_CLEAR_ERR_KEY_SIZE BIT(10) +#define HWKM_CLEAR_ERR_DOUBLE_KEY_DKS_SLOT_NOT_EVEN BIT(11) +#define HWKM_CLEAR_ERR_DKS_SLOT_EMPTY BIT(12) +#define HWKM_CLEAR_ERR_ACCESS_VIOLATION BIT(13) + +/* SET_TPKEY specific errors (bits 8+). */ +#define HWKM_TPKEY_ERR_KT_PARITY BIT(8) +#define HWKM_TPKEY_ERR_DOUBLE_KEY_SLOT_NOT_EVEN BIT(9) +#define HWKM_TPKEY_ERR_WRONG_KEY_SIZE BIT(10) +#define HWKM_TPKEY_ERR_KEYSLOT_ID_OUT_OF_RANGE BIT(11) +#define HWKM_TPKEY_ERR_UNEXPECTED_KEY_TYPE BIT(12) +#define HWKM_TPKEY_ERR_SKS_SLOT_EMPTY BIT(13) +#define HWKM_TPKEY_ERR_ACCESS_VIOLATION BIT(14) + +const char *hwkm_err2str(uint32_t status); + +#endif /* __HWKM_ERRNO_H__ */ diff --git a/core/drivers/crypto/qcom/include/hwkm_regs.h b/core/drivers/crypto/qcom/include/hwkm_regs.h new file mode 100644 index 000000000..297da7786 --- /dev/null +++ b/core/drivers/crypto/qcom/include/hwkm_regs.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. + * + * HWKM register offsets and field masks. + */ + +#ifndef __HWKM_REGS_H__ +#define __HWKM_REGS_H__ + +#include /* BIT() and GENMASK_32(). */ + +/* SHARED_IPCAT_VERSION (HWKM_REGS_BASE + 0x0000U). */ +/* IP Catalog version: [31:24] major, [23:16] minor, [15:0] step. */ +#define HWKM_SHARED_IPCAT_VERSION 0x0000U + +/* SHARED_KEY_POLICY_VERSION (HWKM_REGS_BASE + 0x0004U). */ +/* Key-policy format version supported by this instance. */ +#define HWKM_SHARED_KEY_POLICY_VERSION 0x0004U + +/* SHARED_KEYTABLE_SIZE (HWKM_REGS_BASE + 0x000cU). */ +/* Number of key slots in this instance's key table. */ +#define HWKM_SHARED_KEYTABLE_SIZE 0x000cU + +/* TZ_KM_CTL (HWKM_REGS_BASE + 0x1000U). */ +#define HWKM_TZ_KM_CTL 0x1000U +/* Bit 0 - enable CRC validation on every command packet. */ +#define HWKM_TZ_KM_CTL_CRC_CHECK_EN_SHIFT 0U +#define HWKM_TZ_KM_CTL_CRC_CHECK_EN \ + BIT(HWKM_TZ_KM_CTL_CRC_CHECK_EN_SHIFT) + +/* TZ_KM_STATUS (HWKM_REGS_BASE + 0x1004U). */ +#define HWKM_TZ_KM_STATUS 0x1004U +/* + * Hardware BIST detected a fault in the key table or crypto logic. + * If set, the instance must not be used; the driver treats this as + * a fatal error. + */ +#define HWKM_TZ_KM_STATUS_BIST_ERROR_SHIFT 0xfU +#define HWKM_TZ_KM_STATUS_BIST_ERROR \ + BIT(HWKM_TZ_KM_STATUS_BIST_ERROR_SHIFT) +/* + * Internal crypto-library self-test failed. Treated identically to + * BIST_ERROR by the driver; either bit causes bist_failed to be set. + */ +#define HWKM_TZ_KM_STATUS_CRYPTO_LIB_BIST_ERROR_SHIFT 0xdU +#define HWKM_TZ_KM_STATUS_CRYPTO_LIB_BIST_ERROR \ + BIT(HWKM_TZ_KM_STATUS_CRYPTO_LIB_BIST_ERROR_SHIFT) + +/* TPKEY_RECEIVE_CTL (HWKM_REGS_BASE + 0x101cU). */ +#define HWKM_TZ_TPKEY_RECEIVE_CTL 0x101cU +/* Arm (1) or disarm (0) the slave for TPKEY reception. */ +#define HWKM_TZ_TPKEY_RECEIVE_CTL_EN_SHIFT 0x8U +#define HWKM_TZ_TPKEY_RECEIVE_CTL_EN \ + BIT(HWKM_TZ_TPKEY_RECEIVE_CTL_EN_SHIFT) +/* + * Destination key slot that will receive the incoming TPKEY [7:0]. + * Write CRYPTO_DEFAULT_TPKEY here before asserting EN. + */ +#define HWKM_TZ_TPKEY_RECEIVE_CTL_TPKEY_DKS GENMASK_32(7, 0) + +/* TZ_TPKEY_RECEIVE_STATUS (HWKM_REGS_BASE + 0x1020U). */ +#define HWKM_TZ_TPKEY_RECEIVE_STATUS 0x1020U +/* + * Set by hardware when the TPKEY has been written into TPKEY_DKS. + * Poll this after SET_TPKEY, before disarming the slave. + */ +#define HWKM_TZ_TPKEY_RECEIVE_STATUS_DONE_SHIFT 0x8U +#define HWKM_TZ_TPKEY_RECEIVE_STATUS_DONE \ + BIT(HWKM_TZ_TPKEY_RECEIVE_STATUS_DONE_SHIFT) +/* Slot index where the TPKEY was stored (readback of TPKEY_DKS) [7:0]. */ +#define HWKM_TZ_TPKEY_RECEIVE_STATUS_TPKEY_DKS GENMASK_32(7, 0) + +/* BANK0_KM_CTL (HWKM_REGS_BASE + 0x2000U). */ +#define HWKM_BANK0_KM_CTL 0x2000U +/* + * Enable the command FIFO for a new packet. Write 1 after clearing the + * FIFO and ESR, before writing the first command word. + */ +#define HWKM_BANK0_KM_CTL_CMD_ENABLE_SHIFT 0U +#define HWKM_BANK0_KM_CTL_CMD_ENABLE \ + BIT(HWKM_BANK0_KM_CTL_CMD_ENABLE_SHIFT) +/* + * Flush the command FIFO. Write 1 then 0 to reset. Read back: if still 1 + * after deassertion, the FIFO did not drain. + */ +#define HWKM_BANK0_KM_CTL_CMD_FIFO_CLEAR_SHIFT 0x1U +#define HWKM_BANK0_KM_CTL_CMD_FIFO_CLEAR \ + BIT(HWKM_BANK0_KM_CTL_CMD_FIFO_CLEAR_SHIFT) + +/* BANK0_KM_STATUS (HWKM_REGS_BASE + 0x2004U). */ +#define HWKM_BANK0_KM_STATUS 0x2004U +/* + * Words of data available in the response FIFO [13:9]. + * Poll > 0 before reading each response word. + */ +#define HWKM_BANK0_KM_STATUS_RSP_AVAIL_DATA GENMASK_32(13, 9) +/* + * Words of free space in the command FIFO [18:14]. + * Poll > 0 before writing each command word. + */ +#define HWKM_BANK0_KM_STATUS_CMD_AVAIL_SPACE GENMASK_32(18, 14) + +/* KM_IRQ_STATUS (HWKM_REGS_BASE + 0x2008U). */ +#define HWKM_BANK0_KM_IRQ_STATUS 0x2008U +/* + * Set by hardware when the full command has been processed and the complete + * response is in the RSP FIFO. If 0 after reading all expected response + * words, more data remains -> HWKM_ERR_RSP_OVERFLOW. + * Clear by writing 1 at the end of every successful transaction. + */ +#define HWKM_BANK0_KM_IRQ_STATUS_CMD_DONE_SHIFT 0x1U +#define HWKM_BANK0_KM_IRQ_STATUS_CMD_DONE \ + BIT(HWKM_BANK0_KM_IRQ_STATUS_CMD_DONE_SHIFT) +/* + * Response FIFO full. May be spuriously set after reset (HW errata + * QCTDD06252768). Clear unconditionally during init by writing 1. + */ +#define HWKM_BANK0_KM_IRQ_STATUS_RSP_FIFO_FULL_SHIFT 0x3U +#define HWKM_BANK0_KM_IRQ_STATUS_RSP_FIFO_FULL \ + BIT(HWKM_BANK0_KM_IRQ_STATUS_RSP_FIFO_FULL_SHIFT) + +/* + * BANK0_KM_ESR - Error status register (HWKM_REGS_BASE + 0x2010U). + * + * Each bit represents one error condition from the last command. + * Clear pattern: + * io_write32_off(HWKM_REGS_BASE, HWKM_BANK0_KM_ESR, + * io_read32_off(HWKM_REGS_BASE, HWKM_BANK0_KM_ESR)) + * Do this at the start of every transaction to acknowledge stale errors. + */ +#define HWKM_BANK0_KM_ESR 0x2010U + +/* + * BANK0_KM_CMD_FIFO - Command FIFO write port (HWKM_REGS_BASE + 0x201cU). + * + * Write one 32-bit command word per store after polling CMD_FIFO_AVAIL_SPACE. + */ +#define HWKM_BANK0_KM_CMD_FIFO 0x201cU + +/* + * BANK0_KM_RSP_FIFO - Response FIFO read port (HWKM_REGS_BASE + 0x205cU). + * + * Read one 32-bit response word per load after polling RSP_FIFO_AVAIL_DATA. + */ +#define HWKM_BANK0_KM_RSP_FIFO 0x205cU + +/* Bank-Based Access Control (BBAC) bitmaps. */ + +#define HWKM_BANK0_AC 0x6000U +#define HWKM_BANK1_AC 0x7000U +#define HWKM_BANK2_AC 0x8000U +#define HWKM_BANK3_AC 0x9000U + +#define HWKM_BANKn_AC_BBAC_0 0x0000U /* slots 0-31. */ +#define HWKM_BANKn_AC_BBAC_1 0x0004U /* slots 32-63. */ +#define HWKM_BANKn_AC_BBAC_2 0x0008U /* slots 64-95. */ +#define HWKM_BANKn_AC_BBAC_3 0x000cU /* slots 96-127. */ +#define HWKM_BANKn_AC_BBAC_4 0x0010U /* slots 128-159. */ + +#endif /* __HWKM_REGS_H__ */ diff --git a/core/drivers/crypto/qcom/sub.mk b/core/drivers/crypto/qcom/sub.mk new file mode 100644 index 000000000..741e77845 --- /dev/null +++ b/core/drivers/crypto/qcom/sub.mk @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright (c) 2026, Qualcomm Technologies, Inc. + +incdirs-y += include +srcs-y += hwkm.c hwkm_huk.c hwkm_transaction.c + +# Bitmap of fuse regions whose SHA256 digest is folded into the HUK KDF input. +# Each bit corresponds to a fuse region index; set a bit to bind the HUK to +# that region's content. Defaults to 0 (no fuse regions included). +CFG_HWKM_HUK_FUSE_REGION_DIGEST ?= 0x0 + +# Mix TZ_SKDK_L2 into the HUK KDF via the MKS field. When enabled, an SKDK L3 +# key is derived from TZ_SKDK_L2 and passed as the mixing key for the UKDK L3 +# and L4 derivation steps, binding the HUK to the SKDK lineage in addition to +# the UKDK. Defaults to y. +CFG_HWKM_HUK_MIX_SKDK ?= y diff --git a/core/drivers/crypto/sub.mk b/core/drivers/crypto/sub.mk index 3457f43cc..31f1d7cc2 100644 --- a/core/drivers/crypto/sub.mk +++ b/core/drivers/crypto/sub.mk @@ -17,3 +17,5 @@ subdirs-$(CFG_AMD_ASU_SUPPORT) += asu_driver subdirs-$(CFG_HISILICON_CRYPTO_DRIVER) += hisilicon subdirs-$(CFG_IMX_ELE) += ele + +subdirs-$(CFG_QCOM_HWKM) += qcom diff --git a/core/drivers/qcom/prng/prng.c b/core/drivers/qcom/rng/qcom-csrng.c similarity index 58% rename from core/drivers/qcom/prng/prng.c rename to core/drivers/qcom/rng/qcom-csrng.c index 8f50f56b7..1b7c6a15b 100644 --- a/core/drivers/qcom/prng/prng.c +++ b/core/drivers/qcom/rng/qcom-csrng.c @@ -10,19 +10,19 @@ #include #include -#define SEC_PRNG_REG_SIZE 0x1000 +#define QCOM_RNG_REG_SIZE 0x1000 -#define SEC_PRNG_DATA_OUT 0x0 -#define SEC_PRNG_STATUS 0x4 -#define SEC_PRNG_STATUS_DATA_AVAIL_BMSK 0x1 +#define QCOM_RNG_DATA_OUT 0x0 +#define QCOM_RNG_STATUS 0x4 +#define QCOM_RNG_STATUS_DATA_AVAIL_BMSK 0x1 -#define PRNG_TIMEOUT_US 1000000 +#define QCOM_RNG_TIMEOUT_US 1000000 static struct { paddr_t pa; vaddr_t va; -} prng = { - .pa = SEC_PRNG_REG_BASE, +} rng = { + .pa = QCOM_RNG_REG_BASE, }; TEE_Result hw_get_random_bytes(void *buf, size_t len) @@ -31,22 +31,22 @@ TEE_Result hw_get_random_bytes(void *buf, size_t len) uint32_t val = 0; uint64_t to = 0; - if (!prng.va) + if (!rng.va) return TEE_ERROR_NOT_SUPPORTED; if (!out || !len) return TEE_ERROR_BAD_PARAMETERS; - to = timeout_init_us(PRNG_TIMEOUT_US); + to = timeout_init_us(QCOM_RNG_TIMEOUT_US); while (len) { - if (!(io_read32(prng.va + SEC_PRNG_STATUS) & - SEC_PRNG_STATUS_DATA_AVAIL_BMSK)) { + if (!(io_read32(rng.va + QCOM_RNG_STATUS) & + QCOM_RNG_STATUS_DATA_AVAIL_BMSK)) { if (timeout_elapsed(to)) return TEE_ERROR_BUSY; continue; } - while ((val = io_read32(prng.va + SEC_PRNG_DATA_OUT)) == 0) { + while ((val = io_read32(rng.va + QCOM_RNG_DATA_OUT)) == 0) { if (timeout_elapsed(to)) return TEE_ERROR_BUSY; } @@ -60,14 +60,14 @@ TEE_Result hw_get_random_bytes(void *buf, size_t len) return TEE_SUCCESS; } -static TEE_Result qcom_prng_init(void) +static TEE_Result qcom_csrng_init(void) { - prng.va = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_SEC, prng.pa, - SEC_PRNG_REG_SIZE); - if (!prng.va) + rng.va = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_SEC, rng.pa, + QCOM_RNG_REG_SIZE); + if (!rng.va) return TEE_ERROR_GENERIC; return TEE_SUCCESS; } -early_init(qcom_prng_init); +early_init(qcom_csrng_init); diff --git a/core/drivers/qcom/rpmh/kodiak/rpmh_msgram_config.h b/core/drivers/qcom/rpmh/kodiak/rpmh_msgram_config.h new file mode 100644 index 000000000..6cc71ad80 --- /dev/null +++ b/core/drivers/qcom/rpmh/kodiak/rpmh_msgram_config.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __RPMH_MSGRAM_CONFIG_H__ +#define __RPMH_MSGRAM_CONFIG_H__ + +#define MSG_RAM_SECTION_SIZE 0x10000 + +#endif /* __RPMH_MSGRAM_CONFIG_H__ */ diff --git a/core/drivers/qcom/rpmh/lemans/rpmh_msgram_config.h b/core/drivers/qcom/rpmh/lemans/rpmh_msgram_config.h new file mode 100644 index 000000000..6cc71ad80 --- /dev/null +++ b/core/drivers/qcom/rpmh/lemans/rpmh_msgram_config.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __RPMH_MSGRAM_CONFIG_H__ +#define __RPMH_MSGRAM_CONFIG_H__ + +#define MSG_RAM_SECTION_SIZE 0x10000 + +#endif /* __RPMH_MSGRAM_CONFIG_H__ */ diff --git a/core/drivers/qcom/rpmh/nord/rpmh_msgram_config.h b/core/drivers/qcom/rpmh/nord/rpmh_msgram_config.h new file mode 100644 index 000000000..b44baacc1 --- /dev/null +++ b/core/drivers/qcom/rpmh/nord/rpmh_msgram_config.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __RPMH_MSGRAM_CONFIG_H__ +#define __RPMH_MSGRAM_CONFIG_H__ + +/* AOP message RAM section size: MSG_RAM_DRV_SIZE (0x400) + MSG_RAM_GAP_SIZE (0xC00) */ +#define MSG_RAM_SECTION_SIZE 0x1000 + +#endif /* __RPMH_MSGRAM_CONFIG_H__ */ diff --git a/core/drivers/qcom/rpmh/rpmh_client.c b/core/drivers/qcom/rpmh/rpmh_client.c index e10d73c37..8722ef996 100644 --- a/core/drivers/qcom/rpmh/rpmh_client.c +++ b/core/drivers/qcom/rpmh/rpmh_client.c @@ -22,6 +22,7 @@ #include #include "rpmh_hal.h" +#include "rpmh_msgram_config.h" #include "rpmh_resource_commands.h" #include "rpmh_tcs.h" @@ -66,7 +67,6 @@ struct client_queue { }; #define AOP_BOOT_COOKIE 0xA0C00C1E -#define MSG_RAM_SECTION_SIZE 0x10000 struct aop_msg_ram_dict { uint32_t boot_cookie_offset; @@ -242,7 +242,7 @@ static TEE_Result check_aop_init(void) return TEE_ERROR_GENERIC; } - dict_addr = base + AOP_MSG_RAM_SIZE - MSG_RAM_SECTION_SIZE; + dict_addr = base + 15 * MSG_RAM_SECTION_SIZE; dict = (struct aop_msg_ram_dict *)dict_addr; cookie_addr = base + dict->boot_cookie_offset; diff --git a/core/drivers/qcom/rpmh/sub.mk b/core/drivers/qcom/rpmh/sub.mk index 5152d9c0c..ef6901f3e 100644 --- a/core/drivers/qcom/rpmh/sub.mk +++ b/core/drivers/qcom/rpmh/sub.mk @@ -19,3 +19,6 @@ srcs-y += rpmh_resource_commands.c # DRV configuration srcs-y += rpmh_drv_config.c + +# Per-target rpmh_msgram_config.h (MSG_RAM_SECTION_SIZE) +global-incdirs-y += $(PLATFORM_FLAVOR) diff --git a/core/drivers/qcom/sub.mk b/core/drivers/qcom/sub.mk index 41d17c06c..56e7d0625 100644 --- a/core/drivers/qcom/sub.mk +++ b/core/drivers/qcom/sub.mk @@ -5,8 +5,10 @@ # srcs-$(CFG_QCOM_RAMBLUR_PIMEM_V3) += ramblur/ramblur_pimem_v3.c -srcs-$(CFG_QCOM_PRNG) += prng/prng.c +srcs-$(CFG_QCOM_CSRNG) += rng/qcom-csrng.c +srcs-$(CFG_QCOM_SEC_WDOG) += wdt/qcom-wdt.c subdirs-$(CFG_QCOM_CMD_DB) += cmd_db subdirs-$(CFG_QCOM_RPMH_CLIENT) += rpmh subdirs-$(CFG_QCOM_QFPROM) += qfprom +subdirs-$(CFG_QCOM_XPUV4) += xpu diff --git a/core/drivers/qcom/wdt/qcom-wdt.c b/core/drivers/qcom/wdt/qcom-wdt.c new file mode 100644 index 000000000..ecdc4de67 --- /dev/null +++ b/core/drivers/qcom/wdt/qcom-wdt.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define QCOM_WDT_CTL_OFFSET 0x08 +#define QCOM_WDT_BARK_TIME_OFFSET 0x10 +#define QCOM_WDT_BITE_TIME_OFFSET 0x14 +#define QCOM_WDT_RESET_REG_OFFSET 0x4 + +#define QCOM_WDT_CTL_INT_ENABLE BIT32(0) +#define QCOM_WDT_CTL_UNMASKED_INT_ENABLE BIT32(1) + +#define QCOM_WDT_RESET_REG_RESET UINT32_C(1) + +#define QCOM_WDT_BARK_TIME_RMSK 0xFFFFFU +#define QCOM_WDT_BITE_TIME_RMSK 0xFFFFFU + +#define QCOM_WDT_CLK_HZ 32000U + +#define QCOM_WDT_MS_TO_TICKS(ms) \ + ((uint32_t)(((uint64_t)(ms) * QCOM_WDT_CLK_HZ) / 1000U)) + +#define QCOM_WDT_BARK_TIME_MS 6000U +#define QCOM_WDT_BITE_TIME_MS 22000U + +register_phys_mem_pgdir(MEM_AREA_IO_SEC, QCOM_WDT_TMR_BASE, + CORE_MMU_PGDIR_SIZE); + +static vaddr_t qcom_wdt_base; + +static void qcom_wdt_enable(bool enable) +{ + uint32_t val = QCOM_WDT_CTL_UNMASKED_INT_ENABLE; + + if (enable) + val |= QCOM_WDT_CTL_INT_ENABLE; + + io_write32(qcom_wdt_base + QCOM_WDT_CTL_OFFSET, val); +} + +static void qcom_wdt_reset(void) +{ + io_write32(qcom_wdt_base + QCOM_WDT_RESET_REG_OFFSET, + QCOM_WDT_RESET_REG_RESET); +} + +static void qcom_wdt_start(void) +{ + uint32_t bark_timeout = QCOM_WDT_MS_TO_TICKS(QCOM_WDT_BARK_TIME_MS); + uint32_t bite_timeout = QCOM_WDT_MS_TO_TICKS(QCOM_WDT_BITE_TIME_MS); + + /* Timeouts have a ceiling value */ + bark_timeout = MIN(bark_timeout, (uint32_t)(QCOM_WDT_BARK_TIME_RMSK)); + bite_timeout = MIN(bite_timeout, (uint32_t)(QCOM_WDT_BITE_TIME_RMSK)); + + io_write32(qcom_wdt_base + QCOM_WDT_BARK_TIME_OFFSET, bark_timeout); + io_write32(qcom_wdt_base + QCOM_WDT_BITE_TIME_OFFSET, bite_timeout); + + qcom_wdt_enable(true); + + qcom_wdt_reset(); +} + +static enum itr_return +qcom_wdt_bark_handler(struct itr_handler *h __unused) +{ + io_write32(qcom_wdt_base + QCOM_WDT_RESET_REG_OFFSET, + QCOM_WDT_RESET_REG_RESET); + + return ITRR_HANDLED; +} + +static TEE_Result qcom_wdt_init(void) +{ + TEE_Result res = TEE_SUCCESS; + struct itr_handler *handler = NULL; + + qcom_wdt_base = (vaddr_t)phys_to_virt(QCOM_WDT_TMR_BASE, + MEM_AREA_IO_SEC, + CORE_MMU_PGDIR_SIZE); + if (!qcom_wdt_base) { + EMSG("wdt: Failed to map watchdog registers"); + return TEE_ERROR_GENERIC; + } + + qcom_wdt_enable(false); + + res = interrupt_create_handler(interrupt_get_main_chip(), + QCOM_WDT_BARK_INT_ID, + qcom_wdt_bark_handler, + 0u, 0u, &handler); + if (res != TEE_SUCCESS) { + EMSG("wdt: Failed to register bark handler (err=0x%x)", + res); + return res; + } + + qcom_wdt_start(); + + return TEE_SUCCESS; +} + +driver_init(qcom_wdt_init); + diff --git a/core/drivers/qcom/xpu/ipq52xx/xpu_target.h b/core/drivers/qcom/xpu/ipq52xx/xpu_target.h new file mode 100644 index 000000000..74c974ecb --- /dev/null +++ b/core/drivers/qcom/xpu/ipq52xx/xpu_target.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef XPU_TARGET_H +#define XPU_TARGET_H + +/* MEMNOC_SCH_MPU: resource groups 10..15 are free for runtime allocation */ +#define DDR_MPU_BASE UL(0xAC0000) +#define DDR_MPU_ADDR_OFFSET UL(0x80000000) +#define DDR_XPU_RG_START UL(10) +#define DDR_XPU_RG_COUNT UL(6) + +/* + * OCIMEM_MPU register window. The base is well below CORE_MMU_PGDIR_SIZE, + * so a pgdir-granularity mapping would round it down to address 0 and a + * small explicit range is mapped instead. Resource groups 9..10 are free + * for runtime allocation. + */ +#define IMEM_MPU_BASE UL(0x54000) +#define IMEM_MPU_MAP_SIZE (2 * SMALL_PAGE_SIZE) +#define IMEM_XPU_RG_START UL(9) +#define IMEM_XPU_RG_COUNT UL(2) + +/* AP (secure + non-secure), TME ROM, and debug may read the DIAG log */ +#define DIAG_XPU_READ_QAD \ + (QAD_ENV_APPS | QAD_TME_ROM | QAD_DEBUG) + +#endif /* XPU_TARGET_H */ diff --git a/core/drivers/qcom/xpu/ipq96xx/xpu_target.h b/core/drivers/qcom/xpu/ipq96xx/xpu_target.h new file mode 100644 index 000000000..298931165 --- /dev/null +++ b/core/drivers/qcom/xpu/ipq96xx/xpu_target.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef XPU_TARGET_H +#define XPU_TARGET_H + +/* MACHX_LLCC_MPU: resource groups 30..39 are free for runtime allocation */ +#define DDR_MPU_BASE UL(0x4060000) +#define DDR_MPU_ADDR_OFFSET UL(0x0) +#define DDR_XPU_RG_START UL(30) +#define DDR_XPU_RG_COUNT UL(10) + +/* + * OCIMEM_MPU register window. The base is well below CORE_MMU_PGDIR_SIZE, + * so a pgdir-granularity mapping would round it down to address 0 and a + * small explicit range is mapped instead. Resource groups 6..9 are free + * for runtime allocation. + */ +#define IMEM_MPU_BASE UL(0x54000) +#define IMEM_MPU_MAP_SIZE (2 * SMALL_PAGE_SIZE) +#define IMEM_XPU_RG_START UL(6) +#define IMEM_XPU_RG_COUNT UL(4) + +/* + * AP (secure + non-secure), TME ROM, debug, AP boot loader, modem, and + * PRIME may read the DIAG log. + */ +#define DIAG_XPU_READ_QAD \ + (QAD_ENV_APPS | QAD_TME_ROM | QAD_DEBUG | QAD_AP_QC_BL | QAD_MSA | \ + QAD_PRIME) + +#endif /* XPU_TARGET_H */ diff --git a/core/drivers/qcom/xpu/sub.mk b/core/drivers/qcom/xpu/sub.mk new file mode 100644 index 000000000..fd8be7f20 --- /dev/null +++ b/core/drivers/qcom/xpu/sub.mk @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# + +srcs-$(CFG_QCOM_XPUV4) += xpuv4.c + +global-incdirs-y += $(PLATFORM_FLAVOR) diff --git a/core/drivers/qcom/xpu/xpuv4.c b/core/drivers/qcom/xpu/xpuv4.c new file mode 100644 index 000000000..c43301785 --- /dev/null +++ b/core/drivers/qcom/xpu/xpuv4.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * XPU4 register offsets. + * IDR0 reports the highest resource group (RG) index in NRG. Each RG + * occupies 0x40 bytes starting at base + 0x1000. + * IDR0 +0x0000 NRG = bits 25:16 + * RGCR1n +0x1004 bit 0 = RGE (enable) + * RGCSAR1n +0x1008 start address [63:32] + * RGCSAR0n +0x100C start address [31:0] + * RGCEAR1n +0x1010 end address [63:32] + * RGCEAR0n +0x1014 end address [31:0] + * RGRDRn +0x1018 read QAD vector + * RGWRRn +0x101C write QAD vector + * QADRGLn +0x1030 QAD lock vector (bit 31 = secure lock RGL_S) + */ +#define XPU4_IDR0(b) ((b) + 0x0u) +#define XPU4_RGCR1n(b, n) ((b) + 0x1004u + 0x40u * (n)) +#define XPU4_RGCSAR1n(b, n) ((b) + 0x1008u + 0x40u * (n)) +#define XPU4_RGCSAR0n(b, n) ((b) + 0x100Cu + 0x40u * (n)) +#define XPU4_RGCEAR1n(b, n) ((b) + 0x1010u + 0x40u * (n)) +#define XPU4_RGCEAR0n(b, n) ((b) + 0x1014u + 0x40u * (n)) +#define XPU4_RGRDRn(b, n) ((b) + 0x1018u + 0x40u * (n)) +#define XPU4_RGWRRn(b, n) ((b) + 0x101Cu + 0x40u * (n)) +#define XPU4_QADRGLn(b, n) ((b) + 0x1030u + 0x40u * (n)) + +#define XPU4_IDR0_NRG_MASK SHIFT_U32(0x3FF, 16) +#define XPU4_IDR0_NRG_SHIFT 16 + +#define XPU4_RGCR1n_RGE BIT32(0) + +/* + * struct xpu_instance - An XPU4 instance and the memory it guards + * @base: XPU4 register base (SoC physical address) + * @map_size: Size of the register window to map at @base + * @addr_off: Base the instance's address registers are relative to + * @guard_start: Start of the memory range this instance guards + * @guard_size: Size of the memory range this instance guards + * @rg_start: First resource group available for dynamic allocation + * @rg_count: Number of resource groups available from @rg_start + * + * Resource groups outside [@rg_start, @rg_start + @rg_count) belong to + * other owners such as earlier boot stages and are never allocated here. + */ +struct xpu_instance { + paddr_t base; + size_t map_size; + paddr_t addr_off; + paddr_t guard_start; + size_t guard_size; + unsigned int rg_start; + unsigned int rg_count; +}; + +static const struct xpu_instance xpu_instances[] = { + { + .base = DDR_MPU_BASE, + .map_size = CORE_MMU_PGDIR_SIZE, + .addr_off = DDR_MPU_ADDR_OFFSET, + .guard_start = DRAM0_BASE, + .guard_size = DRAM0_SIZE, + .rg_start = DDR_XPU_RG_START, + .rg_count = DDR_XPU_RG_COUNT, + }, + { + .base = IMEM_MPU_BASE, + .map_size = IMEM_MPU_MAP_SIZE, + .addr_off = IMEM_BASE, + .guard_start = IMEM_BASE, + .guard_size = IMEM_SIZE, + .rg_start = IMEM_XPU_RG_START, + .rg_count = IMEM_XPU_RG_COUNT, + }, +}; + +register_phys_mem_pgdir(MEM_AREA_IO_SEC, DDR_MPU_BASE, CORE_MMU_PGDIR_SIZE); +register_phys_mem(MEM_AREA_IO_SEC, IMEM_MPU_BASE, IMEM_MPU_MAP_SIZE); + +static const struct xpu_instance *xpu_find_instance(paddr_t start, size_t size) +{ + const struct xpu_instance *inst = NULL; + size_t i = 0; + + for (i = 0; i < ARRAY_SIZE(xpu_instances); i++) { + inst = &xpu_instances[i]; + + if (core_is_buffer_inside(start, size, inst->guard_start, + inst->guard_size)) + return inst; + } + + return NULL; +} + +static TEE_Result xpu_find_free_rg(vaddr_t base, + const struct xpu_instance *inst, + unsigned int *rg) +{ + unsigned int rg_end = inst->rg_start + inst->rg_count; + unsigned int nrg = 0; + unsigned int i = 0; + + /* IDR0 reports the highest RG index, so the count is one more */ + nrg = ((io_read32(XPU4_IDR0(base)) & XPU4_IDR0_NRG_MASK) >> + XPU4_IDR0_NRG_SHIFT) + 1; + if (rg_end > nrg) { + EMSG("XPU: RG window %u..%u exceeds %u RGs implemented", + inst->rg_start, rg_end - 1, nrg); + return TEE_ERROR_BAD_STATE; + } + + for (i = inst->rg_start; i < rg_end; i++) { + if (io_read32(XPU4_RGCR1n(base, i)) & XPU4_RGCR1n_RGE) + continue; + + *rg = i; + return TEE_SUCCESS; + } + + EMSG("XPU: no free RG in window %u..%u", inst->rg_start, rg_end - 1); + return TEE_ERROR_OUT_OF_MEMORY; +} + +static void xpu4_program_rg(vaddr_t base, unsigned int rg, paddr_t start, + paddr_t end, uint32_t read_qad, uint32_t write_qad, + uint32_t lock_qad) +{ + io_write32(XPU4_RGCSAR1n(base, rg), (uint32_t)(start >> 32)); + io_write32(XPU4_RGCSAR0n(base, rg), (uint32_t)start); + io_write32(XPU4_RGCEAR1n(base, rg), (uint32_t)(end >> 32)); + io_write32(XPU4_RGCEAR0n(base, rg), (uint32_t)end); + io_write32(XPU4_RGRDRn(base, rg), read_qad); + io_write32(XPU4_RGWRRn(base, rg), write_qad); + io_write32(XPU4_RGCR1n(base, rg), XPU4_RGCR1n_RGE); + io_write32(XPU4_QADRGLn(base, rg), lock_qad); +} + +/* + * xpu_protect_region() - Restrict access to a memory region + * @start: Region start address (must be 4KB aligned) + * @size: Region size in bytes (must be 4KB aligned, non-zero) + * @read_perm: Read QAD permission vector + * @write_perm: Write QAD permission vector + * + * Restricts [@start, @start + @size) to @read_perm/@write_perm and locks + * the configuration. The XPU instance guarding the region and a free + * resource group within it are determined from @start, so callers only + * describe the region and the access policy they need. + * + * The lock is held by whichever AP domains (secure/non-secure APPS) are + * present in @read_perm/@write_perm. + */ +static TEE_Result xpu_protect_region(paddr_t start, size_t size, + uint32_t read_perm, uint32_t write_perm) +{ + const struct xpu_instance *inst = NULL; + uint32_t lock_perm = 0; + unsigned int rg = 0; + paddr_t xpu_start = 0; + paddr_t xpu_end = 0; + vaddr_t base = 0; + TEE_Result res = TEE_ERROR_GENERIC; + + /* XPU4 requires 4KB-aligned, non-zero start and end addresses */ + if (!size || !IS_ALIGNED(start, SIZE_4K) || + !IS_ALIGNED(size, SIZE_4K)) { + EMSG("XPU: region %#" PRIxPA "+%#zx not 4KB aligned", + start, size); + return TEE_ERROR_BAD_PARAMETERS; + } + + inst = xpu_find_instance(start, size); + if (!inst) { + EMSG("XPU: no instance guards region %#" PRIxPA "+%#zx", + start, size); + return TEE_ERROR_ITEM_NOT_FOUND; + } + + /* The XPU stores addresses relative to its memory-region base */ + if (SUB_OVERFLOW(start, inst->addr_off, &xpu_start) || + ADD_OVERFLOW(xpu_start, size, &xpu_end)) { + EMSG("XPU: region %#" PRIxPA "+%#zx invalid for offset %#" + PRIxPA, start, size, inst->addr_off); + return TEE_ERROR_BAD_PARAMETERS; + } + + lock_perm = (read_perm | write_perm) & QAD_ENV_APPS; + if (!lock_perm) { + EMSG("XPU: no AP domain in region perms, refusing to program"); + return TEE_ERROR_BAD_PARAMETERS; + } + + base = io_pa_or_va_secure(&(struct io_pa_va){ .pa = inst->base }, + inst->map_size); + + res = xpu_find_free_rg(base, inst, &rg); + if (res) + return res; + + xpu4_program_rg(base, rg, xpu_start, xpu_end, + read_perm, write_perm, lock_perm); + + return TEE_SUCCESS; +} + +static TEE_Result xpu_init(void) +{ + TEE_Result diag_res = TEE_SUCCESS; + TEE_Result ddr_res = TEE_SUCCESS; + + static_assert(IS_ALIGNED(CFG_TZDRAM_START, SIZE_4K)); + static_assert(IS_ALIGNED(CFG_TZDRAM_SIZE, SIZE_4K)); + + ddr_res = xpu_protect_region(CFG_TZDRAM_START, CFG_TZDRAM_SIZE, + QAD_APPS_SEC, QAD_APPS_SEC); + if (ddr_res) + EMSG("XPU: TZDRAM protection failed: %#" PRIx32, ddr_res); + + /* + * The DIAG log buffer only holds data when the log itself is built + * in, so protecting it otherwise would lock a resource group for a + * region nothing uses. + */ + if (IS_ENABLED(CFG_QCOM_DIAG_LOG)) { + diag_res = xpu_protect_region(DIAG_BASE, DIAG_SIZE, + DIAG_XPU_READ_QAD, QAD_APPS_SEC); + if (diag_res) + EMSG("XPU: DIAG log protection failed: %#" PRIx32, + diag_res); + } + + /* Protect what is left even if one region could not be programmed */ + if (ddr_res) + return ddr_res; + + return diag_res; +} +service_init(xpu_init); diff --git a/core/include/drivers/clk_qcom.h b/core/include/drivers/clk_qcom.h index 9baac78cb..b4c5d3579 100644 --- a/core/include/drivers/clk_qcom.h +++ b/core/include/drivers/clk_qcom.h @@ -7,6 +7,7 @@ #ifndef _CLK_QCOM_H_ #define _CLK_QCOM_H_ +#include #include #include #include @@ -25,7 +26,10 @@ enum qcom_clk_group { QCOM_CLKS_WPSS, QCOM_CLKS_TURING, + QCOM_CLKS_TURING1, QCOM_CLKS_LPASS, + QCOM_CLKS_GPDSP0, + QCOM_CLKS_GPDSP1, QCOM_CLKS_MAX, }; @@ -34,10 +38,52 @@ enum qcom_clk_group { #define CBCR_BRANCH_OFF_BIT BIT(31) #define CMD_RCGR_UPDATE_BIT BIT(0) +/* Register configuration for a Lucid-EVO PLL. */ +struct qcom_lucidevo_pll_config { + uint32_t l_val; + uint32_t cal_l_val; + uint32_t alpha_val; + uint32_t pre_div; /* div-1..div-8; 0 = div-1 */ + uint32_t config_ctl; + uint32_t config_ctl_u; + uint32_t config_ctl_u1; + uint32_t user_ctl; + uint32_t user_ctl_u; + bool frac_mode_mn; /* false = alpha (default for Q6) */ +}; + TEE_Result qcom_clock_enable(enum qcom_clk_group group); TEE_Result qcom_clock_enable_cbc(vaddr_t cbcr); TEE_Result qcom_clock_set_rate(vaddr_t cfg_rcgr, vaddr_t cmd_rcgr, uint32_t cfg_value); + +/* Configure, lock and enable a Lucid-EVO PLL at @pll_base; returns + * TEE_ERROR_TIMEOUT if it fails to lock. + */ +TEE_Result qcom_lucidevo_pll_enable(vaddr_t pll_base, + const struct qcom_lucidevo_pll_config *cfg); +#ifdef CFG_QCOM_PAS_PTA TEE_Result qcom_clock_enable_pas(enum qcom_clk_group group); +TEE_Result qcom_clock_enable_pas_processor(enum qcom_clk_group group); +TEE_Result qcom_clock_pas_reset(enum qcom_clk_group group); +#else +static inline TEE_Result qcom_clock_enable_pas(enum qcom_clk_group group + __unused) +{ + return TEE_ERROR_NOT_SUPPORTED; +} + +static inline TEE_Result +qcom_clock_enable_pas_processor(enum qcom_clk_group group __unused) +{ + return TEE_ERROR_NOT_SUPPORTED; +} + +static inline TEE_Result qcom_clock_pas_reset(enum qcom_clk_group group + __unused) +{ + return TEE_ERROR_NOT_SUPPORTED; +} +#endif #endif /* _CLK_QCOM_H_ */ diff --git a/core/include/drivers/qcom/xpuv4.h b/core/include/drivers/qcom/xpuv4.h new file mode 100644 index 000000000..7c2a34b24 --- /dev/null +++ b/core/include/drivers/qcom/xpuv4.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef XPUV4_H +#define XPUV4_H + +#include + +/* + * QAD vector for the secure APPS domain: bit 0 = QAD_APPS identifier, + * bit 31 = secure qualifier. + */ +#define QAD_APPS_SEC (BIT32(0) | BIT32(31)) + +/* + * AP execution-environment QAD vector (secure + non-secure APPS). + */ +#define QAD_ENV_APPS (BIT32(0) | BIT32(31) | BIT32(30)) + +/* + * Per-master QAD identifiers, so read/write policy vectors in platform + * config spell out which masters have access instead of an opaque hex + * literal. Identifiers and their meaning come from the XPU4 static QAD + * assignment; not every identifier is wired to a real master on every SoC. + */ +#define QAD_TME_ROM BIT32(1) +#define QAD_DEBUG BIT32(3) +#define QAD_AP_QC_BL BIT32(4) +#define QAD_MSA BIT32(5) +#define QAD_PRIME BIT32(6) + +#endif /* XPUV4_H */ diff --git a/core/include/io.h b/core/include/io.h index 2b4717661..b3d5fa10d 100644 --- a/core/include/io.h +++ b/core/include/io.h @@ -62,6 +62,42 @@ static inline uint64_t io_read64(vaddr_t addr) return *(volatile uint64_t *)addr; } +static inline void io_write32_off(vaddr_t base, size_t offset, uint32_t val) +{ + io_write32(base + offset, val); +} + +static inline uint32_t io_read32_off(vaddr_t base, size_t offset) +{ + return io_read32(base + offset); +} + +/* + * Get and set a field within a 32-bit register at @base + @offset. + * + * @mask selects the field's bits in the register. The shift is derived from + * @mask's lowest set bit, so callers only need to supply the mask. + * + * io_read32_off_field() returns the field's current value, right-justified. + * io_write32_off_field() updates only the bits covered by @mask, leaving the + * rest of the register unchanged. + */ +static inline uint32_t io_read32_off_field(vaddr_t base, size_t offset, + uint32_t mask) +{ + return (io_read32_off(base, offset) & mask) / (mask & ~(mask - 1)); +} + +static inline void io_write32_off_field(vaddr_t base, size_t offset, + uint32_t mask, uint32_t val) +{ + uint32_t regval = io_read32_off(base, offset); + + regval &= ~mask; + regval |= (val * (mask & ~(mask - 1))) & mask; + io_write32_off(base, offset, regval); +} + static inline void io_mask8(vaddr_t addr, uint8_t val, uint8_t mask) { io_write8(addr, (io_read8(addr) & ~mask) | (val & mask)); diff --git a/core/mm/core_mmu.c b/core/mm/core_mmu.c index 7be812709..f24f8778a 100644 --- a/core/mm/core_mmu.c +++ b/core/mm/core_mmu.c @@ -2458,8 +2458,24 @@ void *core_mmu_add_mapping(enum teecore_memtypes type, paddr_t addr, size_t len) if (map->size < l) return NULL; - if (static_memory_map.count >= static_memory_map.alloc_count) - return NULL; + if (static_memory_map.count >= static_memory_map.alloc_count) { + /* + * Out of pre-allocated entries (the map is frozen at count + 5 + * after boot), so grow it through the registered realloc hook, + * as grow_mem_map() does for every other add path. + */ + if (!memory_map_realloc_func) + return NULL; + memory_map_realloc_func(mem_map); + + /* + * The realloc may have moved the map array, so the RES_VASPACE + * entry resolved above is now stale - look it up again. + */ + map = find_map_by_type(MEM_AREA_RES_VASPACE); + if (!map) + return NULL; + } mem_map->map[mem_map->count] = (struct tee_mmap_region){ .va = map->va, diff --git a/core/pta/qcom/pas/compute.c b/core/pta/qcom/pas/compute.c deleted file mode 100644 index 608cee5a7..000000000 --- a/core/pta/qcom/pas/compute.c +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause -/* - * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. - */ - -#include -#include -#include -#include - -#include "dsp_boot.h" -#include "pas.h" - -TEE_Result compute_fw_start(struct qcom_pas_data *data) -{ - return dsp_fw_start(data, dsp_fw_get_boot_regs(data->pas_id)); -} - -TEE_Result compute_fw_shutdown(struct qcom_pas_data *data __unused) -{ - return TEE_ERROR_NOT_IMPLEMENTED; -} diff --git a/core/pta/qcom/pas/lpass.c b/core/pta/qcom/pas/lpass.c deleted file mode 100644 index c66a6e1ce..000000000 --- a/core/pta/qcom/pas/lpass.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause -/* - * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. - */ - -#include -#include -#include -#include - -#include "dsp_boot.h" -#include "pas.h" - -TEE_Result lpass_fw_start(struct qcom_pas_data *data) -{ - const struct dsp_fw_boot_regs *reg = dsp_fw_get_boot_regs(data->pas_id); - vaddr_t base = io_pa_or_va(&data->base, data->size); - - if (!reg || !base) - return TEE_ERROR_GENERIC; - - io_write32(base + reg->lpass.efuse_evb_sel, 0); - - return dsp_fw_start(data, reg); -} - -TEE_Result lpass_fw_shutdown(struct qcom_pas_data *data __unused) -{ - return TEE_ERROR_NOT_IMPLEMENTED; -} diff --git a/core/pta/qcom/pas/pas.c b/core/pta/qcom/pas/pas.c deleted file mode 100644 index 4c9af308d..000000000 --- a/core/pta/qcom/pas/pas.c +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause -/* - * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. - */ - -#include -#include - -#include "pas.h" -#include "pas_resources.h" - -static TEE_Result get_mem_rsc(struct resource_table *rt, size_t *rt_size, - struct resource_table *table, - const struct fw_rsc_hdr *mem_hdr, - const struct fw_rsc_devmem *mem_res, - size_t table_header_size, size_t table_size) -{ - uint8_t *p = (uint8_t *)rt; - uint32_t offset = 0; - - if (rt_size && *rt_size < table_size) { - *rt_size = table_size; - - return TEE_SUCCESS; - } - - if (!rt) - return TEE_ERROR_BAD_PARAMETERS; - - offset = table_header_size; - - for (size_t i = 0; i < table->num; i++, mem_res++) { - table->offset[i] = offset; - memcpy(p + offset, mem_hdr, sizeof(*mem_hdr)); - offset += sizeof(*mem_hdr); - memcpy(p + offset, mem_res, sizeof(*mem_res)); - offset += sizeof(*mem_res); - } - - memcpy(p, table, table_header_size); - - return TEE_SUCCESS; -} - -TEE_Result pas_get_resource_table(uint32_t pas_id, struct resource_table *rt, - size_t *rt_size) -{ - switch (pas_id) { - case PAS_ID_WPSS: - return get_mem_rsc(rt, rt_size, &wpss_rt, &wpss_mem_hdr, - wpss_mem_res, - WPSS_RESOURCE_TABLE_HEADER_SIZE, - WPSS_RESOURCE_TABLE_SIZE); - case PAS_ID_TURING: - return get_mem_rsc(rt, rt_size, &turing_rt, &turing_mem_hdr, - turing_mem_res, - TURING_RESOURCE_TABLE_HEADER_SIZE, - TURING_RESOURCE_TABLE_SIZE); - case PAS_ID_QDSP6: - return get_mem_rsc(rt, rt_size, &lpass_rt, &lpass_mem_hdr, - lpass_mem_res, - LPASS_RESOURCE_TABLE_HEADER_SIZE, - LPASS_RESOURCE_TABLE_SIZE); - default: - return TEE_ERROR_NOT_SUPPORTED; - } -} diff --git a/core/pta/qcom/pas/pas.h b/core/pta/qcom/pas/pas.h deleted file mode 100644 index 5cd07d310..000000000 --- a/core/pta/qcom/pas/pas.h +++ /dev/null @@ -1,95 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -/* - * Copyright (c) 2025, Linaro Limited - * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. - */ - -#ifndef _PAS_H_ -#define _PAS_H_ - -#include -#include -#include -#include - -#define PAS_ID_QDSP6 1 -#define PAS_ID_WPSS 6 -#define PAS_ID_VENUS 9 -#define PAS_ID_TURING 18 - -#define DEFINE_RESOURCE_TABLE(prefix, num_res) \ - enum { \ - prefix##_NUM_MEM_RESOURCES = (num_res), \ - prefix##_SIZE_MEM_RES = \ - (sizeof(struct fw_rsc_hdr) + \ - sizeof(struct fw_rsc_devmem)), \ - prefix##_RESOURCE_TABLE_HEADER_SIZE = \ - (sizeof(struct resource_table) + \ - (prefix##_NUM_MEM_RESOURCES * \ - sizeof(uint32_t))), \ - prefix##_RESOURCE_TABLE_SIZE = \ - (prefix##_RESOURCE_TABLE_HEADER_SIZE + \ - (prefix##_NUM_MEM_RESOURCES * \ - prefix##_SIZE_MEM_RES)), \ - } - -struct resource_table { - uint32_t ver; - uint32_t num; - uint32_t reserved[2]; - uint32_t offset[]; -} __packed; - -struct fw_rsc_hdr { - uint32_t type; - uint8_t data[]; -} __packed; - -enum fw_resource_type { - RSC_CARVEOUT = 0, - RSC_DEVMEM = 1, - RSC_TRACE = 2, - RSC_VDEV = 3, - RSC_LAST = 4, - RSC_VENDOR_START = 128, - RSC_VENDOR_END = 512, -}; - -#define IOMMU_READ BIT(0) -#define IOMMU_WRITE BIT(1) - -struct fw_rsc_devmem { - uint32_t da; - uint32_t pa; - uint32_t len; - uint32_t flags; - uint32_t reserved; - uint8_t name[32]; -} __packed; - -struct qcom_pas_data { - uint32_t pas_id; - struct io_pa_va base; - size_t size; - paddr_t fw_base; - size_t fw_size; - enum qcom_clk_group clk_group; -}; - -TEE_Result pas_get_resource_table(uint32_t pas_id, struct resource_table *rt, - size_t *rt_size); - -TEE_Result wpss_fw_start(struct qcom_pas_data *data); -TEE_Result wpss_fw_shutdown(struct qcom_pas_data *data); - -TEE_Result compute_fw_start(struct qcom_pas_data *data); -TEE_Result compute_fw_shutdown(struct qcom_pas_data *data); - -TEE_Result lpass_fw_start(struct qcom_pas_data *data); -TEE_Result lpass_fw_shutdown(struct qcom_pas_data *data); - -TEE_Result venus_fw_start(struct qcom_pas_data *data); -TEE_Result venus_fw_shutdown(struct qcom_pas_data *data); -TEE_Result venus_fw_set_state(struct qcom_pas_data *data, bool power_on); - -#endif /* _PAS_H_ */ diff --git a/core/pta/qcom/pas/pas_core.c b/core/pta/qcom/pas/pas_core.c new file mode 100644 index 000000000..403fb9eba --- /dev/null +++ b/core/pta/qcom/pas/pas_core.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include + +#include "pas_subsys.h" + +static struct qcom_pas_subsys *pas_lookup(uint32_t pas_id) +{ + struct qcom_pas_subsys *subsys = NULL; + size_t count = 0; + + subsys = qcom_pas_platform_subsys(&count); + for (size_t i = 0; i < count; i++) { + if (subsys[i].data.pas_id == pas_id) + return &subsys[i]; + } + + return NULL; +} + +TEE_Result pas_platform_is_supported(uint32_t pas_id) +{ + if (!pas_lookup(pas_id)) + return TEE_ERROR_NOT_SUPPORTED; + + return TEE_SUCCESS; +} + +TEE_Result pas_platform_capabilities(uint32_t pas_id __unused) +{ + return TEE_SUCCESS; +} + +TEE_Result pas_platform_init_image(uint32_t pas_id) +{ + if (!pas_lookup(pas_id)) + return TEE_ERROR_NOT_SUPPORTED; + + return TEE_SUCCESS; +} + +TEE_Result pas_platform_mem_setup(uint32_t pas_id, uint32_t fw_size, + uint32_t fw_base_low, uint32_t fw_base_high) +{ + struct qcom_pas_subsys *subsys = pas_lookup(pas_id); + struct qcom_pas_data *data = NULL; + + if (!subsys) + return TEE_ERROR_NOT_SUPPORTED; + + data = &subsys->data; + data->fw_size = fw_size; + data->fw_base = fw_base_low; + data->fw_base |= SHIFT_U64(fw_base_high, 32); + + /* Map the controller */ + if (!data->base.va) { + data->base.va = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_NSEC, + data->base.pa, + data->size); + if (!data->base.va) + return TEE_ERROR_GENERIC; + } + + return TEE_SUCCESS; +} + +TEE_Result pas_platform_get_resource_table(uint32_t pas_id, + struct resource_table *rt, + size_t *size) +{ + struct qcom_pas_subsys *subsys = pas_lookup(pas_id); + + if (!subsys || !subsys->ops->get_resource_table) + return TEE_ERROR_NOT_SUPPORTED; + + return subsys->ops->get_resource_table(rt, size); +} + +TEE_Result pas_platform_set_remote_state(uint32_t pas_id, uint32_t state) +{ + struct qcom_pas_subsys *subsys = pas_lookup(pas_id); + + if (!subsys || !subsys->ops->fw_set_state) + return TEE_ERROR_NOT_IMPLEMENTED; + + return subsys->ops->fw_set_state(&subsys->data, state); +} + +TEE_Result pas_platform_auth_and_reset(uint32_t pas_id) +{ + struct qcom_pas_subsys *subsys = pas_lookup(pas_id); + struct qcom_pas_data *data = NULL; + TEE_Result res = TEE_ERROR_GENERIC; + + if (!subsys) + return TEE_ERROR_NOT_SUPPORTED; + + data = &subsys->data; + if (!data->fw_base) + return TEE_ERROR_NO_DATA; + + switch (subsys->reset_seq) { + case QCOM_PAS_RESET_CLK_FULL: + res = qcom_clock_pas_reset(data->clk_group); + if (res != TEE_SUCCESS) + return res; + + res = qcom_clock_enable(data->clk_group); + if (res != TEE_SUCCESS) + return res; + + res = subsys->ops->fw_start(data); + if (res != TEE_SUCCESS) + return res; + + return qcom_clock_enable_pas_processor(data->clk_group); + case QCOM_PAS_RESET_CLK_ENABLE: + res = qcom_clock_enable(data->clk_group); + if (res != TEE_SUCCESS) { + EMSG("Failed to enable clocks: %d", res); + return res; + } + + return subsys->ops->fw_start(data); + case QCOM_PAS_RESET_NONE: + return subsys->ops->fw_start(data); + default: + return TEE_ERROR_NOT_SUPPORTED; + } +} + +TEE_Result pas_platform_shutdown(uint32_t pas_id) +{ + struct qcom_pas_subsys *subsys = pas_lookup(pas_id); + + if (!subsys || !subsys->ops->fw_shutdown) + return TEE_ERROR_NOT_SUPPORTED; + + return subsys->ops->fw_shutdown(&subsys->data); +} diff --git a/core/pta/qcom/pas/platform/kodiak/cdsp.c b/core/pta/qcom/pas/platform/kodiak/cdsp.c new file mode 100644 index 000000000..a8cad6548 --- /dev/null +++ b/core/pta/qcom/pas/platform/kodiak/cdsp.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include + +#include "cdsp.h" +#include "dsp_fw.h" + +#define TURING_QDSP6V68SS_PUB_REG 0x00b00000 +#define TURING_QDSP6V68SS_CC_REG 0x00b18000 +#define TURING_QDSP6SS_Q6_CC_REG 0x00b40000 + +static const struct fw_rsc_devmem turing_mem_res[] = { + { .name = "tcsr_2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x01fc0000, .pa = 0x01fc0000, .len = 0x00030000, }, + { .name = "tcsr_mutex", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x01f40000, .pa = 0x01f40000, .len = 0x00020000, }, + { .name = "efuse", .flags = IOMMU_READ, + .da = 0x00780000, .pa = 0x00780000, .len = 0x0000A000, }, + { .name = "mailbox", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x406000, .pa = 0x406000, .len = 0x00001000, }, + { .name = "smem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x80900000, .pa = 0x80900000, .len = 0x00200000, }, + { .name = "cmd_db", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x80860000, .pa = 0x80860000, .len = 0x00020000, }, + { .name = "aoss_msg_ram", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x0c300000, .pa = 0x0c300000, .len = 0x00100000, }, + { .name = "clk_ctl", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x00100000, .pa = 0x00100000, .len = 0x001f0000, }, + { .name = "rpmh_pdc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x0b2b0000, .pa = 0x0b2b0000, .len = 0x00010000, }, + { .name = "rpmh_seqmem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x0b4b0000, .pa = 0x0b4b0000, .len = 0x00010000, }, + { .name = "rpmh_bcm", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x0bbf0000, .pa = 0x0bbf0000, .len = 0x0002000, }, + { .name = "ddr_reg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x09080000, .pa = 0x09080000, .len = 0x00001000, }, + { .name = "llcc_bdcast", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x09600000, .pa = 0x09600000, .len = 0x00058000, }, + { .name = "llcc0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x09200000, .pa = 0x09200000, .len = 0x00058000, }, + { .name = "llcc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x09280000, .pa = 0x09280000, .len = 0x00058000, }, + { .name = "rdpm", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x00634000, .pa = 0x00634000, .len = 0x00004000, }, +}; + +DEFINE_RESOURCE_TABLE(TURING, ARRAY_SIZE(turing_mem_res)); + +static TEE_Result cdsp_fw_start(struct qcom_pas_data *data) +{ + const struct dsp_fw_start_regs regs = { + .boot_status = TURING_QDSP6V68SS_PUB_REG + 0x408, + .core_start = TURING_QDSP6V68SS_PUB_REG + 0x400, + .core_cbcr = TURING_QDSP6SS_Q6_CC_REG + 0x1040, + .sleep_cbcr = TURING_QDSP6V68SS_CC_REG + 0x58, + .boot_cmd = TURING_QDSP6V68SS_PUB_REG + 0x404, + .rst_evb = TURING_QDSP6V68SS_PUB_REG + 0x10, + .xo_cbcr = TURING_QDSP6V68SS_CC_REG + 0x54, + }; + + return dsp_fw_start(data, ®s); +} + +static TEE_Result cdsp_fw_shutdown(struct qcom_pas_data *data __unused) +{ + return TEE_ERROR_NOT_IMPLEMENTED; +} + +static TEE_Result cdsp_get_resource_table(struct resource_table *rt, + size_t *rt_size) +{ + const struct fw_rsc_hdr header = { + .type = RSC_DEVMEM, + }; + static struct resource_table table = { + .ver = 1, + .num = TURING_NUM_MEM_RESOURCES, + .offset[TURING_NUM_MEM_RESOURCES - 1] = 0, + }; + + return get_mem_rsc(rt, rt_size, &table, &header, + turing_mem_res, + TURING_RESOURCE_TABLE_HEADER_SIZE, + TURING_RESOURCE_TABLE_SIZE); +} + +const struct qcom_pas_ops cdsp_ops = { + .fw_start = cdsp_fw_start, + .fw_shutdown = cdsp_fw_shutdown, + .get_resource_table = cdsp_get_resource_table, +}; diff --git a/core/pta/qcom/pas/platform/kodiak/cdsp.h b/core/pta/qcom/pas/platform/kodiak/cdsp.h new file mode 100644 index 000000000..4f8713fad --- /dev/null +++ b/core/pta/qcom/pas/platform/kodiak/cdsp.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _CDSP_H_ +#define _CDSP_H_ + +#include "pas_subsys.h" + +extern const struct qcom_pas_ops cdsp_ops; + +#endif /* _CDSP_H_ */ diff --git a/core/pta/qcom/pas/platform/kodiak/dsp_boot.h b/core/pta/qcom/pas/platform/kodiak/dsp_boot.h deleted file mode 100644 index 11800fc40..000000000 --- a/core/pta/qcom/pas/platform/kodiak/dsp_boot.h +++ /dev/null @@ -1,80 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -/* - * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. - */ - -#ifndef _DSP_BOOT_H_ -#define _DSP_BOOT_H_ - -#include -#include -#include -#include - -#include "dsp.h" -#include "pas.h" - -/* - * Compute - */ -#define TURING_QDSP6V68SS_PUB_REG 0x00b00000 -#define TURING_QDSP6V68SS_CC_REG 0x00b18000 -#define TURING_QDSP6SS_Q6_CC_REG 0x00b40000 - -static const struct dsp_fw_boot_regs compute_fw_boot_regs = { - .xo_cbcr = TURING_QDSP6V68SS_CC_REG + 0x54, - .sleep_cbcr = TURING_QDSP6V68SS_CC_REG + 0x58, - .core_cbcr = TURING_QDSP6SS_Q6_CC_REG + 0x1040, - .rst_evb = TURING_QDSP6V68SS_PUB_REG + 0x10, - .core_start = TURING_QDSP6V68SS_PUB_REG + 0x400, - .boot_cmd = TURING_QDSP6V68SS_PUB_REG + 0x404, - .boot_status = TURING_QDSP6V68SS_PUB_REG + 0x408, -}; - -/* - * LPASS - */ -#define LPASS_QDSP6V67SS_PUB_REG 0x00400000 -#define LPASS_MCC_REG 0x00950000 - -static const struct dsp_fw_boot_regs lpass_fw_boot_regs = { - .xo_cbcr = LPASS_QDSP6V67SS_PUB_REG + 0x38, - .sleep_cbcr = LPASS_QDSP6V67SS_PUB_REG + 0x3c, - .core_cbcr = LPASS_QDSP6V67SS_PUB_REG + 0x20, - .rst_evb = LPASS_QDSP6V67SS_PUB_REG + 0x10, - .core_start = LPASS_QDSP6V67SS_PUB_REG + 0x400, - .boot_cmd = LPASS_QDSP6V67SS_PUB_REG + 0x404, - .boot_status = LPASS_QDSP6V67SS_PUB_REG + 0x408, - .lpass.efuse_evb_sel = LPASS_MCC_REG + 0xb000, -}; - -/* - * WPSS - */ -#define WPSS_QDSP6V67SS_PUB_REG 0x00000000 - -static const struct dsp_fw_boot_regs wpss_fw_boot_regs = { - .xo_cbcr = WPSS_QDSP6V67SS_PUB_REG + 0x38, - .sleep_cbcr = WPSS_QDSP6V67SS_PUB_REG + 0x3c, - .core_cbcr = WPSS_QDSP6V67SS_PUB_REG + 0x20, - .rst_evb = WPSS_QDSP6V67SS_PUB_REG + 0x10, - .core_start = WPSS_QDSP6V67SS_PUB_REG + 0x400, - .boot_cmd = WPSS_QDSP6V67SS_PUB_REG + 0x404, - .boot_status = WPSS_QDSP6V67SS_PUB_REG + 0x408, -}; - -static inline const struct dsp_fw_boot_regs *dsp_fw_get_boot_regs(uint32_t id) -{ - switch (id) { - case PAS_ID_WPSS: - return &wpss_fw_boot_regs; - case PAS_ID_TURING: - return &compute_fw_boot_regs; - case PAS_ID_QDSP6: - return &lpass_fw_boot_regs; - default: - return NULL; - } -} - -#endif /* _DSP_BOOT_H_ */ diff --git a/core/pta/qcom/pas/dsp.c b/core/pta/qcom/pas/platform/kodiak/dsp_fw.c similarity index 92% rename from core/pta/qcom/pas/dsp.c rename to core/pta/qcom/pas/platform/kodiak/dsp_fw.c index d81c96fcd..df970e1b3 100644 --- a/core/pta/qcom/pas/dsp.c +++ b/core/pta/qcom/pas/platform/kodiak/dsp_fw.c @@ -4,12 +4,10 @@ */ #include -#include #include #include -#include "dsp.h" -#include "pas.h" +#include "dsp_fw.h" #define CBCR_BRANCH_ENABLE_BIT BIT(0) #define CBCR_HW_CTL_ENABLE_BIT BIT(1) @@ -19,7 +17,7 @@ #define BOOT_FSM_TIMEOUT 10000 TEE_Result dsp_fw_start(struct qcom_pas_data *data, - const struct dsp_fw_boot_regs *regs) + const struct dsp_fw_start_regs *regs) { vaddr_t base = io_pa_or_va(&data->base, data->size); uint64_t timeout; diff --git a/core/pta/qcom/pas/dsp.h b/core/pta/qcom/pas/platform/kodiak/dsp_fw.h similarity index 62% rename from core/pta/qcom/pas/dsp.h rename to core/pta/qcom/pas/platform/kodiak/dsp_fw.h index 8b190b5a4..e2b33f3fb 100644 --- a/core/pta/qcom/pas/dsp.h +++ b/core/pta/qcom/pas/platform/kodiak/dsp_fw.h @@ -3,16 +3,16 @@ * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. */ -#ifndef _DSP_H_ -#define _DSP_H_ +#ifndef _DSP_FW_H_ +#define _DSP_FW_H_ -#include "pas.h" +#include "pas_data.h" -struct dsp_fw_boot_lpass_regs { +struct dsp_fw_start_lpass_regs { uint32_t efuse_evb_sel; }; -struct dsp_fw_boot_regs { +struct dsp_fw_start_regs { uint32_t xo_cbcr; uint32_t sleep_cbcr; uint32_t core_cbcr; @@ -21,10 +21,10 @@ struct dsp_fw_boot_regs { uint32_t boot_cmd; uint32_t boot_status; /* lpass */ - struct dsp_fw_boot_lpass_regs lpass; + struct dsp_fw_start_lpass_regs lpass; }; TEE_Result dsp_fw_start(struct qcom_pas_data *data, - const struct dsp_fw_boot_regs *regs); + const struct dsp_fw_start_regs *regs); -#endif /* _DSP_H_ */ +#endif /* _DSP_FW_H_ */ diff --git a/core/pta/qcom/pas/venus.c b/core/pta/qcom/pas/platform/kodiak/iris.c similarity index 66% rename from core/pta/qcom/pas/venus.c rename to core/pta/qcom/pas/platform/kodiak/iris.c index deea980a5..54f60a162 100644 --- a/core/pta/qcom/pas/venus.c +++ b/core/pta/qcom/pas/platform/kodiak/iris.c @@ -4,12 +4,10 @@ */ #include -#include #include #include -#include "pas.h" -#include "video.h" +#include "iris.h" #define WRAPPER_IRIS_VERSION 0x0 #define WRAPPER_CPA_START_ADDR 0x1020 @@ -21,10 +19,11 @@ #define WRAPPER_TZ_XTSS_SW_RESET 0x1000 #define WRAPPER_XTSS_SW_RESET_BIT BIT(0) -static TEE_Result venus_reset_cpu(struct qcom_pas_data *data) +static TEE_Result iris_reset_cpu(struct qcom_pas_data *data) { - vaddr_t base = io_pa_or_va(&data->base, data->size); + vaddr_t base = 0; + base = io_pa_or_va(&data->base, data->size); if (!base) return TEE_ERROR_GENERIC; @@ -41,11 +40,12 @@ static TEE_Result venus_reset_cpu(struct qcom_pas_data *data) return TEE_SUCCESS; } -TEE_Result venus_fw_shutdown(struct qcom_pas_data *data) +static TEE_Result iris_fw_shutdown(struct qcom_pas_data *data) { - vaddr_t base = io_pa_or_va(&data->base, data->size); - uint32_t reg; + vaddr_t base = 0; + uint32_t reg = 0; + base = io_pa_or_va(&data->base, data->size); if (!base) return TEE_ERROR_GENERIC; @@ -58,16 +58,21 @@ TEE_Result venus_fw_shutdown(struct qcom_pas_data *data) return TEE_SUCCESS; } -TEE_Result venus_fw_start(struct qcom_pas_data *data) +static TEE_Result iris_fw_start(struct qcom_pas_data *data) { - return venus_reset_cpu(data); + return iris_reset_cpu(data); } -TEE_Result venus_fw_set_state(struct qcom_pas_data *data, bool power_on) +static TEE_Result iris_fw_set_state(struct qcom_pas_data *data, bool power_on) { if (power_on) - return venus_reset_cpu(data); + return iris_reset_cpu(data); - return venus_fw_shutdown(data); + return iris_fw_shutdown(data); } +const struct qcom_pas_ops iris_ops = { + .fw_start = iris_fw_start, + .fw_shutdown = iris_fw_shutdown, + .fw_set_state = iris_fw_set_state, +}; diff --git a/core/pta/qcom/pas/platform/kodiak/video.h b/core/pta/qcom/pas/platform/kodiak/iris.h similarity index 64% rename from core/pta/qcom/pas/platform/kodiak/video.h rename to core/pta/qcom/pas/platform/kodiak/iris.h index da31db4b0..b283c3cf0 100644 --- a/core/pta/qcom/pas/platform/kodiak/video.h +++ b/core/pta/qcom/pas/platform/kodiak/iris.h @@ -3,10 +3,14 @@ * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. */ -#ifndef _VIDEO_H_ -#define _VIDEO_H_ +#ifndef _IRIS_H_ +#define _IRIS_H_ + +#include "pas_subsys.h" #define IRIS_WRAPPER_TOP_TZ_REG_BASE 0x000c0000 #define IRIS_WRAPPER_TOP_REG_BASE 0x000b0000 -#endif +extern const struct qcom_pas_ops iris_ops; + +#endif /* _IRIS_H_ */ diff --git a/core/pta/qcom/pas/platform/kodiak/lpass.c b/core/pta/qcom/pas/platform/kodiak/lpass.c new file mode 100644 index 000000000..d12f43661 --- /dev/null +++ b/core/pta/qcom/pas/platform/kodiak/lpass.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include + +#include "dsp_fw.h" +#include "lpass.h" + +#define LPASS_QDSP6V67SS_PUB_REG 0x00400000 +#define LPASS_MCC_REG 0x00950000 + +static const struct fw_rsc_devmem lpass_mem_res[] = { + { .name = "efuse", .flags = IOMMU_READ, + .da = 0x00786000, .pa = 0x00786000, .len = 0x00020000, }, + { .name = "rng", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x010d4000, .pa = 0x010d4000, .len = 0x00001000, }, + { .name = "mailbox", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x00403000, .pa = 0x00403000, .len = 0x00001000, }, + { .name = "rpmh", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x0a000000, .pa = 0x0a000000, .len = 0x05000000, }, + { .name = "tcsr_2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x01fc0000, .pa = 0x01fc0000, .len = 0x00030000, }, + { .name = "tcsr_mutex", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x01f40000, .pa = 0x01f40000, .len = 0x00020000, }, + { .name = "smem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x80900000, .pa = 0x80900000, .len = 0x00200000, }, + { .name = "gcc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x00100000, .pa = 0x00100000, .len = 0x001F0000, }, + { .name = "cmd_db", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x80860000, .pa = 0x80860000, .len = 0x00020000, }, + { .name = "i2c", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x00a80000, .pa = 0x00a80000, .len = 0x00004000, }, + { .name = "pinctrl", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x0f100000, .pa = 0x0f100000, .len = 0x00300000, }, +}; + +DEFINE_RESOURCE_TABLE(LPASS, ARRAY_SIZE(lpass_mem_res)); + +static TEE_Result lpass_fw_start(struct qcom_pas_data *data) +{ + const struct dsp_fw_start_regs regs = { + .boot_status = LPASS_QDSP6V67SS_PUB_REG + 0x408, + .core_start = LPASS_QDSP6V67SS_PUB_REG + 0x400, + .sleep_cbcr = LPASS_QDSP6V67SS_PUB_REG + 0x3c, + .lpass.efuse_evb_sel = LPASS_MCC_REG + 0xb000, + .core_cbcr = LPASS_QDSP6V67SS_PUB_REG + 0x20, + .boot_cmd = LPASS_QDSP6V67SS_PUB_REG + 0x404, + .xo_cbcr = LPASS_QDSP6V67SS_PUB_REG + 0x38, + .rst_evb = LPASS_QDSP6V67SS_PUB_REG + 0x10, + }; + vaddr_t base = 0; + + base = io_pa_or_va(&data->base, data->size); + if (!base) + return TEE_ERROR_GENERIC; + + io_write32(base + regs.lpass.efuse_evb_sel, 0); + + return dsp_fw_start(data, ®s); +} + +static TEE_Result lpass_fw_shutdown(struct qcom_pas_data *data __unused) +{ + return TEE_ERROR_NOT_IMPLEMENTED; +} + +static TEE_Result lpass_get_resource_table(struct resource_table *rt, + size_t *rt_size) +{ + const struct fw_rsc_hdr header = { + .type = RSC_DEVMEM, + }; + static struct resource_table table = { + .ver = 1, + .num = LPASS_NUM_MEM_RESOURCES, + .offset[LPASS_NUM_MEM_RESOURCES - 1] = 0, + }; + + return get_mem_rsc(rt, rt_size, &table, &header, + lpass_mem_res, + LPASS_RESOURCE_TABLE_HEADER_SIZE, + LPASS_RESOURCE_TABLE_SIZE); +} + +const struct qcom_pas_ops lpass_ops = { + .fw_start = lpass_fw_start, + .fw_shutdown = lpass_fw_shutdown, + .get_resource_table = lpass_get_resource_table, +}; diff --git a/core/pta/qcom/pas/platform/kodiak/lpass.h b/core/pta/qcom/pas/platform/kodiak/lpass.h new file mode 100644 index 000000000..f8cf519fc --- /dev/null +++ b/core/pta/qcom/pas/platform/kodiak/lpass.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _LPASS_H_ +#define _LPASS_H_ + +#include "pas_subsys.h" + +extern const struct qcom_pas_ops lpass_ops; + +#endif /* _LPASS_H_ */ diff --git a/core/pta/qcom/pas/platform/kodiak/pas_resources.h b/core/pta/qcom/pas/platform/kodiak/pas_resources.h deleted file mode 100644 index b1b7886e5..000000000 --- a/core/pta/qcom/pas/platform/kodiak/pas_resources.h +++ /dev/null @@ -1,129 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -/* - * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. - */ - -#ifndef _PAS_RESOURCES_H_ -#define _PAS_RESOURCES_H_ - -#include -#include -#include -#include - -#include "pas.h" - -/* - * WPSS - */ -static const struct fw_rsc_devmem wpss_mem_res[] = { - {.name = "wlan_fw_mem", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x80c00000, .pa = 0x80c00000, .len = 0xc00000, }, - {.name = "wlan_ce_mem", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x004cd000, .pa = 0x004cd000, .len = 0x1000, }, -}; - -static const struct fw_rsc_hdr wpss_mem_hdr = { - .type = RSC_DEVMEM, -}; - -DEFINE_RESOURCE_TABLE(WPSS, ARRAY_SIZE(wpss_mem_res)); - -static struct resource_table wpss_rt = { - .ver = 1, - .num = WPSS_NUM_MEM_RESOURCES, - .offset[WPSS_NUM_MEM_RESOURCES - 1] = 0, -}; - -/* - * Compute - */ -static const struct fw_rsc_devmem turing_mem_res[] = { - { .name = "tcsr_2", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x01fc0000, .pa = 0x01fc0000, .len = 0x00030000, }, - { .name = "tcsr_mutex", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x01f40000, .pa = 0x01f40000, .len = 0x00020000, }, - { .name = "efuse", .flags = IOMMU_READ, - .da = 0x00780000, .pa = 0x00780000, .len = 0x0000A000, }, - { .name = "mailbox", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x406000, .pa = 0x406000, .len = 0x00001000, }, - { .name = "smem", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x80900000, .pa = 0x80900000, .len = 0x00200000, }, - { .name = "cmd_db", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x80860000, .pa = 0x80860000, .len = 0x00020000, }, - { .name = "aoss_msg_ram", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x0c300000, .pa = 0x0c300000, .len = 0x00100000, }, - { .name = "clk_ctl", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x00100000, .pa = 0x00100000, .len = 0x001f0000, }, - { .name = "rpmh_pdc", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x0b2b0000, .pa = 0x0b2b0000, .len = 0x00010000, }, - { .name = "rpmh_seqmem", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x0b4b0000, .pa = 0x0b4b0000, .len = 0x00010000, }, - { .name = "rpmh_bcm", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x0bbf0000, .pa = 0x0bbf0000, .len = 0x0002000, }, - { .name = "ddr_reg", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x09080000, .pa = 0x09080000, .len = 0x00001000, }, - { .name = "llcc_bdcast", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x09600000, .pa = 0x09600000, .len = 0x00058000, }, - { .name = "llcc0", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x09200000, .pa = 0x09200000, .len = 0x00058000, }, - { .name = "llcc1", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x09280000, .pa = 0x09280000, .len = 0x00058000, }, - { .name = "rdpm", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x00634000, .pa = 0x00634000, .len = 0x00004000, }, -}; - -static const struct fw_rsc_hdr turing_mem_hdr = { - .type = RSC_DEVMEM, -}; - -DEFINE_RESOURCE_TABLE(TURING, ARRAY_SIZE(turing_mem_res)); - -static struct resource_table turing_rt = { - .ver = 1, - .num = TURING_NUM_MEM_RESOURCES, - .offset[TURING_NUM_MEM_RESOURCES - 1] = 0, -}; - -/* - * LPASS - */ -static const struct fw_rsc_devmem lpass_mem_res[] = { - { .name = "efuse", .flags = IOMMU_READ, - .da = 0x00786000, .pa = 0x00786000, .len = 0x00020000, }, - { .name = "rng", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x010d4000, .pa = 0x010d4000, .len = 0x00001000, }, - { .name = "mailbox", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x00403000, .pa = 0x00403000, .len = 0x00001000, }, - { .name = "rpmh", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x0a000000, .pa = 0x0a000000, .len = 0x05000000, }, - { .name = "tcsr_2", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x01fc0000, .pa = 0x01fc0000, .len = 0x00030000, }, - { .name = "tcsr_mutex", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x01f40000, .pa = 0x01f40000, .len = 0x00020000, }, - { .name = "smem", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x80900000, .pa = 0x80900000, .len = 0x00200000, }, - { .name = "gcc", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x00100000, .pa = 0x00100000, .len = 0x001F0000, }, - { .name = "cmd_db", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x80860000, .pa = 0x80860000, .len = 0x00020000, }, - { .name = "i2c", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x00a80000, .pa = 0x00a80000, .len = 0x00004000, }, - { .name = "pinctrl", .flags = IOMMU_READ | IOMMU_WRITE, - .da = 0x0f100000, .pa = 0x0f100000, .len = 0x00300000, }, -}; - -static const struct fw_rsc_hdr lpass_mem_hdr = { - .type = RSC_DEVMEM, -}; - -DEFINE_RESOURCE_TABLE(LPASS, ARRAY_SIZE(lpass_mem_res)); - -static struct resource_table lpass_rt = { - .ver = 1, - .num = LPASS_NUM_MEM_RESOURCES, - .offset[LPASS_NUM_MEM_RESOURCES - 1] = 0, -}; - -#endif /* _PAS_RESOURCES_H_ */ - diff --git a/core/pta/qcom/pas/platform/kodiak/sub.mk b/core/pta/qcom/pas/platform/kodiak/sub.mk new file mode 100644 index 000000000..4be1630e1 --- /dev/null +++ b/core/pta/qcom/pas/platform/kodiak/sub.mk @@ -0,0 +1,3 @@ +srcs-y += subsys.c cdsp.c dsp_fw.c lpass.c wpss.c iris.c +incdirs-y += . +incdirs-y += ../ diff --git a/core/pta/qcom/pas/platform/kodiak/subsys.c b/core/pta/qcom/pas/platform/kodiak/subsys.c new file mode 100644 index 000000000..10cd7fbe4 --- /dev/null +++ b/core/pta/qcom/pas/platform/kodiak/subsys.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include + +#include "cdsp.h" +#include "iris.h" +#include "lpass.h" +#include "pas_subsys.h" +#include "wpss.h" + +static struct qcom_pas_subsys subsystems[] = { + { + .data = { + .pas_id = PAS_ID_WPSS, + .base.pa = WPSS_BASE, + .size = WPSS_SIZE, + .clk_group = QCOM_CLKS_WPSS, + }, + .ops = &wpss_ops, + .reset_seq = QCOM_PAS_RESET_CLK_ENABLE, + }, + { + .data = { + .pas_id = PAS_ID_TURING, + .base.pa = TURING_BASE, + .size = TURING_SIZE, + .clk_group = QCOM_CLKS_TURING, + }, + .ops = &cdsp_ops, + .reset_seq = QCOM_PAS_RESET_CLK_ENABLE, + }, + { + .data = { + .pas_id = PAS_ID_QDSP6, + .base.pa = LPASS_BASE, + .size = LPASS_SIZE, + .clk_group = QCOM_CLKS_LPASS, + }, + .ops = &lpass_ops, + .reset_seq = QCOM_PAS_RESET_CLK_ENABLE, + }, + { + .data = { + .pas_id = PAS_ID_IRIS, + .base.pa = IRIS_BASE, + .size = IRIS_SIZE, + }, + .ops = &iris_ops, + .reset_seq = QCOM_PAS_RESET_NONE, + }, +}; + +struct qcom_pas_subsys *qcom_pas_platform_subsys(size_t *count) +{ + *count = ARRAY_SIZE(subsystems); + + return subsystems; +} diff --git a/core/pta/qcom/pas/platform/kodiak/wpss.c b/core/pta/qcom/pas/platform/kodiak/wpss.c new file mode 100644 index 000000000..ce7fa88b4 --- /dev/null +++ b/core/pta/qcom/pas/platform/kodiak/wpss.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include + +#include "dsp_fw.h" +#include "wpss.h" + +#define WPSS_QDSP6V67SS_PUB_REG 0x00000000 + +static const struct fw_rsc_devmem wpss_mem_res[] = { + { .name = "wlan_fw_mem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x80c00000, .pa = 0x80c00000, .len = 0xc00000, }, + { .name = "wlan_ce_mem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x004cd000, .pa = 0x004cd000, .len = 0x1000, }, +}; + +DEFINE_RESOURCE_TABLE(WPSS, ARRAY_SIZE(wpss_mem_res)); + +static TEE_Result wpss_fw_start(struct qcom_pas_data *data) +{ + static const struct dsp_fw_start_regs regs = { + .boot_status = WPSS_QDSP6V67SS_PUB_REG + 0x408, + .core_start = WPSS_QDSP6V67SS_PUB_REG + 0x400, + .sleep_cbcr = WPSS_QDSP6V67SS_PUB_REG + 0x3c, + .core_cbcr = WPSS_QDSP6V67SS_PUB_REG + 0x20, + .boot_cmd = WPSS_QDSP6V67SS_PUB_REG + 0x404, + .rst_evb = WPSS_QDSP6V67SS_PUB_REG + 0x10, + .xo_cbcr = WPSS_QDSP6V67SS_PUB_REG + 0x38, + }; + + return dsp_fw_start(data, ®s); +} + +static TEE_Result wpss_fw_shutdown(struct qcom_pas_data *data __unused) +{ + return TEE_ERROR_NOT_IMPLEMENTED; +} + +static TEE_Result wpss_get_resource_table(struct resource_table *rt, + size_t *rt_size) +{ + const struct fw_rsc_hdr header = { + .type = RSC_DEVMEM, + }; + static struct resource_table table = { + .ver = 1, + .num = WPSS_NUM_MEM_RESOURCES, + .offset[WPSS_NUM_MEM_RESOURCES - 1] = 0, + }; + + return get_mem_rsc(rt, rt_size, &table, &header, + wpss_mem_res, + WPSS_RESOURCE_TABLE_HEADER_SIZE, + WPSS_RESOURCE_TABLE_SIZE); +} + +const struct qcom_pas_ops wpss_ops = { + .fw_start = wpss_fw_start, + .fw_shutdown = wpss_fw_shutdown, + .get_resource_table = wpss_get_resource_table, +}; diff --git a/core/pta/qcom/pas/platform/kodiak/wpss.h b/core/pta/qcom/pas/platform/kodiak/wpss.h new file mode 100644 index 000000000..3b60634df --- /dev/null +++ b/core/pta/qcom/pas/platform/kodiak/wpss.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _WPSS_H_ +#define _WPSS_H_ + +#include "pas_subsys.h" + +extern const struct qcom_pas_ops wpss_ops; + +#endif /* _WPSS_H_ */ diff --git a/core/pta/qcom/pas/platform/lemans/camera.c b/core/pta/qcom/pas/platform/lemans/camera.c new file mode 100644 index 000000000..6c77b1adf --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/camera.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include + +#include "camera.h" + +#define ICP_SYS_RESET 0x0000 +#define ICP_SYS_RESET_FUNC_RESET BIT(4) + +#define ICP_SYS_CONTROL 0x0004 +#define ICP_SYS_CONTROL_CPU_EN BIT(9) + +#define ICP_SYS_STATUS 0x000c +#define ICP_SYS_STATUS_LX7_STANDBYWFI BIT(7) + +#define ICP_SYS_ACCESS 0x0010 +#define ICP_SYS_ACCESS_QOS_PRIORITY 0x0A0A + +#define ICP_SYS_SID1_START_ADDR 0x0048 +#define ICP_SYS_SID1_START_ADDR_EN BIT(0) +#define ICP_SYS_SID_REGION_MASK 0xFFFFFFF0U + +#define ICP_SYS_SID1_END_ADDR 0x004c + +#define LX7_WFI_TIMEOUT_US 300000 + +static TEE_Result camera_fw_start(struct qcom_pas_data *data) +{ + vaddr_t base = io_pa_or_va(&data->base, data->size); + uint32_t sid_end = 0; + uint32_t reg = 0; + + if (!base) + return TEE_ERROR_GENERIC; + + io_write32(base + ICP_SYS_RESET, ICP_SYS_RESET_FUNC_RESET); + + sid_end = (uint32_t)(data->fw_size) & ICP_SYS_SID_REGION_MASK; + + DMSG("camera: SID1 start=0x%08x end=0x%08x", 0, sid_end); + + io_write32(base + ICP_SYS_SID1_START_ADDR, 0); + io_write32(base + ICP_SYS_SID1_END_ADDR, sid_end); + + io_write32(base + ICP_SYS_ACCESS, ICP_SYS_ACCESS_QOS_PRIORITY); + + reg = io_read32(base + ICP_SYS_SID1_START_ADDR); + io_write32(base + ICP_SYS_SID1_START_ADDR, + reg | ICP_SYS_SID1_START_ADDR_EN); + + io_write32(base + ICP_SYS_CONTROL, ICP_SYS_CONTROL_CPU_EN); + + return TEE_SUCCESS; +} + +static TEE_Result camera_fw_shutdown(struct qcom_pas_data *data) +{ + vaddr_t base = io_pa_or_va(&data->base, data->size); + + if (!base) + return TEE_ERROR_GENERIC; + + io_write32(base + ICP_SYS_CONTROL, 0); + + return TEE_SUCCESS; +} + +static TEE_Result camera_fw_set_state(struct qcom_pas_data *data, bool power_on) +{ + uint64_t timeout = timeout_init_us(LX7_WFI_TIMEOUT_US); + vaddr_t base = io_pa_or_va(&data->base, data->size); + + if (!base) + return TEE_ERROR_GENERIC; + + if (power_on) { + if (io_read32(base + ICP_SYS_CONTROL) & ICP_SYS_CONTROL_CPU_EN) + return TEE_ERROR_BAD_STATE; + return camera_fw_start(data); + } + + while (!timeout_elapsed(timeout)) { + if (io_read32(base + ICP_SYS_STATUS) & + ICP_SYS_STATUS_LX7_STANDBYWFI) + return camera_fw_shutdown(data); + udelay(10); + } + + DMSG("camera: WFI timeout, forcing halt"); + camera_fw_shutdown(data); + return TEE_ERROR_TIMEOUT; +} + +const struct qcom_pas_ops camera_ops = { + .fw_start = camera_fw_start, + .fw_shutdown = camera_fw_shutdown, + .fw_set_state = camera_fw_set_state, +}; diff --git a/core/pta/qcom/pas/platform/lemans/camera.h b/core/pta/qcom/pas/platform/lemans/camera.h new file mode 100644 index 000000000..befe8f518 --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/camera.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _CAMERA_H_ +#define _CAMERA_H_ + +#include "pas_subsys.h" + +extern const struct qcom_pas_ops camera_ops; + +#endif /* _CAMERA_H_ */ diff --git a/core/pta/qcom/pas/platform/lemans/cdsp0.c b/core/pta/qcom/pas/platform/lemans/cdsp0.c new file mode 100644 index 000000000..63c91c2e7 --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/cdsp0.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cdsp0.h" + +#define TURING_NSPAUX_XO_CBCR 0x02008040 +#define TURING_Q6SS_Q6_AXIM_CBCR 0x02008404 +#define TURING_Q6SS_AXIS2_CBCR 0x0200840c + +#define TURING_QDSP6SS_CORE_CBCR 0x02348040 + +#define TURING_QDSP6SS_RST_EVB 0x02300010 +#define TURING_QDSP6SS_BOOT_CMD 0x02300404 +#define TURING_QDSP6SS_BOOT_STATUS 0x02300408 + +static const struct fw_rsc_devmem turing_mem_res[] = { + { .name = "gcc_gpll0_3", .flags = IOMMU_READ, + .da = 0x110000, .pa = 0x110000, .len = 0x4000, }, + { .name = "gcc_turing1_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x114000, .pa = 0x114000, .len = 0xf000, }, + { .name = "gcc_gpll6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x123000, .pa = 0x123000, .len = 0x1000, }, + { .name = "gcc_qupv3_wrap1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x124000, .pa = 0x124000, .len = 0x3000, }, + { .name = "gcc_qupv3_wrap0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x127000, .pa = 0x127000, .len = 0x3000, }, + { .name = "gcc_gpll7_9", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x12a000, .pa = 0x12a000, .len = 0x3000, }, + { .name = "gcc_qupv3_wrap2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x12e000, .pa = 0x12e000, .len = 0x1000, }, + { .name = "gcc_gpll10", .flags = IOMMU_READ, + .da = 0x12f000, .pa = 0x12f000, .len = 0x1000, }, + { .name = "gcc_boot_rom", .flags = IOMMU_READ, + .da = 0x144000, .pa = 0x144000, .len = 0x1000, }, + { .name = "gcc_boot_rom_ahb", .flags = IOMMU_READ, + .da = 0x148000, .pa = 0x148000, .len = 0x1000, }, + { .name = "gcc_turing0_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x149000, .pa = 0x149000, .len = 0xc000, }, + { .name = "gcc_turing0_gdscr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x155000, .pa = 0x155000, .len = 0x1000, }, + { .name = "gcc_turing_dsp_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x16b000, .pa = 0x16b000, .len = 0x1000, }, + { .name = "gcc_clk_frq_measure", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x172000, .pa = 0x172000, .len = 0x1000, }, + { .name = "gcc_turing0_pll_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x173000, .pa = 0x173000, .len = 0x11000, }, + { .name = "gcc_gpll5", .flags = IOMMU_READ, + .da = 0x184000, .pa = 0x184000, .len = 0x1000, }, + { .name = "gcc_gpll4", .flags = IOMMU_READ, + .da = 0x186000, .pa = 0x186000, .len = 0x1000, }, + { .name = "gcc_turing1_pll_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x187000, .pa = 0x187000, .len = 0x45000, }, + { .name = "gcc_turing1_gdscr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1cc000, .pa = 0x1cc000, .len = 0x1000, }, + { .name = "mproc_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x406000, .pa = 0x406000, .len = 0x1000, }, + { .name = "mproc_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x412000, .pa = 0x412000, .len = 0x1000, }, + { .name = "computel0_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x446000, .pa = 0x446000, .len = 0x1000, }, + { .name = "computel0_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x452000, .pa = 0x452000, .len = 0x1000, }, + { .name = "computel1_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x486000, .pa = 0x486000, .len = 0x1000, }, + { .name = "computel1_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x492000, .pa = 0x492000, .len = 0x1000, }, + { .name = "periph_ipc0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4c6000, .pa = 0x4c6000, .len = 0x1000, }, + { .name = "periph_ipc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4d2000, .pa = 0x4d2000, .len = 0x1000, }, + { .name = "ipc_mode", .flags = IOMMU_READ, + .da = 0x4fc000, .pa = 0x4fc000, .len = 0x1000, }, + { .name = "nspcx0_cpr3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x63a000, .pa = 0x63a000, .len = 0x4000, }, + { .name = "nsp_cprf_cprc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x63e000, .pa = 0x63e000, .len = 0x4000, }, + { .name = "oem_fuses", .flags = IOMMU_READ, + .da = 0x780000, .pa = 0x780000, .len = 0x10000, }, + { .name = "hwkm_prng_cm", .flags = IOMMU_READ, + .da = 0x10d0000, .pa = 0x10d0000, .len = 0x1000, }, + { .name = "hwkm_prng_ee10", .flags = IOMMU_READ, + .da = 0x10da000, .pa = 0x10da000, .len = 0x1000, }, + { .name = "qos_usb_ufs_pcie", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x16c2000, .pa = 0x16c2000, .len = 0x9000, }, + { .name = "qos_ufs_ipa_crypto", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1703000, .pa = 0x1703000, .len = 0x5000, }, + { .name = "hw_mutex", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1f40000, .pa = 0x1f40000, .len = 0x40000, }, + { .name = "tcsr_ro", .flags = IOMMU_READ, + .da = 0x1fc0000, .pa = 0x1fc0000, .len = 0x2b000, }, + { .name = "tcsr_timeout_intr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1feb000, .pa = 0x1feb000, .len = 0x1000, }, + { .name = "tcsr_ro2", .flags = IOMMU_READ, + .da = 0x1fec000, .pa = 0x1fec000, .len = 0x4000, }, + { .name = "tcsr_spare_rg63", .flags = IOMMU_READ, + .da = 0x1fff000, .pa = 0x1fff000, .len = 0x1000, }, + { .name = "ddr_llc_info", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9080000, .pa = 0x9080000, .len = 0x1000, }, + { .name = "bwmon0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x90b4000, .pa = 0x90b4000, .len = 0x1000, }, + { .name = "bwmon1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x90b8000, .pa = 0x90b8000, .len = 0x1000, }, + { .name = "llcc_trp0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9200000, .pa = 0x9200000, .len = 0x28000, }, + { .name = "llcc_trp1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9300000, .pa = 0x9300000, .len = 0x28000, }, + { .name = "llcc_trp2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9400000, .pa = 0x9400000, .len = 0x28000, }, + { .name = "llcc_trp3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9500000, .pa = 0x9500000, .len = 0x28000, }, + { .name = "llcc_trp4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9600000, .pa = 0x9600000, .len = 0x28000, }, + { .name = "llcc_trp5", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9700000, .pa = 0x9700000, .len = 0x28000, }, + { .name = "pdc_seq_mem0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb2c0000, .pa = 0xb2c0000, .len = 0x10000, }, + { .name = "pdc_rsc0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb2f0000, .pa = 0xb2f0000, .len = 0x10000, }, + { .name = "pdc_seq_mem1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb4c0000, .pa = 0xb4c0000, .len = 0x10000, }, + { .name = "pdc_rsc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb4f0000, .pa = 0xb4f0000, .len = 0x10000, }, + { .name = "rpmh_bcm", .flags = IOMMU_READ, + .da = 0xbbf0000, .pa = 0xbbf0000, .len = 0x2000, }, + { .name = "rpmh_cprf_nsp9", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc20a000, .pa = 0xc20a000, .len = 0x1000, }, + { .name = "rpmh_cprf_nsp10", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc20b000, .pa = 0xc20b000, .len = 0x1000, }, + { .name = "mpm", .flags = IOMMU_READ, + .da = 0xc210000, .pa = 0xc210000, .len = 0x80000, }, + { .name = "rpmh_drv_cdsp", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc330000, .pa = 0xc330000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv0", .flags = IOMMU_READ, + .da = 0xc370000, .pa = 0xc370000, .len = 0x1000, }, + { .name = "rpmh_drv8_aop", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc380000, .pa = 0xc380000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv1", .flags = IOMMU_READ, + .da = 0xc390000, .pa = 0xc390000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv2", .flags = IOMMU_READ, + .da = 0xc3a0000, .pa = 0xc3a0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv3", .flags = IOMMU_READ, + .da = 0xc3b0000, .pa = 0xc3b0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv4", .flags = IOMMU_READ, + .da = 0xc3c0000, .pa = 0xc3c0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv5", .flags = IOMMU_READ, + .da = 0xc3d0000, .pa = 0xc3d0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv6", .flags = IOMMU_READ, + .da = 0xc3e0000, .pa = 0xc3e0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv7", .flags = IOMMU_READ, + .da = 0xc3f0000, .pa = 0xc3f0000, .len = 0x1000, }, + { .name = "pmic_arb", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc440000, .pa = 0xc440000, .len = 0x10000, }, + { .name = "pmic_arb_mgpi", .flags = IOMMU_READ, + .da = 0xc460000, .pa = 0xc460000, .len = 0x81000, }, + { .name = "pmic_obs", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xe600000, .pa = 0xe600000, .len = 0x100000, }, + { .name = "spmi_pic", .flags = IOMMU_READ, + .da = 0xe700000, .pa = 0xe700000, .len = 0xa0000, }, + { .name = "tlmm", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xf000000, .pa = 0xf000000, .len = 0x1000000, }, + { .name = "sys_imem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x146d8000, .pa = 0x146d8000, .len = 0x1000, }, + { .name = "stm_trace", .flags = IOMMU_WRITE, + .da = 0x16000000, .pa = 0x16000000, .len = 0x1000000, }, + { .name = "emac1_ptp", .flags = IOMMU_READ, + .da = 0x23007000, .pa = 0x23007000, .len = 0x1000, }, + { .name = "emac0_ptp", .flags = IOMMU_READ, + .da = 0x23047000, .pa = 0x23047000, .len = 0x1000, }, + { .name = "emac_sgmii", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x2304e000, .pa = 0x2304e000, .len = 0x2000, }, + { .name = "nsp_7806", .flags = IOMMU_READ, + .da = 0x90860000, .pa = 0x90860000, .len = 0x20000, }, + /* + * SMEM holds the GLINK FIFOs the DSP uses to talk to the apps + * processor; without this mapping the DSP faults on its first + * SMEM access. + */ + { .name = "smem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x90900000, .pa = 0x90900000, .len = 0x200000, }, +}; + +DEFINE_RESOURCE_TABLE(TURING, ARRAY_SIZE(turing_mem_res)); + +#define BOOT_FSM_TIMEOUT 10000 + +/* + * Clear the CDSP0 content-protection shared channel before starting the DSP; + * stale contents block the host from talking to CDSP0. No CDSP1 equivalent. + */ +static TEE_Result cdsp0_reset_shared_channel(void) +{ + void *va = core_mmu_add_mapping(MEM_AREA_RAM_SEC, + CDSP_SECCHANNEL_BASE, + CDSP_SECCHANNEL_SIZE); + + if (!va) { + EMSG("Failed to map CDSP shared channel"); + return TEE_ERROR_GENERIC; + } + + memset(va, 0, CDSP_SECCHANNEL_SIZE); + + /* + * The channel is write-back cacheable, so flush the zeros to DDR before + * unmapping; otherwise the DSP/fastrpc may read stale cached data. + */ + dcache_clean_range(va, CDSP_SECCHANNEL_SIZE); + + if (core_mmu_remove_mapping(MEM_AREA_RAM_SEC, va, + CDSP_SECCHANNEL_SIZE)) { + EMSG("Failed to unmap CDSP shared channel"); + return TEE_ERROR_GENERIC; + } + + return TEE_SUCCESS; +} + +static TEE_Result cdsp0_fw_start(struct qcom_pas_data *data) +{ + vaddr_t base = io_pa_or_va(&data->base, data->size); + uint64_t timeout = timeout_init_us(BOOT_FSM_TIMEOUT); + TEE_Result res = TEE_SUCCESS; + + res = cdsp0_reset_shared_channel(); + if (res != TEE_SUCCESS) + return res; + + /* QDSPV73SS out of reset sequence */ + io_setbits32(base + TURING_QDSP6SS_CORE_CBCR, CBCR_BRANCH_ENABLE_BIT); + io_setbits32(base + TURING_Q6SS_Q6_AXIM_CBCR, CBCR_HW_CTL_ENABLE_BIT); + io_setbits32(base + TURING_Q6SS_AXIS2_CBCR, CBCR_HW_CTL_ENABLE_BIT); + io_setbits32(base + TURING_NSPAUX_XO_CBCR, CBCR_BRANCH_ENABLE_BIT); + + /* Program firmware */ + io_write32(base + TURING_QDSP6SS_RST_EVB, data->fw_base >> 4); + dsb(); + + /* Trigger the boot FSM. The core itself is released later, after the + * Q6 PLL is configured, by qcom_clock_enable_pas_processor(). + */ + io_write32(base + TURING_QDSP6SS_BOOT_CMD, 0x1); + + while (!timeout_elapsed(timeout)) { + if (io_read32(base + TURING_QDSP6SS_BOOT_STATUS) & BIT(0)) + return TEE_SUCCESS; + + udelay(10); + } + + return TEE_ERROR_TIMEOUT; +} + +static TEE_Result cdsp0_fw_shutdown(struct qcom_pas_data *data) +{ + return qcom_clock_pas_reset(data->clk_group); +} + +static TEE_Result cdsp0_get_resource_table(struct resource_table *rt, + size_t *rt_size) +{ + const struct fw_rsc_hdr header = { + .type = RSC_DEVMEM, + }; + static struct resource_table table = { + .ver = 1, + .num = TURING_NUM_MEM_RESOURCES, + .offset[TURING_NUM_MEM_RESOURCES - 1] = 0, + }; + + return get_mem_rsc(rt, rt_size, &table, &header, + turing_mem_res, + TURING_RESOURCE_TABLE_HEADER_SIZE, + TURING_RESOURCE_TABLE_SIZE); +} + +const struct qcom_pas_ops cdsp0_ops = { + .fw_start = cdsp0_fw_start, + .fw_shutdown = cdsp0_fw_shutdown, + .get_resource_table = cdsp0_get_resource_table, +}; diff --git a/core/pta/qcom/pas/platform/lemans/cdsp0.h b/core/pta/qcom/pas/platform/lemans/cdsp0.h new file mode 100644 index 000000000..2a0f117a8 --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/cdsp0.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _CDSP0_H_ +#define _CDSP0_H_ + +#include "pas_subsys.h" + +extern const struct qcom_pas_ops cdsp0_ops; + +#endif /* _CDSP0_H_ */ diff --git a/core/pta/qcom/pas/platform/lemans/cdsp1.c b/core/pta/qcom/pas/platform/lemans/cdsp1.c new file mode 100644 index 000000000..60c47abc7 --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/cdsp1.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include + +#include "cdsp1.h" + +#define TURING_NSPAUX_XO_CBCR 0x02008040 +#define TURING_Q6SS_Q6_AXIM_CBCR 0x02008404 +#define TURING_Q6SS_AXIS2_CBCR 0x0200840c + +#define TURING_QDSP6SS_CORE_CBCR 0x02348040 + +#define TURING_QDSP6SS_RST_EVB 0x02300010 +#define TURING_QDSP6SS_BOOT_CMD 0x02300404 +#define TURING_QDSP6SS_BOOT_STATUS 0x02300408 + +static const struct fw_rsc_devmem turing_mem_res[] = { + { .name = "gcc_gpll0_3", .flags = IOMMU_READ, + .da = 0x110000, .pa = 0x110000, .len = 0x4000, }, + { .name = "gcc_turing1_cfg", .flags = IOMMU_READ, + .da = 0x114000, .pa = 0x114000, .len = 0xf000, }, + { .name = "gcc_gpll6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x123000, .pa = 0x123000, .len = 0x1000, }, + { .name = "gcc_qupv3_wrap1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x124000, .pa = 0x124000, .len = 0x3000, }, + { .name = "gcc_qupv3_wrap0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x127000, .pa = 0x127000, .len = 0x3000, }, + { .name = "gcc_gpll7_9", .flags = IOMMU_READ, + .da = 0x12a000, .pa = 0x12a000, .len = 0x3000, }, + { .name = "gcc_qupv3_wrap2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x12e000, .pa = 0x12e000, .len = 0x1000, }, + { .name = "gcc_gpll10", .flags = IOMMU_READ, + .da = 0x12f000, .pa = 0x12f000, .len = 0x1000, }, + { .name = "gcc_boot_rom", .flags = IOMMU_READ, + .da = 0x144000, .pa = 0x144000, .len = 0x1000, }, + { .name = "gcc_boot_rom_ahb", .flags = IOMMU_READ, + .da = 0x148000, .pa = 0x148000, .len = 0x1000, }, + { .name = "gcc_turing0_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x149000, .pa = 0x149000, .len = 0xc000, }, + { .name = "gcc_turing0_gdscr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x155000, .pa = 0x155000, .len = 0x1000, }, + { .name = "gcc_turing_dsp_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x16b000, .pa = 0x16b000, .len = 0x1000, }, + { .name = "gcc_clk_frq_measure", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x172000, .pa = 0x172000, .len = 0x1000, }, + { .name = "gcc_turing0_pll_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x173000, .pa = 0x173000, .len = 0x11000, }, + { .name = "gcc_gpll5", .flags = IOMMU_READ, + .da = 0x184000, .pa = 0x184000, .len = 0x1000, }, + { .name = "gcc_gpll4", .flags = IOMMU_READ, + .da = 0x186000, .pa = 0x186000, .len = 0x1000, }, + { .name = "gcc_turing1_pll_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x187000, .pa = 0x187000, .len = 0x45000, }, + { .name = "gcc_turing1_gdscr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1cc000, .pa = 0x1cc000, .len = 0x1000, }, + { .name = "mproc_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x406000, .pa = 0x406000, .len = 0x1000, }, + { .name = "mproc_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x412000, .pa = 0x412000, .len = 0x1000, }, + { .name = "computel0_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x446000, .pa = 0x446000, .len = 0x1000, }, + { .name = "computel0_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x452000, .pa = 0x452000, .len = 0x1000, }, + { .name = "computel1_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x486000, .pa = 0x486000, .len = 0x1000, }, + { .name = "computel1_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x492000, .pa = 0x492000, .len = 0x1000, }, + { .name = "periph_ipc0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4c6000, .pa = 0x4c6000, .len = 0x1000, }, + { .name = "periph_ipc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4d2000, .pa = 0x4d2000, .len = 0x1000, }, + { .name = "ipc_mode", .flags = IOMMU_READ, + .da = 0x4fc000, .pa = 0x4fc000, .len = 0x1000, }, + { .name = "nsp_cprf_cprc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x63e000, .pa = 0x63e000, .len = 0x4000, }, + { .name = "oem_fuses", .flags = IOMMU_READ, + .da = 0x780000, .pa = 0x780000, .len = 0x10000, }, + { .name = "hwkm_prng_cm", .flags = IOMMU_READ, + .da = 0x10d0000, .pa = 0x10d0000, .len = 0x1000, }, + { .name = "hwkm_prng_ee10", .flags = IOMMU_READ, + .da = 0x10da000, .pa = 0x10da000, .len = 0x1000, }, + { .name = "qos_usb_ufs_pcie", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x16c2000, .pa = 0x16c2000, .len = 0x9000, }, + { .name = "qos_ufs_ipa_crypto", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1703000, .pa = 0x1703000, .len = 0x5000, }, + { .name = "hw_mutex", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1f40000, .pa = 0x1f40000, .len = 0x40000, }, + { .name = "tcsr_ro", .flags = IOMMU_READ, + .da = 0x1fc0000, .pa = 0x1fc0000, .len = 0x2b000, }, + { .name = "tcsr_timeout_intr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1feb000, .pa = 0x1feb000, .len = 0x1000, }, + { .name = "tcsr_ro2", .flags = IOMMU_READ, + .da = 0x1fec000, .pa = 0x1fec000, .len = 0x4000, }, + { .name = "tcsr_spare_rg63", .flags = IOMMU_READ, + .da = 0x1fff000, .pa = 0x1fff000, .len = 0x1000, }, + { .name = "ddr_llc_info", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9080000, .pa = 0x9080000, .len = 0x1000, }, + { .name = "bwmon0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x90b4000, .pa = 0x90b4000, .len = 0x1000, }, + { .name = "llcc_trp0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9200000, .pa = 0x9200000, .len = 0x28000, }, + { .name = "llcc_trp1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9300000, .pa = 0x9300000, .len = 0x28000, }, + { .name = "llcc_trp2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9400000, .pa = 0x9400000, .len = 0x28000, }, + { .name = "llcc_trp3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9500000, .pa = 0x9500000, .len = 0x28000, }, + { .name = "llcc_trp4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9600000, .pa = 0x9600000, .len = 0x28000, }, + { .name = "llcc_trp5", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9700000, .pa = 0x9700000, .len = 0x28000, }, + { .name = "pdc_seq_mem0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb2c0000, .pa = 0xb2c0000, .len = 0x10000, }, + { .name = "pdc_rsc0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb2f0000, .pa = 0xb2f0000, .len = 0x10000, }, + { .name = "pdc_seq_mem1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb4c0000, .pa = 0xb4c0000, .len = 0x10000, }, + { .name = "pdc_rsc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb4f0000, .pa = 0xb4f0000, .len = 0x10000, }, + { .name = "rpmh_bcm", .flags = IOMMU_READ, + .da = 0xbbf0000, .pa = 0xbbf0000, .len = 0x2000, }, + { .name = "rpmh_cprf_nsp9", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc20a000, .pa = 0xc20a000, .len = 0x1000, }, + { .name = "rpmh_cprf_nsp10", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc20b000, .pa = 0xc20b000, .len = 0x1000, }, + { .name = "mpm", .flags = IOMMU_READ, + .da = 0xc210000, .pa = 0xc210000, .len = 0x80000, }, + { .name = "rpmh_drv_cdsp", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc330000, .pa = 0xc330000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv0", .flags = IOMMU_READ, + .da = 0xc370000, .pa = 0xc370000, .len = 0x1000, }, + { .name = "rpmh_drv8_aop", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc380000, .pa = 0xc380000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv1", .flags = IOMMU_READ, + .da = 0xc390000, .pa = 0xc390000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv2", .flags = IOMMU_READ, + .da = 0xc3a0000, .pa = 0xc3a0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv3", .flags = IOMMU_READ, + .da = 0xc3b0000, .pa = 0xc3b0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv4", .flags = IOMMU_READ, + .da = 0xc3c0000, .pa = 0xc3c0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv5", .flags = IOMMU_READ, + .da = 0xc3d0000, .pa = 0xc3d0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv6", .flags = IOMMU_READ, + .da = 0xc3e0000, .pa = 0xc3e0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv7", .flags = IOMMU_READ, + .da = 0xc3f0000, .pa = 0xc3f0000, .len = 0x1000, }, + { .name = "pmic_arb_master", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc400000, .pa = 0xc400000, .len = 0x30000, }, + { .name = "pmic_arb", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc440000, .pa = 0xc440000, .len = 0x10000, }, + { .name = "pmic_arb_mgpi", .flags = IOMMU_READ, + .da = 0xc460000, .pa = 0xc460000, .len = 0x81000, }, + { .name = "pmic_obs", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xe600000, .pa = 0xe600000, .len = 0x100000, }, + { .name = "spmi_pic", .flags = IOMMU_READ, + .da = 0xe700000, .pa = 0xe700000, .len = 0xa0000, }, + { .name = "tlmm", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xf000000, .pa = 0xf000000, .len = 0x1000000, }, + { .name = "shared_imem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x146bf000, .pa = 0x146bf000, .len = 0x1000, }, + { .name = "sys_imem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x146d8000, .pa = 0x146d8000, .len = 0x1000, }, + { .name = "stm_trace", .flags = IOMMU_WRITE, + .da = 0x16000000, .pa = 0x16000000, .len = 0x1000000, }, + { .name = "emac1_ptp", .flags = IOMMU_READ, + .da = 0x23007000, .pa = 0x23007000, .len = 0x1000, }, + { .name = "emac0_ptp", .flags = IOMMU_READ, + .da = 0x23047000, .pa = 0x23047000, .len = 0x1000, }, + { .name = "emac_sgmii", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x2304e000, .pa = 0x2304e000, .len = 0x1000, }, + { .name = "nsp_7806", .flags = IOMMU_READ, + .da = 0x90860000, .pa = 0x90860000, .len = 0x20000, }, + /* + * SMEM holds the GLINK FIFOs the DSP uses to talk to the apps + * processor; without this mapping the DSP faults on its first + * SMEM access. + */ + { .name = "smem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x90900000, .pa = 0x90900000, .len = 0x200000, }, +}; + +DEFINE_RESOURCE_TABLE(TURING1, ARRAY_SIZE(turing_mem_res)); + +#define BOOT_FSM_TIMEOUT 10000 + +static TEE_Result cdsp1_fw_start(struct qcom_pas_data *data) +{ + vaddr_t base = io_pa_or_va(&data->base, data->size); + uint64_t timeout = timeout_init_us(BOOT_FSM_TIMEOUT); + + /* QDSPV73SS out of reset sequence */ + io_setbits32(base + TURING_QDSP6SS_CORE_CBCR, CBCR_BRANCH_ENABLE_BIT); + io_setbits32(base + TURING_Q6SS_Q6_AXIM_CBCR, CBCR_HW_CTL_ENABLE_BIT); + io_setbits32(base + TURING_Q6SS_AXIS2_CBCR, CBCR_HW_CTL_ENABLE_BIT); + io_setbits32(base + TURING_NSPAUX_XO_CBCR, CBCR_BRANCH_ENABLE_BIT); + + /* Program firmware */ + io_write32(base + TURING_QDSP6SS_RST_EVB, data->fw_base >> 4); + dsb(); + + /* Trigger the boot FSM. The core itself is released later, after the + * Q6 PLL is configured, by qcom_clock_enable_pas_processor(). + */ + io_write32(base + TURING_QDSP6SS_BOOT_CMD, 0x1); + + while (!timeout_elapsed(timeout)) { + if (io_read32(base + TURING_QDSP6SS_BOOT_STATUS) & BIT(0)) + return TEE_SUCCESS; + + udelay(10); + } + + return TEE_ERROR_TIMEOUT; +} + +static TEE_Result cdsp1_fw_shutdown(struct qcom_pas_data *data) +{ + return qcom_clock_pas_reset(data->clk_group); +} + +static TEE_Result cdsp1_get_resource_table(struct resource_table *rt, + size_t *rt_size) +{ + const struct fw_rsc_hdr header = { + .type = RSC_DEVMEM, + }; + static struct resource_table table = { + .ver = 1, + .num = TURING1_NUM_MEM_RESOURCES, + .offset[TURING1_NUM_MEM_RESOURCES - 1] = 0, + }; + + return get_mem_rsc(rt, rt_size, &table, &header, + turing_mem_res, + TURING1_RESOURCE_TABLE_HEADER_SIZE, + TURING1_RESOURCE_TABLE_SIZE); +} + +const struct qcom_pas_ops cdsp1_ops = { + .fw_start = cdsp1_fw_start, + .fw_shutdown = cdsp1_fw_shutdown, + .get_resource_table = cdsp1_get_resource_table, +}; diff --git a/core/pta/qcom/pas/platform/lemans/cdsp1.h b/core/pta/qcom/pas/platform/lemans/cdsp1.h new file mode 100644 index 000000000..18988bb20 --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/cdsp1.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _CDSP1_H_ +#define _CDSP1_H_ + +#include "pas_subsys.h" + +extern const struct qcom_pas_ops cdsp1_ops; + +#endif /* _CDSP1_H_ */ diff --git a/core/pta/qcom/pas/platform/lemans/gpdsp0.c b/core/pta/qcom/pas/platform/lemans/gpdsp0.c new file mode 100644 index 000000000..c4a636e6b --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/gpdsp0.c @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include + +#include "gpdsp0.h" + +#define GPDSP_QDSP6SS_RST_EVB 0x00c00010 +#define GPDSP_QDSP6SS_BOOT_CORE_START 0x00c00400 +#define GPDSP_QDSP6SS_BOOT_CMD 0x00c00404 +#define GPDSP_QDSP6SS_BOOT_STATUS 0x00c00408 + +static const struct fw_rsc_devmem turing_mem_res[] = { + { .name = "gcc_gpll0_3", .flags = IOMMU_READ, + .da = 0x110000, .pa = 0x110000, .len = 0x4000, }, + { .name = "gcc_gpll6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x123000, .pa = 0x123000, .len = 0x1000, }, + { .name = "gcc_qupv3_wrap1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x124000, .pa = 0x124000, .len = 0x3000, }, + { .name = "gcc_qupv3_wrap0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x127000, .pa = 0x127000, .len = 0x3000, }, + { .name = "gcc_gpll7_9", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x12a000, .pa = 0x12a000, .len = 0x3000, }, + { .name = "gcc_qupv3_wrap2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x12e000, .pa = 0x12e000, .len = 0x1000, }, + { .name = "gcc_gpll10", .flags = IOMMU_READ, + .da = 0x12f000, .pa = 0x12f000, .len = 0x1000, }, + { .name = "gcc_boot_rom", .flags = IOMMU_READ, + .da = 0x144000, .pa = 0x144000, .len = 0x1000, }, + { .name = "gcc_boot_rom_ahb", .flags = IOMMU_READ, + .da = 0x148000, .pa = 0x148000, .len = 0x1000, }, + { .name = "gcc_gpdsp0_gdscr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x155000, .pa = 0x155000, .len = 0x1000, }, + { .name = "gcc_gpdsp0_pll_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x156000, .pa = 0x156000, .len = 0x15000, }, + { .name = "gcc_gpdsp_dsp_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x16b000, .pa = 0x16b000, .len = 0x1000, }, + { .name = "gcc_clk_frq_measure", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x172000, .pa = 0x172000, .len = 0x1000, }, + { .name = "gcc_gpll5", .flags = IOMMU_READ, + .da = 0x184000, .pa = 0x184000, .len = 0x1000, }, + { .name = "gcc_gpll4", .flags = IOMMU_READ, + .da = 0x186000, .pa = 0x186000, .len = 0x1000, }, + { .name = "gcc_gpdsp0_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1c4000, .pa = 0x1c4000, .len = 0x1000, }, + { .name = "gcc_gpdsp1_gdscr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1cc000, .pa = 0x1cc000, .len = 0x1000, }, + { .name = "mproc_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x406000, .pa = 0x406000, .len = 0x1000, }, + { .name = "mproc_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x412000, .pa = 0x412000, .len = 0x1000, }, + { .name = "mproc_ipc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x41f000, .pa = 0x41f000, .len = 0x1000, }, + { .name = "computel0_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x446000, .pa = 0x446000, .len = 0x1000, }, + { .name = "computel0_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x452000, .pa = 0x452000, .len = 0x1000, }, + { .name = "computel0_ipc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x45f000, .pa = 0x45f000, .len = 0x1000, }, + { .name = "computel1_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x486000, .pa = 0x486000, .len = 0x1000, }, + { .name = "computel1_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x492000, .pa = 0x492000, .len = 0x1000, }, + { .name = "computel1_ipc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x49f000, .pa = 0x49f000, .len = 0x1000, }, + { .name = "periph_ipc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4d2000, .pa = 0x4d2000, .len = 0x1000, }, + { .name = "periph_ipc2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4df000, .pa = 0x4df000, .len = 0x1000, }, + { .name = "ipc_mode", .flags = IOMMU_READ, + .da = 0x4fc000, .pa = 0x4fc000, .len = 0x1000, }, + { .name = "oem_fuses", .flags = IOMMU_READ, + .da = 0x780000, .pa = 0x780000, .len = 0x10000, }, + { .name = "hwkm_prng_cm", .flags = IOMMU_READ, + .da = 0x10d0000, .pa = 0x10d0000, .len = 0x1000, }, + { .name = "hwkm_prng_ee7", .flags = IOMMU_READ, + .da = 0x10d7000, .pa = 0x10d7000, .len = 0x1000, }, + { .name = "qos_usb_ufs_pcie", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x16c2000, .pa = 0x16c2000, .len = 0x9000, }, + { .name = "qos_ufs_ipa_crypto", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1703000, .pa = 0x1703000, .len = 0x5000, }, + { .name = "qos_misc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x178d000, .pa = 0x178d000, .len = 0x1000, }, + { .name = "hw_mutex", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1f40000, .pa = 0x1f40000, .len = 0x40000, }, + { .name = "tcsr_rw", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1fc0000, .pa = 0x1fc0000, .len = 0x9000, }, + { .name = "tcsr_ro", .flags = IOMMU_READ, + .da = 0x1fc9000, .pa = 0x1fc9000, .len = 0x22000, }, + { .name = "tcsr_timeout_intr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1feb000, .pa = 0x1feb000, .len = 0x1000, }, + { .name = "tcsr_ro2", .flags = IOMMU_READ, + .da = 0x1fec000, .pa = 0x1fec000, .len = 0x4000, }, + { .name = "tcsr_spare", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1ffb000, .pa = 0x1ffb000, .len = 0x1000, }, + { .name = "lpass_lpm0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3140000, .pa = 0x3140000, .len = 0x29000, }, + { .name = "lpass_lpm1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3180000, .pa = 0x3180000, .len = 0x29000, }, + { .name = "lpass_lpm2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3260000, .pa = 0x3260000, .len = 0x10000, }, + { .name = "lpass_lpm3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3280000, .pa = 0x3280000, .len = 0x29000, }, + { .name = "lpass_lpm4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x32c0000, .pa = 0x32c0000, .len = 0x29000, }, + { .name = "lpass_lpm5", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x33c0000, .pa = 0x33c0000, .len = 0x29000, }, + { .name = "lpass_lpm6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x33ec000, .pa = 0x33ec000, .len = 0x3000, }, + { .name = "lpass_lpm7", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3a10000, .pa = 0x3a10000, .len = 0x8000, }, + { .name = "lpass_lpm8", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3b00000, .pa = 0x3b00000, .len = 0x29000, }, + { .name = "lpass_lpm9", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3b40000, .pa = 0x3b40000, .len = 0x29000, }, + { .name = "lpass_core0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4001000, .pa = 0x4001000, .len = 0x1000, }, + { .name = "lpass_core1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4002000, .pa = 0x4002000, .len = 0x1000, }, + { .name = "lpass_core2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4041000, .pa = 0x4041000, .len = 0x1000, }, + { .name = "lpass_core3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4042000, .pa = 0x4042000, .len = 0x1000, }, + { .name = "lpass_core4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4043000, .pa = 0x4043000, .len = 0x1000, }, + { .name = "lpass_core5", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4045000, .pa = 0x4045000, .len = 0x1000, }, + { .name = "lpass_core6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4046000, .pa = 0x4046000, .len = 0x1000, }, + { .name = "lpass_core7", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4048000, .pa = 0x4048000, .len = 0x1000, }, + { .name = "ddr_llc_info", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9080000, .pa = 0x9080000, .len = 0x1000, }, + { .name = "llcc_trp0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9200000, .pa = 0x9200000, .len = 0x28000, }, + { .name = "llcc_trp1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9300000, .pa = 0x9300000, .len = 0x28000, }, + { .name = "llcc_trp2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9400000, .pa = 0x9400000, .len = 0x28000, }, + { .name = "llcc_trp3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9500000, .pa = 0x9500000, .len = 0x28000, }, + { .name = "llcc_trp4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9600000, .pa = 0x9600000, .len = 0x28000, }, + { .name = "llcc_trp5", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9700000, .pa = 0x9700000, .len = 0x28000, }, + { .name = "llcc_trp6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9a00000, .pa = 0x9a00000, .len = 0x28000, }, + { .name = "pdc_seq_mem_a", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb240000, .pa = 0xb240000, .len = 0x10000, }, + { .name = "pdc_seq_mem0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb2c0000, .pa = 0xb2c0000, .len = 0x10000, }, + { .name = "pdc_rsc0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb2f0000, .pa = 0xb2f0000, .len = 0x10000, }, + { .name = "pdc_seq_mem1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb440000, .pa = 0xb440000, .len = 0x10000, }, + { .name = "pdc_seq_mem2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb4c0000, .pa = 0xb4c0000, .len = 0x10000, }, + { .name = "pdc_rsc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb4f0000, .pa = 0xb4f0000, .len = 0x10000, }, + { .name = "rpmh_bcm", .flags = IOMMU_READ, + .da = 0xbbf0000, .pa = 0xbbf0000, .len = 0x2000, }, + { .name = "mpm", .flags = IOMMU_READ, + .da = 0xc210000, .pa = 0xc210000, .len = 0x80000, }, + { .name = "rpmh_drv_gpdsp", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc330000, .pa = 0xc330000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc350000, .pa = 0xc350000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv1", .flags = IOMMU_READ, + .da = 0xc370000, .pa = 0xc370000, .len = 0x1000, }, + { .name = "rpmh_drv8_aop", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc380000, .pa = 0xc380000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv2", .flags = IOMMU_READ, + .da = 0xc390000, .pa = 0xc390000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv3", .flags = IOMMU_READ, + .da = 0xc3a0000, .pa = 0xc3a0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv4", .flags = IOMMU_READ, + .da = 0xc3b0000, .pa = 0xc3b0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv5", .flags = IOMMU_READ, + .da = 0xc3c0000, .pa = 0xc3c0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv6", .flags = IOMMU_READ, + .da = 0xc3d0000, .pa = 0xc3d0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv7", .flags = IOMMU_READ, + .da = 0xc3e0000, .pa = 0xc3e0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv8", .flags = IOMMU_READ, + .da = 0xc3f0000, .pa = 0xc3f0000, .len = 0x1000, }, + { .name = "pmic_arb_master", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc400000, .pa = 0xc400000, .len = 0x30000, }, + { .name = "pmic_arb", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc440000, .pa = 0xc440000, .len = 0x10000, }, + { .name = "pmic_arb_mgpi", .flags = IOMMU_READ, + .da = 0xc460000, .pa = 0xc460000, .len = 0x81000, }, + { .name = "pmic_obs", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xe600000, .pa = 0xe600000, .len = 0x100000, }, + { .name = "spmi_pic", .flags = IOMMU_READ, + .da = 0xe700000, .pa = 0xe700000, .len = 0xa0000, }, + { .name = "tlmm", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xf000000, .pa = 0xf000000, .len = 0x1000000, }, + { .name = "sys_imem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x146d8000, .pa = 0x146d8000, .len = 0x1000, }, + { .name = "stm_trace", .flags = IOMMU_WRITE, + .da = 0x16000000, .pa = 0x16000000, .len = 0x1000000, }, + /* GP-DSP0 exclusive DDR (RW to GPDSP0 only) */ + { .name = "gpdsp0_ddr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x20000000, .pa = 0x20000000, .len = 0x1000000, }, + { .name = "emac0", .flags = IOMMU_READ, + .da = 0x23000000, .pa = 0x23000000, .len = 0x30000, }, + { .name = "emac1", .flags = IOMMU_READ, + .da = 0x23040000, .pa = 0x23040000, .len = 0x30000, }, + { .name = "nsp_7806", .flags = IOMMU_READ, + .da = 0x90860000, .pa = 0x90860000, .len = 0x20000, }, + /* SMEM (smem@90900000, 2 MB) holds the GLINK FIFOs the DSP must + * read/write to talk to the apps processor. Without this mapping the + * DSP takes a translation fault on its first SMEM access (e.g. iova + * 0x90aff330) -> mmufault/watchdog and never reaches running. + */ + { .name = "smem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x90900000, .pa = 0x90900000, .len = 0x200000, }, +}; + +DEFINE_RESOURCE_TABLE(GPDSP0, ARRAY_SIZE(turing_mem_res)); + +#define BOOT_FSM_TIMEOUT 10000 + +static TEE_Result gpdsp0_fw_start(struct qcom_pas_data *data) +{ + vaddr_t base = io_pa_or_va(&data->base, data->size); + uint64_t timeout = timeout_init_us(BOOT_FSM_TIMEOUT); + + /* Program firmware entry; clocks/PLL are set up by the clock driver. */ + io_write32(base + GPDSP_QDSP6SS_RST_EVB, data->fw_base >> 4); + dsb(); + + /* + * De-assert stop-core, then trigger the boot FSM. The Q6 PLL and core + * RCG were already configured by gpdsp_setup() in the clock driver. + */ + io_setbits32(base + GPDSP_QDSP6SS_BOOT_CORE_START, BIT(0)); + udelay(5); + io_write32(base + GPDSP_QDSP6SS_BOOT_CMD, 0x1); + + while (!timeout_elapsed(timeout)) { + if (io_read32(base + GPDSP_QDSP6SS_BOOT_STATUS) & BIT(0)) + return TEE_SUCCESS; + + udelay(10); + } + + return TEE_ERROR_TIMEOUT; +} + +static TEE_Result gpdsp0_fw_shutdown(struct qcom_pas_data *data) +{ + return qcom_clock_pas_reset(data->clk_group); +} + +static TEE_Result gpdsp0_get_resource_table(struct resource_table *rt, + size_t *rt_size) +{ + const struct fw_rsc_hdr header = { + .type = RSC_DEVMEM, + }; + static struct resource_table table = { + .ver = 1, + .num = GPDSP0_NUM_MEM_RESOURCES, + .offset[GPDSP0_NUM_MEM_RESOURCES - 1] = 0, + }; + + return get_mem_rsc(rt, rt_size, &table, &header, + turing_mem_res, + GPDSP0_RESOURCE_TABLE_HEADER_SIZE, + GPDSP0_RESOURCE_TABLE_SIZE); +} + +const struct qcom_pas_ops gpdsp0_ops = { + .fw_start = gpdsp0_fw_start, + .fw_shutdown = gpdsp0_fw_shutdown, + .get_resource_table = gpdsp0_get_resource_table, +}; diff --git a/core/pta/qcom/pas/platform/lemans/gpdsp0.h b/core/pta/qcom/pas/platform/lemans/gpdsp0.h new file mode 100644 index 000000000..cbcceab92 --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/gpdsp0.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _GPDSP0_H_ +#define _GPDSP0_H_ + +#include "pas_subsys.h" + +extern const struct qcom_pas_ops gpdsp0_ops; + +#endif /* _GPDSP0_H_ */ diff --git a/core/pta/qcom/pas/platform/lemans/gpdsp1.c b/core/pta/qcom/pas/platform/lemans/gpdsp1.c new file mode 100644 index 000000000..c2d4303ca --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/gpdsp1.c @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include + +#include "gpdsp1.h" + +#define GPDSP_QDSP6SS_RST_EVB 0x00c00010 +#define GPDSP_QDSP6SS_BOOT_CORE_START 0x00c00400 +#define GPDSP_QDSP6SS_BOOT_CMD 0x00c00404 +#define GPDSP_QDSP6SS_BOOT_STATUS 0x00c00408 + +static const struct fw_rsc_devmem turing_mem_res[] = { + { .name = "gcc_gpll0_3", .flags = IOMMU_READ, + .da = 0x110000, .pa = 0x110000, .len = 0x4000, }, + { .name = "gcc_gpll6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x123000, .pa = 0x123000, .len = 0x1000, }, + { .name = "gcc_qupv3_wrap1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x124000, .pa = 0x124000, .len = 0x3000, }, + { .name = "gcc_qupv3_wrap0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x127000, .pa = 0x127000, .len = 0x3000, }, + { .name = "gcc_gpll7_9", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x12a000, .pa = 0x12a000, .len = 0x3000, }, + { .name = "gcc_qupv3_wrap2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x12e000, .pa = 0x12e000, .len = 0x1000, }, + { .name = "gcc_gpll10", .flags = IOMMU_READ, + .da = 0x12f000, .pa = 0x12f000, .len = 0x1000, }, + { .name = "gcc_boot_rom", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x144000, .pa = 0x144000, .len = 0x1000, }, + { .name = "gcc_boot_rom_ahb", .flags = IOMMU_READ, + .da = 0x148000, .pa = 0x148000, .len = 0x1000, }, + { .name = "gcc_gpdsp0_gdscr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x155000, .pa = 0x155000, .len = 0x1000, }, + { .name = "gcc_gpdsp_dsp_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x16b000, .pa = 0x16b000, .len = 0x1000, }, + { .name = "gcc_clk_frq_measure", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x172000, .pa = 0x172000, .len = 0x1000, }, + { .name = "gcc_gpdsp1_pll_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x173000, .pa = 0x173000, .len = 0x11000, }, + { .name = "gcc_gpll5", .flags = IOMMU_READ, + .da = 0x184000, .pa = 0x184000, .len = 0x1000, }, + { .name = "gcc_gpll4", .flags = IOMMU_READ, + .da = 0x186000, .pa = 0x186000, .len = 0x1000, }, + { .name = "gcc_gpdsp1_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1c4000, .pa = 0x1c4000, .len = 0x1000, }, + { .name = "gcc_gpdsp1_gdscr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1cc000, .pa = 0x1cc000, .len = 0x1000, }, + { .name = "mproc_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x406000, .pa = 0x406000, .len = 0x1000, }, + { .name = "mproc_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x412000, .pa = 0x412000, .len = 0x1000, }, + { .name = "mproc_ipc2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x41f000, .pa = 0x41f000, .len = 0x1000, }, + { .name = "mproc_ipc3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x420000, .pa = 0x420000, .len = 0x1000, }, + { .name = "computel0_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x446000, .pa = 0x446000, .len = 0x1000, }, + { .name = "computel0_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x452000, .pa = 0x452000, .len = 0x1000, }, + { .name = "computel0_ipc2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x45f000, .pa = 0x45f000, .len = 0x1000, }, + { .name = "computel0_ipc3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x460000, .pa = 0x460000, .len = 0x26000, }, + { .name = "computel1_ipc_cfg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x486000, .pa = 0x486000, .len = 0x1000, }, + { .name = "computel1_ipc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x492000, .pa = 0x492000, .len = 0x1000, }, + { .name = "computel1_ipc2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x49f000, .pa = 0x49f000, .len = 0x1000, }, + { .name = "computel1_ipc3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4a0000, .pa = 0x4a0000, .len = 0x32000, }, + { .name = "periph_ipc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4d2000, .pa = 0x4d2000, .len = 0x1000, }, + { .name = "periph_ipc2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4df000, .pa = 0x4df000, .len = 0x1000, }, + { .name = "periph_ipc3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4e0000, .pa = 0x4e0000, .len = 0x1c000, }, + { .name = "ipc_mode", .flags = IOMMU_READ, + .da = 0x4fc000, .pa = 0x4fc000, .len = 0x1000, }, + { .name = "oem_fuses", .flags = IOMMU_READ, + .da = 0x780000, .pa = 0x780000, .len = 0x10000, }, + { .name = "hwkm_prng_cm", .flags = IOMMU_READ, + .da = 0x10d0000, .pa = 0x10d0000, .len = 0x1000, }, + { .name = "hwkm_prng_ee", .flags = IOMMU_READ, + .da = 0x10d9000, .pa = 0x10d9000, .len = 0x1000, }, + { .name = "qos_usb_ufs_pcie", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x16c2000, .pa = 0x16c2000, .len = 0x9000, }, + { .name = "qos_ufs_ipa_crypto", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1703000, .pa = 0x1703000, .len = 0x5000, }, + { .name = "qos_misc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x178e000, .pa = 0x178e000, .len = 0x1000, }, + { .name = "hw_mutex", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1f40000, .pa = 0x1f40000, .len = 0x40000, }, + { .name = "tcsr_regs", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1fc0000, .pa = 0x1fc0000, .len = 0x9000, }, + { .name = "tcsr_ro", .flags = IOMMU_READ, + .da = 0x1fc9000, .pa = 0x1fc9000, .len = 0x22000, }, + { .name = "tcsr_timeout_intr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1feb000, .pa = 0x1feb000, .len = 0x1000, }, + { .name = "tcsr_ro2", .flags = IOMMU_READ, + .da = 0x1fec000, .pa = 0x1fec000, .len = 0x4000, }, + { .name = "tcsr_spare", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1ffb000, .pa = 0x1ffb000, .len = 0x1000, }, + { .name = "lpass_lpm0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3140000, .pa = 0x3140000, .len = 0x29000, }, + { .name = "lpass_lpm1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3180000, .pa = 0x3180000, .len = 0x29000, }, + { .name = "lpass_lpm2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3260000, .pa = 0x3260000, .len = 0x10000, }, + { .name = "lpass_lpm3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3280000, .pa = 0x3280000, .len = 0x29000, }, + { .name = "lpass_lpm4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x32c0000, .pa = 0x32c0000, .len = 0x29000, }, + { .name = "lpass_lpm5", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x33c0000, .pa = 0x33c0000, .len = 0x29000, }, + { .name = "lpass_lpm6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x33ec000, .pa = 0x33ec000, .len = 0x3000, }, + { .name = "lpass_lpm7", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3a10000, .pa = 0x3a10000, .len = 0x8000, }, + { .name = "lpass_lpm8", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3b00000, .pa = 0x3b00000, .len = 0x29000, }, + { .name = "lpass_lpm9", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3b40000, .pa = 0x3b40000, .len = 0x29000, }, + { .name = "lpass_core0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4001000, .pa = 0x4001000, .len = 0x1000, }, + { .name = "lpass_core1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4002000, .pa = 0x4002000, .len = 0x1000, }, + { .name = "lpass_core2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4041000, .pa = 0x4041000, .len = 0x1000, }, + { .name = "lpass_core3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4042000, .pa = 0x4042000, .len = 0x1000, }, + { .name = "lpass_core4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4043000, .pa = 0x4043000, .len = 0x1000, }, + { .name = "lpass_core5", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4045000, .pa = 0x4045000, .len = 0x1000, }, + { .name = "lpass_core6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4046000, .pa = 0x4046000, .len = 0x1000, }, + { .name = "lpass_core7", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4048000, .pa = 0x4048000, .len = 0x1000, }, + { .name = "ddr_llc_info", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9080000, .pa = 0x9080000, .len = 0x1000, }, + { .name = "llcc_trp0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9200000, .pa = 0x9200000, .len = 0x28000, }, + { .name = "llcc_trp1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9300000, .pa = 0x9300000, .len = 0x28000, }, + { .name = "llcc_trp2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9400000, .pa = 0x9400000, .len = 0x28000, }, + { .name = "llcc_trp3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9500000, .pa = 0x9500000, .len = 0x28000, }, + { .name = "llcc_trp4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9600000, .pa = 0x9600000, .len = 0x28000, }, + { .name = "llcc_trp5", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9700000, .pa = 0x9700000, .len = 0x28000, }, + { .name = "llcc_trp6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9a00000, .pa = 0x9a00000, .len = 0x28000, }, + { .name = "pdc_seq_mem0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb2c0000, .pa = 0xb2c0000, .len = 0x10000, }, + { .name = "pdc_gpdsp1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb2d0000, .pa = 0xb2d0000, .len = 0x10000, }, + { .name = "pdc_rsc0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb2f0000, .pa = 0xb2f0000, .len = 0x10000, }, + { .name = "pdc_seq_mem1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb4c0000, .pa = 0xb4c0000, .len = 0x10000, }, + { .name = "pdc_gpdsp1_b", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb4d0000, .pa = 0xb4d0000, .len = 0x10000, }, + { .name = "pdc_rsc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb4f0000, .pa = 0xb4f0000, .len = 0x10000, }, + { .name = "rpmh_bcm", .flags = IOMMU_READ, + .da = 0xbbf0000, .pa = 0xbbf0000, .len = 0x2000, }, + { .name = "mpm", .flags = IOMMU_READ, + .da = 0xc210000, .pa = 0xc210000, .len = 0x80000, }, + { .name = "rpmh_drv_gpdsp", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc310000, .pa = 0xc310000, .len = 0x1000, }, + { .name = "rpmh_drv_cdsp", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc330000, .pa = 0xc330000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv0", .flags = IOMMU_READ, + .da = 0xc370000, .pa = 0xc370000, .len = 0x1000, }, + { .name = "rpmh_drv8_aop", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc380000, .pa = 0xc380000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv1", .flags = IOMMU_READ, + .da = 0xc390000, .pa = 0xc390000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv2", .flags = IOMMU_READ, + .da = 0xc3a0000, .pa = 0xc3a0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv3", .flags = IOMMU_READ, + .da = 0xc3b0000, .pa = 0xc3b0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv4", .flags = IOMMU_READ, + .da = 0xc3c0000, .pa = 0xc3c0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv5", .flags = IOMMU_READ, + .da = 0xc3d0000, .pa = 0xc3d0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv6", .flags = IOMMU_READ, + .da = 0xc3e0000, .pa = 0xc3e0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv7", .flags = IOMMU_READ, + .da = 0xc3f0000, .pa = 0xc3f0000, .len = 0x1000, }, + { .name = "pmic_arb_master", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc400000, .pa = 0xc400000, .len = 0x30000, }, + { .name = "pmic_arb", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc440000, .pa = 0xc440000, .len = 0x10000, }, + { .name = "pmic_arb_mgpi", .flags = IOMMU_READ, + .da = 0xc460000, .pa = 0xc460000, .len = 0x81000, }, + { .name = "pmic_obs", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xe600000, .pa = 0xe600000, .len = 0x100000, }, + { .name = "spmi_pic", .flags = IOMMU_READ, + .da = 0xe700000, .pa = 0xe700000, .len = 0xa0000, }, + { .name = "tlmm", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xf000000, .pa = 0xf000000, .len = 0x1000000, }, + { .name = "sys_imem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x146d8000, .pa = 0x146d8000, .len = 0x1000, }, + { .name = "stm_trace", .flags = IOMMU_WRITE, + .da = 0x16000000, .pa = 0x16000000, .len = 0x1000000, }, + /* GP-DSP1 exclusive DDR (RW to GPDSP1 only) */ + { .name = "gpdsp1_ddr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x21000000, .pa = 0x21000000, .len = 0x1000000, }, + { .name = "emac1", .flags = IOMMU_READ, + .da = 0x23000000, .pa = 0x23000000, .len = 0x30000, }, + { .name = "emac0", .flags = IOMMU_READ, + .da = 0x23040000, .pa = 0x23040000, .len = 0x30000, }, + { .name = "nsp_7806", .flags = IOMMU_READ, + .da = 0x90860000, .pa = 0x90860000, .len = 0x20000, }, + /* SMEM (smem@90900000, 2 MB) holds the GLINK FIFOs the DSP must + * read/write to talk to the apps processor. Without this mapping the + * DSP takes a translation fault on its first SMEM access (e.g. iova + * 0x90aff330) -> mmufault/watchdog and never reaches running. + */ + { .name = "smem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x90900000, .pa = 0x90900000, .len = 0x200000, }, +}; + +DEFINE_RESOURCE_TABLE(GPDSP1, ARRAY_SIZE(turing_mem_res)); + +#define BOOT_FSM_TIMEOUT 10000 + +static TEE_Result gpdsp1_fw_start(struct qcom_pas_data *data) +{ + vaddr_t base = io_pa_or_va(&data->base, data->size); + uint64_t timeout = timeout_init_us(BOOT_FSM_TIMEOUT); + + /* Program firmware entry; clocks/PLL are set up by the clock driver. */ + io_write32(base + GPDSP_QDSP6SS_RST_EVB, data->fw_base >> 4); + dsb(); + + /* + * De-assert stop-core, then trigger the boot FSM. The Q6 PLL and core + * RCG were already configured by gpdsp_setup() in the clock driver. + */ + io_setbits32(base + GPDSP_QDSP6SS_BOOT_CORE_START, BIT(0)); + udelay(5); + io_write32(base + GPDSP_QDSP6SS_BOOT_CMD, 0x1); + + while (!timeout_elapsed(timeout)) { + if (io_read32(base + GPDSP_QDSP6SS_BOOT_STATUS) & BIT(0)) + return TEE_SUCCESS; + + udelay(10); + } + + return TEE_ERROR_TIMEOUT; +} + +static TEE_Result gpdsp1_fw_shutdown(struct qcom_pas_data *data) +{ + return qcom_clock_pas_reset(data->clk_group); +} + +static TEE_Result gpdsp1_get_resource_table(struct resource_table *rt, + size_t *rt_size) +{ + const struct fw_rsc_hdr header = { + .type = RSC_DEVMEM, + }; + static struct resource_table table = { + .ver = 1, + .num = GPDSP1_NUM_MEM_RESOURCES, + .offset[GPDSP1_NUM_MEM_RESOURCES - 1] = 0, + }; + + return get_mem_rsc(rt, rt_size, &table, &header, + turing_mem_res, + GPDSP1_RESOURCE_TABLE_HEADER_SIZE, + GPDSP1_RESOURCE_TABLE_SIZE); +} + +const struct qcom_pas_ops gpdsp1_ops = { + .fw_start = gpdsp1_fw_start, + .fw_shutdown = gpdsp1_fw_shutdown, + .get_resource_table = gpdsp1_get_resource_table, +}; diff --git a/core/pta/qcom/pas/platform/lemans/gpdsp1.h b/core/pta/qcom/pas/platform/lemans/gpdsp1.h new file mode 100644 index 000000000..60f82121e --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/gpdsp1.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _GPDSP1_H_ +#define _GPDSP1_H_ + +#include "pas_subsys.h" + +extern const struct qcom_pas_ops gpdsp1_ops; + +#endif /* _GPDSP1_H_ */ diff --git a/core/pta/qcom/pas/platform/lemans/iris.c b/core/pta/qcom/pas/platform/lemans/iris.c new file mode 100644 index 000000000..54f60a162 --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/iris.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include + +#include "iris.h" + +#define WRAPPER_IRIS_VERSION 0x0 +#define WRAPPER_CPA_START_ADDR 0x1020 +#define WRAPPER_CPA_END_ADDR 0x1024 +#define WRAPPER_FW_START_ADDR 0x1028 +#define WRAPPER_FW_END_ADDR 0x102C +#define WRAPPER_NONPIX_START_ADDR 0x1030 +#define WRAPPER_NONPIX_END_ADDR 0x1034 +#define WRAPPER_TZ_XTSS_SW_RESET 0x1000 +#define WRAPPER_XTSS_SW_RESET_BIT BIT(0) + +static TEE_Result iris_reset_cpu(struct qcom_pas_data *data) +{ + vaddr_t base = 0; + + base = io_pa_or_va(&data->base, data->size); + if (!base) + return TEE_ERROR_GENERIC; + + base += IRIS_WRAPPER_TOP_TZ_REG_BASE; + + io_write32(base + WRAPPER_FW_START_ADDR, 0); + io_write32(base + WRAPPER_FW_END_ADDR, data->fw_size); + io_write32(base + WRAPPER_CPA_START_ADDR, 0); + io_write32(base + WRAPPER_CPA_END_ADDR, data->fw_size); + io_write32(base + WRAPPER_NONPIX_START_ADDR, data->fw_size); + io_write32(base + WRAPPER_NONPIX_END_ADDR, data->fw_size); + io_write32(base + WRAPPER_TZ_XTSS_SW_RESET, 0); + + return TEE_SUCCESS; +} + +static TEE_Result iris_fw_shutdown(struct qcom_pas_data *data) +{ + vaddr_t base = 0; + uint32_t reg = 0; + + base = io_pa_or_va(&data->base, data->size); + if (!base) + return TEE_ERROR_GENERIC; + + base += IRIS_WRAPPER_TOP_TZ_REG_BASE; + + reg = io_read32(base + WRAPPER_TZ_XTSS_SW_RESET); + reg |= WRAPPER_XTSS_SW_RESET_BIT; + io_write32(base + WRAPPER_TZ_XTSS_SW_RESET, reg); + + return TEE_SUCCESS; +} + +static TEE_Result iris_fw_start(struct qcom_pas_data *data) +{ + return iris_reset_cpu(data); +} + +static TEE_Result iris_fw_set_state(struct qcom_pas_data *data, bool power_on) +{ + if (power_on) + return iris_reset_cpu(data); + + return iris_fw_shutdown(data); +} + +const struct qcom_pas_ops iris_ops = { + .fw_start = iris_fw_start, + .fw_shutdown = iris_fw_shutdown, + .fw_set_state = iris_fw_set_state, +}; diff --git a/core/pta/qcom/pas/platform/lemans/iris.h b/core/pta/qcom/pas/platform/lemans/iris.h new file mode 100644 index 000000000..b283c3cf0 --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/iris.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _IRIS_H_ +#define _IRIS_H_ + +#include "pas_subsys.h" + +#define IRIS_WRAPPER_TOP_TZ_REG_BASE 0x000c0000 +#define IRIS_WRAPPER_TOP_REG_BASE 0x000b0000 + +extern const struct qcom_pas_ops iris_ops; + +#endif /* _IRIS_H_ */ diff --git a/core/pta/qcom/pas/platform/lemans/lpass.c b/core/pta/qcom/pas/platform/lemans/lpass.c new file mode 100644 index 000000000..84bf42049 --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/lpass.c @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include + +#include "lpass.h" + +/* + * QDSP6 boot registers, relative to the LPASS subsystem base. The PUB block + * holds the reset/boot FSM registers; the MCC block holds the EVB select. The + * Q6 PLL and core RCG are configured earlier by the clock driver (lpass_setup). + */ +#define LPASS_PUB_OFFSET 0x00400000 +#define LPASS_MCC_OFFSET 0x008d0000 + +#define LPASS_QDSP6SS_RST_EVB (LPASS_PUB_OFFSET + 0x10) +#define LPASS_QDSP6SS_BOOT_CORE_START (LPASS_PUB_OFFSET + 0x400) +#define LPASS_QDSP6SS_BOOT_CMD (LPASS_PUB_OFFSET + 0x404) +#define LPASS_QDSP6SS_BOOT_STATUS (LPASS_PUB_OFFSET + 0x408) + +#define LPASS_EFUSE_Q6SS_EVB_SEL (LPASS_MCC_OFFSET + 0xb000) + +#define BOOT_FSM_TIMEOUT 10000 + +/* + * LPASS / ADSP (QDSP6) IOMMU device-memory resource table. Regions are + * identity-mapped (da == pa); flags follow the AC_PERM_R / AC_PERM_W bits. + */ +static const struct fw_rsc_devmem lpass_mem_res[] = { + { .name = "gcc_gpll0_3", .flags = IOMMU_READ, + .da = 0x110000, .pa = 0x110000, .len = 0x4000, }, + { .name = "gcc_gpll6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x123000, .pa = 0x123000, .len = 0x1000, }, + { .name = "gcc_qupv3_wrap1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x124000, .pa = 0x124000, .len = 0x3000, }, + { .name = "gcc_qupv3_wrap0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x127000, .pa = 0x127000, .len = 0x2000, }, + { .name = "gcc_gpll7_9", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x12a000, .pa = 0x12a000, .len = 0x3000, }, + { .name = "gcc_qupv3_wrap2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x12e000, .pa = 0x12e000, .len = 0x1000, }, + { .name = "gcc_gpll10", .flags = IOMMU_READ, + .da = 0x12f000, .pa = 0x12f000, .len = 0x1000, }, + { .name = "gcc_boot_rom_ahb", .flags = IOMMU_READ, + .da = 0x144000, .pa = 0x144000, .len = 0x1000, }, + { .name = "gcc_boot_rom", .flags = IOMMU_READ, + .da = 0x148000, .pa = 0x148000, .len = 0x1000, }, + { .name = "gcc_lpass_cfg0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x149000, .pa = 0x149000, .len = 0xe000, }, + { .name = "gcc_lpass_cbcr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x157000, .pa = 0x157000, .len = 0x1000, }, + { .name = "gcc_lpass_cfg1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x158000, .pa = 0x158000, .len = 0xd000, }, + { .name = "gcc_lpass_dsp_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x165000, .pa = 0x165000, .len = 0x1000, }, + { .name = "gcc_clk_frq_measure", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x172000, .pa = 0x172000, .len = 0x1000, }, + { .name = "gcc_pll_vote", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x173000, .pa = 0x173000, .len = 0x8000, }, + { .name = "gcc_pcie4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x17b000, .pa = 0x17b000, .len = 0x2000, }, + { .name = "gcc_pcie_phy", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x17f000, .pa = 0x17f000, .len = 0x1000, }, + { .name = "gcc_gpll5", .flags = IOMMU_READ, + .da = 0x184000, .pa = 0x184000, .len = 0x1000, }, + { .name = "gcc_gpll4", .flags = IOMMU_READ, + .da = 0x186000, .pa = 0x186000, .len = 0x1000, }, + { .name = "gcc_pcie1_tunnel", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x19c000, .pa = 0x19c000, .len = 0x3000, }, + { .name = "gcc_pcie1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x19f000, .pa = 0x19f000, .len = 0xe000, }, + { .name = "gcc_pcie2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1ad000, .pa = 0x1ad000, .len = 0x2000, }, + { .name = "gcc_pcie3a", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1b0000, .pa = 0x1b0000, .len = 0x1000, }, + { .name = "gcc_pcie3b", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1b2000, .pa = 0x1b2000, .len = 0x1000, }, + { .name = "gcc_pcie0_tunnel", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1b4000, .pa = 0x1b4000, .len = 0x1000, }, + { .name = "gcc_pcie_throttle", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1b6000, .pa = 0x1b6000, .len = 0x1000, }, + { .name = "gcc_pcie_rscc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1be000, .pa = 0x1be000, .len = 0x1000, }, + { .name = "gcc_pcie_rscc_seq", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1bf000, .pa = 0x1bf000, .len = 0x10000, }, + { .name = "gcc_aggre_pcie", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1cf000, .pa = 0x1cf000, .len = 0x1000, }, + { .name = "lpass_ipc_mproc", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x403000, .pa = 0x403000, .len = 0x1000, }, + { .name = "lpass_ipc_computel0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x443000, .pa = 0x443000, .len = 0x1000, }, + { .name = "lpass_ipc_computel1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x483000, .pa = 0x483000, .len = 0x1000, }, + { .name = "lpass_ipc_periph", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4c3000, .pa = 0x4c3000, .len = 0x1000, }, + { .name = "ipc_mode", .flags = IOMMU_READ, + .da = 0x4fc000, .pa = 0x4fc000, .len = 0x1000, }, + { .name = "oem_fuses", .flags = IOMMU_READ, + .da = 0x780000, .pa = 0x780000, .len = 0x7000, }, + { .name = "hwkm_prng_cm", .flags = IOMMU_READ, + .da = 0x10d0000, .pa = 0x10d0000, .len = 0x1000, }, + { .name = "rng", .flags = IOMMU_READ, + .da = 0x10d4000, .pa = 0x10d4000, .len = 0x1000, }, + { .name = "tcsr_dbg0", .flags = IOMMU_READ, + .da = 0x1dc4000, .pa = 0x1dc4000, .len = 0x1000, }, + { .name = "tcsr_dbg1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1dc5000, .pa = 0x1dc5000, .len = 0x1000, }, + { .name = "tcsr_dbg2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1dc8000, .pa = 0x1dc8000, .len = 0x1000, }, + { .name = "tcsr_dbg3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1dfa000, .pa = 0x1dfa000, .len = 0x1000, }, + { .name = "tcsr_dbg4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1dfd000, .pa = 0x1dfd000, .len = 0x1000, }, + { .name = "hw_mutex", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1f40000, .pa = 0x1f40000, .len = 0x40000, }, + { .name = "tcsr_ro", .flags = IOMMU_READ, + .da = 0x1fc0000, .pa = 0x1fc0000, .len = 0x29000, }, + { .name = "tcsr_timeout_intr", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x1fe9000, .pa = 0x1fe9000, .len = 0x1000, }, + { .name = "tcsr_ro1", .flags = IOMMU_READ, + .da = 0x1fea000, .pa = 0x1fea000, .len = 0x1000, }, + { .name = "tcsr_ro2", .flags = IOMMU_READ, + .da = 0x1feb000, .pa = 0x1feb000, .len = 0x1000, }, + { .name = "tcsr_ro3", .flags = IOMMU_READ, + .da = 0x1fec000, .pa = 0x1fec000, .len = 0x4000, }, + { .name = "lpass_ag_noc0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3c41000, .pa = 0x3c41000, .len = 0x3000, }, + { .name = "lpass_ag_noc1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x3c4f000, .pa = 0x3c4f000, .len = 0x1000, }, + { .name = "lpass_core0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4001000, .pa = 0x4001000, .len = 0x1000, }, + { .name = "lpass_core1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4002000, .pa = 0x4002000, .len = 0x1000, }, + { .name = "lpass_core2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4041000, .pa = 0x4041000, .len = 0x1000, }, + { .name = "lpass_core3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4042000, .pa = 0x4042000, .len = 0x1000, }, + { .name = "lpass_core4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4043000, .pa = 0x4043000, .len = 0x1000, }, + { .name = "lpass_core5", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4045000, .pa = 0x4045000, .len = 0x1000, }, + { .name = "lpass_core6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4046000, .pa = 0x4046000, .len = 0x1000, }, + { .name = "lpass_core7", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x404e000, .pa = 0x404e000, .len = 0x1000, }, + { .name = "lpass_core8", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x404f000, .pa = 0x404f000, .len = 0x1000, }, + { .name = "lpass_qdss0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4b04000, .pa = 0x4b04000, .len = 0x1000, }, + { .name = "lpass_qdss1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4b05000, .pa = 0x4b05000, .len = 0x1000, }, + { .name = "lpass_qdss2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4b11000, .pa = 0x4b11000, .len = 0x1000, }, + { .name = "lpass_island_dbg", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x4b40000, .pa = 0x4b40000, .len = 0x20000, }, + { .name = "ddr_llc_info", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9080000, .pa = 0x9080000, .len = 0x1000, }, + { .name = "llcc_trp0", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9200000, .pa = 0x9200000, .len = 0x28000, }, + { .name = "llcc_trp1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9300000, .pa = 0x9300000, .len = 0x28000, }, + { .name = "llcc_trp2", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9400000, .pa = 0x9400000, .len = 0x28000, }, + { .name = "llcc_trp3", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9500000, .pa = 0x9500000, .len = 0x28000, }, + { .name = "llcc_trp4", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9600000, .pa = 0x9600000, .len = 0x28000, }, + { .name = "llcc_trp5", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x9700000, .pa = 0x9700000, .len = 0x28000, }, + { .name = "pdc_audio", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb250000, .pa = 0xb250000, .len = 0x10000, }, + { .name = "pdc_audio1", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xb450000, .pa = 0xb450000, .len = 0x10000, }, + { .name = "rpmh_bcm", .flags = IOMMU_READ, + .da = 0xbbf0000, .pa = 0xbbf0000, .len = 0x2000, }, + { .name = "mpm", .flags = IOMMU_READ, + .da = 0xc210000, .pa = 0xc210000, .len = 0x80000, }, + { .name = "rpmh_drv_lpass", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc340000, .pa = 0xc340000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv0", .flags = IOMMU_READ, + .da = 0xc370000, .pa = 0xc370000, .len = 0x1000, }, + { .name = "rpmh_drv8_aop", .flags = IOMMU_READ, + .da = 0xc380000, .pa = 0xc380000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv1", .flags = IOMMU_READ, + .da = 0xc390000, .pa = 0xc390000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv2", .flags = IOMMU_READ, + .da = 0xc3a0000, .pa = 0xc3a0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv3", .flags = IOMMU_READ, + .da = 0xc3b0000, .pa = 0xc3b0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv4", .flags = IOMMU_READ, + .da = 0xc3c0000, .pa = 0xc3c0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv5", .flags = IOMMU_READ, + .da = 0xc3d0000, .pa = 0xc3d0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv6", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc3e0000, .pa = 0xc3e0000, .len = 0x1000, }, + { .name = "rpmh_drv_rsv7", .flags = IOMMU_READ, + .da = 0xc3f0000, .pa = 0xc3f0000, .len = 0x1000, }, + { .name = "pmic_arb_master", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc400000, .pa = 0xc400000, .len = 0x30000, }, + { .name = "pmic_arb", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xc440000, .pa = 0xc440000, .len = 0x10000, }, + { .name = "pmic_arb_mgpi", .flags = IOMMU_READ, + .da = 0xc460000, .pa = 0xc460000, .len = 0x81000, }, + { .name = "pmic_obs", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xe600000, .pa = 0xe600000, .len = 0x100000, }, + { .name = "spmi_pic", .flags = IOMMU_READ, + .da = 0xe700000, .pa = 0xe700000, .len = 0xa0000, }, + { .name = "tlmm", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0xf000000, .pa = 0xf000000, .len = 0x1000000, }, + { .name = "sys_imem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x146d8000, .pa = 0x146d8000, .len = 0x1000, }, + { .name = "stm_trace", .flags = IOMMU_WRITE, + .da = 0x16000000, .pa = 0x16000000, .len = 0x1000000, }, + { .name = "aop_cmd_db", .flags = IOMMU_READ, + .da = 0x90860000, .pa = 0x90860000, .len = 0x20000, }, + /* SMEM (smem@90900000, 2 MB) holds the GLINK FIFOs the DSP must + * read/write to talk to the apps processor. Without this mapping the + * DSP takes a translation fault on its first SMEM access (e.g. iova + * 0x90aff330) -> mmufault/watchdog and never reaches running. + */ + { .name = "smem", .flags = IOMMU_READ | IOMMU_WRITE, + .da = 0x90900000, .pa = 0x90900000, .len = 0x200000, }, +}; + +DEFINE_RESOURCE_TABLE(LPASS, ARRAY_SIZE(lpass_mem_res)); + +static TEE_Result lpass_fw_start(struct qcom_pas_data *data) +{ + vaddr_t base = io_pa_or_va(&data->base, data->size); + uint64_t timeout = timeout_init_us(BOOT_FSM_TIMEOUT); + + if (!base) + return TEE_ERROR_GENERIC; + + /* + * Program the firmware entry address and select the programmed EVB; + * the Q6 PLL and core RCG are already configured by lpass_setup(). + */ + io_write32(base + LPASS_QDSP6SS_RST_EVB, data->fw_base >> 4); + io_write32(base + LPASS_EFUSE_Q6SS_EVB_SEL, 0); + dsb(); + + /* De-assert stop-core, then trigger the boot FSM. */ + io_setbits32(base + LPASS_QDSP6SS_BOOT_CORE_START, BIT(0)); + io_write32(base + LPASS_QDSP6SS_BOOT_CMD, 0x1); + + while (!timeout_elapsed(timeout)) { + if (io_read32(base + LPASS_QDSP6SS_BOOT_STATUS) & BIT(0)) + return TEE_SUCCESS; + + udelay(10); + } + + return TEE_ERROR_TIMEOUT; +} + +static TEE_Result lpass_fw_shutdown(struct qcom_pas_data *data __unused) +{ + return TEE_ERROR_NOT_IMPLEMENTED; +} + +static TEE_Result lpass_get_resource_table(struct resource_table *rt, + size_t *rt_size) +{ + const struct fw_rsc_hdr header = { + .type = RSC_DEVMEM, + }; + static struct resource_table table = { + .ver = 1, + .num = LPASS_NUM_MEM_RESOURCES, + .offset[LPASS_NUM_MEM_RESOURCES - 1] = 0, + }; + + return get_mem_rsc(rt, rt_size, &table, &header, + lpass_mem_res, + LPASS_RESOURCE_TABLE_HEADER_SIZE, + LPASS_RESOURCE_TABLE_SIZE); +} + +const struct qcom_pas_ops lpass_ops = { + .fw_start = lpass_fw_start, + .fw_shutdown = lpass_fw_shutdown, + .get_resource_table = lpass_get_resource_table, +}; diff --git a/core/pta/qcom/pas/platform/lemans/lpass.h b/core/pta/qcom/pas/platform/lemans/lpass.h new file mode 100644 index 000000000..f8cf519fc --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/lpass.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _LPASS_H_ +#define _LPASS_H_ + +#include "pas_subsys.h" + +extern const struct qcom_pas_ops lpass_ops; + +#endif /* _LPASS_H_ */ diff --git a/core/pta/qcom/pas/platform/lemans/sub.mk b/core/pta/qcom/pas/platform/lemans/sub.mk new file mode 100644 index 000000000..c40fd65fc --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/sub.mk @@ -0,0 +1,3 @@ +srcs-y += subsys.c camera.c cdsp0.c cdsp1.c lpass.c iris.c gpdsp0.c gpdsp1.c +incdirs-y += . +incdirs-y += ../ diff --git a/core/pta/qcom/pas/platform/lemans/subsys.c b/core/pta/qcom/pas/platform/lemans/subsys.c new file mode 100644 index 000000000..039e6b98c --- /dev/null +++ b/core/pta/qcom/pas/platform/lemans/subsys.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include + +#include "camera.h" +#include "cdsp0.h" +#include "cdsp1.h" +#include "gpdsp0.h" +#include "gpdsp1.h" +#include "iris.h" +#include "lpass.h" +#include "pas_subsys.h" + +static struct qcom_pas_subsys subsystems[] = { + { + .data = { + .pas_id = PAS_ID_TURING, + .base.pa = TURING_0_BASE, + .size = TURING_0_SIZE, + .clk_group = QCOM_CLKS_TURING, + }, + .ops = &cdsp0_ops, + .reset_seq = QCOM_PAS_RESET_CLK_FULL, + }, + { + .data = { + .pas_id = PAS_ID_TURING1, + .base.pa = TURING_1_BASE, + .size = TURING_1_SIZE, + .clk_group = QCOM_CLKS_TURING1, + }, + .ops = &cdsp1_ops, + .reset_seq = QCOM_PAS_RESET_CLK_FULL, + }, + { + .data = { + .pas_id = PAS_ID_QDSP6, + .base.pa = LPASS_BASE, + .size = LPASS_SIZE, + .clk_group = QCOM_CLKS_LPASS, + }, + .ops = &lpass_ops, + .reset_seq = QCOM_PAS_RESET_CLK_FULL, + }, + { + .data = { + .pas_id = PAS_ID_GPDSP0, + .base.pa = TURING_GDSP_0_BASE, + .size = TURING_GDSP_0_SIZE, + .clk_group = QCOM_CLKS_GPDSP0, + }, + .ops = &gpdsp0_ops, + .reset_seq = QCOM_PAS_RESET_CLK_FULL, + }, + { + .data = { + .pas_id = PAS_ID_GPDSP1, + .base.pa = TURING_GDSP_1_BASE, + .size = TURING_GDSP_1_SIZE, + .clk_group = QCOM_CLKS_GPDSP1, + }, + .ops = &gpdsp1_ops, + .reset_seq = QCOM_PAS_RESET_CLK_FULL, + }, + { + .data = { + .pas_id = PAS_ID_IRIS, + .base.pa = IRIS_BASE, + .size = IRIS_SIZE, + }, + .ops = &iris_ops, + .reset_seq = QCOM_PAS_RESET_NONE, + }, + { + .data = { + .pas_id = PAS_ID_CAMERA, + .base.pa = TITAN_SS_BASE, + .size = TITAN_SS_SIZE, + }, + .ops = &camera_ops, + .reset_seq = QCOM_PAS_RESET_NONE, + }, +}; + +struct qcom_pas_subsys *qcom_pas_platform_subsys(size_t *count) +{ + *count = ARRAY_SIZE(subsystems); + + return subsystems; +} diff --git a/core/pta/qcom/pas/platform/pas_data.h b/core/pta/qcom/pas/platform/pas_data.h new file mode 100644 index 000000000..1cf99887b --- /dev/null +++ b/core/pta/qcom/pas/platform/pas_data.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2025, Linaro Limited + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _PAS_DATA_H_ +#define _PAS_DATA_H_ + +#include +#include +#include + +#define PAS_ID_QDSP6 1 +#define PAS_ID_WPSS 6 +#define PAS_ID_IRIS 9 +#define PAS_ID_TURING 18 +#define PAS_ID_TURING1 30 +#define PAS_ID_CAMERA 33 +#define PAS_ID_GPDSP0 39 +#define PAS_ID_GPDSP1 40 + +struct qcom_pas_data { + uint32_t pas_id; + struct io_pa_va base; + size_t size; + paddr_t fw_base; + size_t fw_size; + enum qcom_clk_group clk_group; +}; + +#endif /* _PAS_DATA_H_ */ diff --git a/core/pta/qcom/pas/platform/pas_subsys.h b/core/pta/qcom/pas/platform/pas_subsys.h new file mode 100644 index 000000000..dd526f84d --- /dev/null +++ b/core/pta/qcom/pas/platform/pas_subsys.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef PAS_SUBSYS_H +#define PAS_SUBSYS_H + +#include +#include +#include + +#include "pas_data.h" +#include "resource_table.h" + +/* + * struct qcom_pas_ops : per-subsystem firmware operations. + * + * Each remoteproc subsystem a platform supports provides one of these. Any + * member may be NULL when the subsystem does not implement that operation; + * the generic core (pas_core.c) returns the appropriate error in that case. + * + * @fw_start: Program the firmware entry and run the boot FSM. + * @fw_shutdown: Put the processor back into reset. + * @fw_set_state: Power the processor on (@on == true) or off. + * @get_resource_table: Serialise the firmware resource table (see + * resource_table.h). NULL for subsystems with no table. + */ +struct qcom_pas_ops { + TEE_Result (*fw_start)(struct qcom_pas_data *data); + TEE_Result (*fw_shutdown)(struct qcom_pas_data *data); + TEE_Result (*fw_set_state)(struct qcom_pas_data *data, bool on); + TEE_Result (*get_resource_table)(struct resource_table *rt, + size_t *size); +}; + +/* + * enum qcom_pas_reset_seq : clock/reset sequence auth_and_reset runs around + * the subsystem's fw_start op. + * + * @QCOM_PAS_RESET_NONE: fw_start only; no clock management here. + * @QCOM_PAS_RESET_CLK_ENABLE: qcom_clock_enable() then fw_start(). + * @QCOM_PAS_RESET_CLK_FULL: qcom_clock_pas_reset(), qcom_clock_enable(), + * fw_start(), then + * qcom_clock_enable_pas_processor(). + */ +enum qcom_pas_reset_seq { + QCOM_PAS_RESET_NONE = 0, + QCOM_PAS_RESET_CLK_ENABLE, + QCOM_PAS_RESET_CLK_FULL, +}; + +/* + * struct qcom_pas_subsys : one remoteproc subsystem on a platform. + * + * @data: Runtime state, seeded with the static pas_id / base / size / + * clk_group and updated during mem_setup and bring-up. + * @ops: Firmware operations for this subsystem. + * @reset_seq: Clock/reset sequence auth_and_reset must run. + * + * Platform descriptor tables are writable because @data is mutated at + * runtime. + */ +struct qcom_pas_subsys { + struct qcom_pas_data data; + const struct qcom_pas_ops *ops; + enum qcom_pas_reset_seq reset_seq; +}; + +/* + * qcom_pas_platform_subsys() : return this platform's subsystem table. + * + * Implemented once per platform flavor in platform//subsys.c. + * + * @count: out, number of entries in the returned table. + * Returns the (writable) descriptor array. + */ +struct qcom_pas_subsys *qcom_pas_platform_subsys(size_t *count); + +#endif /* PAS_SUBSYS_H */ diff --git a/core/pta/qcom/pas/platform/platform_pas.h b/core/pta/qcom/pas/platform/platform_pas.h new file mode 100644 index 000000000..7bb596be7 --- /dev/null +++ b/core/pta/qcom/pas/platform/platform_pas.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef PLATFORM_PAS_H +#define PLATFORM_PAS_H + +#include + +TEE_Result pas_platform_mem_setup(uint32_t pas_id, uint32_t fw_size, + uint32_t fw_base_low, uint32_t fw_base_high); +TEE_Result pas_platform_get_resource_table(uint32_t pas_id, + struct resource_table *rt, + size_t *size); +TEE_Result pas_platform_set_remote_state(uint32_t pas_id, uint32_t state); +TEE_Result pas_platform_auth_and_reset(uint32_t pas_id); +TEE_Result pas_platform_is_supported(uint32_t pas_id); +TEE_Result pas_platform_capabilities(uint32_t pas_id); +TEE_Result pas_platform_init_image(uint32_t pas_id); +TEE_Result pas_platform_shutdown(uint32_t pas_id); + +#endif diff --git a/core/pta/qcom/pas/platform/resource_table.h b/core/pta/qcom/pas/platform/resource_table.h new file mode 100644 index 000000000..5239e38a4 --- /dev/null +++ b/core/pta/qcom/pas/platform/resource_table.h @@ -0,0 +1,185 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/* + * Firmware resource table helpers for Qualcomm remoteproc subsystems. + * + * A resource table is a data structure embedded in (or alongside) a processor + * firmware image. It advertises to the host the set of memory regions the + * processor needs mapped into its IOMMU before it can boot. The layout + * expected by the remoteproc / PAS loader is: + * + * [ struct resource_table header + offset[] array ] + * [ struct fw_rsc_hdr + struct fw_rsc_devmem ] * N <- one per region + * + * Each element in offset[] holds the byte offset from the start of the table + * to the corresponding fw_rsc_hdr/fw_rsc_devmem pair. + * + * Callers define a table with DEFINE_RESOURCE_TABLE(), declare a static + * struct resource_table and a static array of struct fw_rsc_devmem, then + * call get_mem_rsc() to serialise everything into a caller-supplied buffer. + */ + +#ifndef RESOURCE_TABLE_H +#define RESOURCE_TABLE_H + +#include +#include +#include +#include +#include + +/* + * DEFINE_RESOURCE_TABLE(prefix, num_res) : emit compile-time size constants + * for a resource table that holds @num_res device-memory entries. + * + * Generates an anonymous enum with four members, all prefixed by @prefix: + * + * PREFIX_NUM_MEM_RESOURCES : number of fw_rsc_devmem entries + * PREFIX_SIZE_MEM_RES : byte size of one (hdr + devmem) entry + * PREFIX_RESOURCE_TABLE_HEADER_SIZE : byte size of the table header plus + * the offset[] array + * PREFIX_RESOURCE_TABLE_SIZE : total byte size of the serialised table + * + * Use these constants to size the struct resource_table initialiser and to + * pass table_header_size / table_size to get_mem_rsc(). + */ +#define DEFINE_RESOURCE_TABLE(prefix, num_res) \ + enum prefix##_rt_sizes { \ + prefix##_NUM_MEM_RESOURCES = (num_res), \ + prefix##_SIZE_MEM_RES = \ + (sizeof(struct fw_rsc_hdr) + \ + sizeof(struct fw_rsc_devmem)), \ + prefix##_RESOURCE_TABLE_HEADER_SIZE = \ + (sizeof(struct resource_table) + \ + (prefix##_NUM_MEM_RESOURCES * \ + sizeof(uint32_t))), \ + prefix##_RESOURCE_TABLE_SIZE = \ + (prefix##_RESOURCE_TABLE_HEADER_SIZE + \ + (prefix##_NUM_MEM_RESOURCES * \ + prefix##_SIZE_MEM_RES)), \ + } + +/* + * resource_table : top-level header of the firmware resource table. + * + * @ver: Table version; must be 1. + * @num: Number of resource entries (length of the offset[] array). + * @reserved: Must be zero. + * @offset: Array of byte offsets from the start of the table to each + * fw_rsc_hdr entry. Populated by get_mem_rsc(). + */ +struct resource_table { + uint32_t ver; + uint32_t num; + uint32_t reserved[2]; + uint32_t offset[]; +} __packed; + +/* + * fw_rsc_hdr : per-resource entry header. + * + * @type: Resource type (see enum fw_resource_type). + * @data: Type-specific payload; for RSC_DEVMEM this is struct fw_rsc_devmem. + */ +struct fw_rsc_hdr { + uint32_t type; + uint8_t data[]; +} __packed; + +/* Resource entry types defined by the remoteproc ABI. */ +enum fw_resource_type { + RSC_CARVEOUT = 0, /* contiguous memory carve-out */ + RSC_DEVMEM = 1, /* device memory IOMMU mapping */ + RSC_TRACE = 2, /* trace buffer */ + RSC_VDEV = 3, /* virtio device */ + RSC_LAST = 4, + RSC_VENDOR_START = 128, + RSC_VENDOR_END = 512, +}; + +/* IOMMU permission flags for fw_rsc_devmem.flags. */ +#define IOMMU_READ BIT(0) +#define IOMMU_WRITE BIT(1) + +/* + * fw_rsc_devmem : describes a single IOMMU mapping the processor requires. + * + * @da: Device virtual address of the mapping. + * @pa: Physical address; on Kodiak these are identity-mapped (da == pa). + * @len: Size of the region in bytes. + * @flags: IOMMU permission flags (IOMMU_READ, IOMMU_WRITE). + * @reserved: Must be zero. + * @name: Human-readable label for debugging (NUL-terminated, 32 bytes). + */ +struct fw_rsc_devmem { + uint32_t da; + uint32_t pa; + uint32_t len; + uint32_t flags; + uint32_t reserved; + uint8_t name[32]; +} __packed; + +/* + * get_mem_rsc() : serialise a processor resource table into a caller buffer. + * + * The function has two modes: + * + * Size query: pass rt == NULL (or *rt_size < table_size). The required + * buffer size is written to *rt_size and TEE_SUCCESS is returned so the + * caller can allocate an appropriately-sized buffer. + * + * Serialise: pass a buffer of at least table_size bytes in rt. The + * function fills in table->offset[], copies each (mem_hdr + mem_res[i]) + * pair at the computed offset, then copies the updated header to the start + * of the buffer. + * + * @rt: Output buffer (may be NULL for size query). + * @rt_size: In/out: caller capacity on entry; required size on + * exit when the buffer is too small. + * @table: Partially initialised resource_table (ver, num set by + * the caller via DEFINE_RESOURCE_TABLE constants). + * @mem_hdr: fw_rsc_hdr with type = RSC_DEVMEM, shared by all + * entries. + * @mem_res: Array of table->num fw_rsc_devmem descriptors. + * @table_header_size: PREFIX_RESOURCE_TABLE_HEADER_SIZE from the macro. + * @table_size: PREFIX_RESOURCE_TABLE_SIZE from the macro. + */ +static inline TEE_Result get_mem_rsc(struct resource_table *rt, size_t *rt_size, + struct resource_table *table, + const struct fw_rsc_hdr *mem_hdr, + const struct fw_rsc_devmem *mem_res, + size_t table_header_size, + size_t table_size) +{ + uint8_t *p = (uint8_t *)rt; + uint32_t offset = 0; + + if (rt_size && *rt_size < table_size) { + *rt_size = table_size; + + return TEE_SUCCESS; + } + + if (!rt) + return TEE_ERROR_BAD_PARAMETERS; + + offset = table_header_size; + + for (size_t i = 0; i < table->num; i++, mem_res++) { + table->offset[i] = offset; + memcpy(p + offset, mem_hdr, sizeof(*mem_hdr)); + offset += sizeof(*mem_hdr); + memcpy(p + offset, mem_res, sizeof(*mem_res)); + offset += sizeof(*mem_res); + } + + memcpy(p, table, table_header_size); + + return TEE_SUCCESS; +} + +#endif diff --git a/core/pta/qcom/pas/pta_qcom_pas.c b/core/pta/qcom/pas/pta_qcom_pas.c index b8bef6f04..13d5a10d6 100644 --- a/core/pta/qcom/pas/pta_qcom_pas.c +++ b/core/pta/qcom/pas/pta_qcom_pas.c @@ -7,43 +7,15 @@ #include #include #include +#include #include #include -#include "pas.h" - #define PTA_NAME "pta.qcom.pas" #define TA_PAS_UUID { 0xcff7d191, 0x7ca0, 0x4784, \ { 0xaf, 0x13, 0x48, 0x22, 0x3b, 0x9a, 0x4f, 0xbe} } -static struct qcom_pas_data wpss_dsp_data = { - .pas_id = PAS_ID_WPSS, - .base.pa = WPSS_BASE, - .size = WPSS_SIZE, - .clk_group = QCOM_CLKS_WPSS, -}; - -static struct qcom_pas_data turing_dsp_data = { - .pas_id = PAS_ID_TURING, - .base.pa = TURING_BASE, - .size = TURING_SIZE, - .clk_group = QCOM_CLKS_TURING, -}; - -static struct qcom_pas_data lpass_dsp_data = { - .pas_id = PAS_ID_QDSP6, - .base.pa = LPASS_BASE, - .size = LPASS_SIZE, - .clk_group = QCOM_CLKS_LPASS, -}; - -static struct qcom_pas_data venus_fw_data = { - .pas_id = PAS_ID_VENUS, - .base.pa = IRIS_BASE, - .size = IRIS_SIZE, -}; - static TEE_Result qcom_pas_is_supported(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS]) { @@ -54,16 +26,9 @@ static TEE_Result qcom_pas_is_supported(uint32_t pt, if (pt != exp_pt) return TEE_ERROR_BAD_PARAMETERS; - DMSG("invoked with pas_id: %d", params[0].value.a); - if (params[0].value.a != PAS_ID_WPSS && - params[0].value.a != PAS_ID_QDSP6 && - params[0].value.a != PAS_ID_VENUS && - params[0].value.a != PAS_ID_TURING) - return TEE_ERROR_NOT_SUPPORTED; - - return TEE_SUCCESS; + return pas_platform_is_supported(params[0].value.a); } static TEE_Result qcom_pas_capabilities(uint32_t pt, @@ -76,12 +41,11 @@ static TEE_Result qcom_pas_capabilities(uint32_t pt, if (pt != exp_pt) return TEE_ERROR_BAD_PARAMETERS; - DMSG("invoked with pas_id: %d", params[0].value.a); + /* Capabilities flags reserved for future use */ params[1].value.a = 0; - - return TEE_SUCCESS; + return pas_platform_capabilities(params[1].value.a); } static TEE_Result qcom_pas_init_image(uint32_t pt, @@ -94,16 +58,9 @@ static TEE_Result qcom_pas_init_image(uint32_t pt, if (pt != exp_pt) return TEE_ERROR_BAD_PARAMETERS; - DMSG("invoked with pas_id: %d", params[0].value.a); - if (params[0].value.a != PAS_ID_WPSS && - params[0].value.a != PAS_ID_QDSP6 && - params[0].value.a != PAS_ID_VENUS && - params[0].value.a != PAS_ID_TURING) - return TEE_ERROR_NOT_SUPPORTED; - - return TEE_SUCCESS; + return pas_platform_init_image(params[0].value.a); } static TEE_Result qcom_pas_mem_setup(uint32_t pt, @@ -113,44 +70,12 @@ static TEE_Result qcom_pas_mem_setup(uint32_t pt, TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); - struct qcom_pas_data *data = NULL; - if (pt != exp_pt) return TEE_ERROR_BAD_PARAMETERS; - DMSG("invoked with pas_id: %d", params[0].value.a); - switch (params[0].value.a) { - case PAS_ID_WPSS: - data = &wpss_dsp_data; - break; - case PAS_ID_TURING: - data = &turing_dsp_data; - break; - case PAS_ID_QDSP6: - data = &lpass_dsp_data; - break; - case PAS_ID_VENUS: - data = &venus_fw_data; - break; - default: - return TEE_ERROR_NOT_SUPPORTED; - } - - data->fw_size = params[0].value.b; - data->fw_base = params[1].value.a; - data->fw_base |= SHIFT_U64(params[1].value.b, 32); - - /* Map the controller */ - if (!data->base.va) { - data->base.va = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_NSEC, - data->base.pa, - data->size); - if (!data->base.va) - return TEE_ERROR_GENERIC; - } - - return TEE_SUCCESS; + return pas_platform_mem_setup(params[0].value.a, params[0].value.b, + params[1].value.a, params[1].value.b); } static TEE_Result qcom_pas_get_resource_table(uint32_t pt, @@ -163,17 +88,11 @@ static TEE_Result qcom_pas_get_resource_table(uint32_t pt, if (pt != exp_pt) return TEE_ERROR_BAD_PARAMETERS; - DMSG("invoked with pas_id: %d", params[0].value.a); - if (params[0].value.a != PAS_ID_WPSS && - params[0].value.a != PAS_ID_TURING && - params[0].value.a != PAS_ID_QDSP6) - return TEE_ERROR_NOT_SUPPORTED; - - return pas_get_resource_table(params[0].value.a, - params[1].memref.buffer, - ¶ms[1].memref.size); + return pas_platform_get_resource_table(params[0].value.a, + params[1].memref.buffer, + ¶ms[1].memref.size); } static TEE_Result @@ -187,13 +106,10 @@ qcom_pas_set_remote_state(uint32_t pt, if (pt != exp_pt) return TEE_ERROR_BAD_PARAMETERS; - DMSG("invoked with pas_id: %d", params[0].value.a); - if (params[0].value.a == PAS_ID_VENUS) - return venus_fw_set_state(&venus_fw_data, params[0].value.b); - - return TEE_ERROR_NOT_IMPLEMENTED; + return pas_platform_set_remote_state(params[0].value.a, + params[0].value.b); } static TEE_Result qcom_pas_auth_and_reset(uint32_t pt, @@ -203,55 +119,12 @@ static TEE_Result qcom_pas_auth_and_reset(uint32_t pt, TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_NONE); - TEE_Result res = TEE_SUCCESS; if (pt != exp_pt) return TEE_ERROR_BAD_PARAMETERS; - DMSG("invoked with pas_id: %d", params[0].value.a); - switch (params[0].value.a) { - case PAS_ID_WPSS: - if (!wpss_dsp_data.fw_base) - return TEE_ERROR_NO_DATA; - - res = qcom_clock_enable(wpss_dsp_data.clk_group); - if (res != TEE_SUCCESS) { - EMSG("Failed to enable clocks: %d", res); - return res; - } - - return wpss_fw_start(&wpss_dsp_data); - case PAS_ID_TURING: - if (!turing_dsp_data.fw_base) - return TEE_ERROR_NO_DATA; - - res = qcom_clock_enable(turing_dsp_data.clk_group); - if (res != TEE_SUCCESS) { - EMSG("Failed to enable clocks: %d", res); - return res; - } - - return compute_fw_start(&turing_dsp_data); - case PAS_ID_QDSP6: - if (!lpass_dsp_data.fw_base) - return TEE_ERROR_NO_DATA; - - res = qcom_clock_enable(lpass_dsp_data.clk_group); - if (res != TEE_SUCCESS) { - EMSG("Failed to enable clocks: %d", res); - return res; - } - - return lpass_fw_start(&lpass_dsp_data); - case PAS_ID_VENUS: - if (!venus_fw_data.fw_base) - return TEE_ERROR_NO_DATA; - - return venus_fw_start(&venus_fw_data); - default: - return TEE_ERROR_NOT_SUPPORTED; - } + return pas_platform_auth_and_reset(params[0].value.a); } static TEE_Result @@ -265,23 +138,9 @@ qcom_pas_shutdown(uint32_t pt, if (pt != exp_pt) return TEE_ERROR_BAD_PARAMETERS; - DMSG("invoked with pas_id: %d", params[0].value.a); - switch (params[0].value.a) { - case PAS_ID_WPSS: - return wpss_fw_shutdown(&wpss_dsp_data); - case PAS_ID_TURING: - return compute_fw_shutdown(&turing_dsp_data); - case PAS_ID_QDSP6: - return lpass_fw_shutdown(&lpass_dsp_data); - case PAS_ID_VENUS: - return venus_fw_shutdown(&venus_fw_data); - default: - return TEE_ERROR_NOT_SUPPORTED; - } - - return TEE_ERROR_NOT_IMPLEMENTED; + return pas_platform_shutdown(params[0].value.a); } static TEE_Result pta_qcom_pas_invoke_command(void *session __unused, @@ -320,8 +179,8 @@ pta_qcom_pas_open_session(uint32_t pt __unused, void **sess_ctx __unused) { struct ts_session *s = ts_get_calling_session(); - struct ts_ctx *ctx = NULL; TEE_UUID ta_uuid = TA_PAS_UUID; + struct ts_ctx *ctx = NULL; if (!s) return TEE_ERROR_ACCESS_DENIED; @@ -333,11 +192,9 @@ pta_qcom_pas_open_session(uint32_t pt __unused, return TEE_SUCCESS; } -/* - * TA_FLAG_CONCURRENT disabled: - * concurrent operation must be supported by the client. - */ -pseudo_ta_register(.uuid = PTA_QCOM_PAS_UUID, .name = PTA_NAME, +/* TA_FLAG_CONCURRENT disabled: concurrency must be handled by the client. */ +pseudo_ta_register(.invoke_command_entry_point = pta_qcom_pas_invoke_command, + .open_session_entry_point = pta_qcom_pas_open_session, .flags = PTA_DEFAULT_FLAGS, - .invoke_command_entry_point = pta_qcom_pas_invoke_command, - .open_session_entry_point = pta_qcom_pas_open_session); + .uuid = PTA_QCOM_PAS_UUID, + .name = PTA_NAME); diff --git a/core/pta/qcom/pas/q6dsp.c b/core/pta/qcom/pas/q6dsp.c deleted file mode 100644 index ebc6df834..000000000 --- a/core/pta/qcom/pas/q6dsp.c +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause -/* - * Copyright (c) 2025, Linaro Limited - * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries. - */ - -#include -#include -#include -#include -#include - -#include "dsp_boot.h" -#include "pas.h" - -TEE_Result wpss_fw_start(struct qcom_pas_data *data) -{ - return dsp_fw_start(data, dsp_fw_get_boot_regs(data->pas_id)); -} - -TEE_Result wpss_fw_shutdown(struct qcom_pas_data *data __unused) -{ - return TEE_ERROR_NOT_IMPLEMENTED; -} diff --git a/core/pta/qcom/pas/sub.mk b/core/pta/qcom/pas/sub.mk index 7c56b2915..06bdd894c 100644 --- a/core/pta/qcom/pas/sub.mk +++ b/core/pta/qcom/pas/sub.mk @@ -1,3 +1,5 @@ -srcs-y += pta_qcom_pas.c dsp.c pas.c q6dsp.c compute.c lpass.c venus.c +srcs-y += pta_qcom_pas.c +srcs-y += pas_core.c incdirs-y += . -incdirs-y += platform/$(PLATFORM_FLAVOR) +incdirs-y += platform/ +subdirs-y += platform/$(PLATFORM_FLAVOR)