From 2f9b4ad6a508628ce60973e649b036c099eda310 Mon Sep 17 00:00:00 2001 From: Swathi Tamilselvan Date: Wed, 19 Nov 2025 19:48:19 +0530 Subject: [PATCH] soc/qualcomm/x1p42100: Add DFSR table configuration support Add support to configure DFSR table, introduce qupv3_clock_v2 structure to calculate register addresses for serial engines 2 and 3. Update CBCR registers to use the new structure for QUPv3 clock enablement. BUG=b:444617760 TEST=Create an image.serial.bin and ensure it boots on X1P42100. Dump DFSR registers for corresponding QUP and check if values are updated properly into correct register address. Change-Id: Ibd7e4bf121bd99130336047a50ed70d4cbec2234 Signed-off-by: Swathi Tamilselvan Reviewed-on: https://review.coreboot.org/c/coreboot/+/90145 Reviewed-by: Subrata Banik Tested-by: build bot (Jenkins) Reviewed-by: Kapil Porwal --- .../common/include/soc/clock_common.h | 9 ++ src/soc/qualcomm/x1p42100/clock.c | 117 +++++++++++++++--- .../x1p42100/include/soc/addressmap.h | 3 + src/soc/qualcomm/x1p42100/include/soc/clock.h | 17 +++ 4 files changed, 130 insertions(+), 16 deletions(-) diff --git a/src/soc/qualcomm/common/include/soc/clock_common.h b/src/soc/qualcomm/common/include/soc/clock_common.h index 10ae134c70..f638ce00e6 100644 --- a/src/soc/qualcomm/common/include/soc/clock_common.h +++ b/src/soc/qualcomm/common/include/soc/clock_common.h @@ -52,6 +52,15 @@ struct qupv3_clock { struct clock_rcg_dfsr dfsr_clk; }; +struct qupv3_clock_v2 { + u32 cbcr; +#if CONFIG(QC_COMMON_QUPV3_2) + u8 reserved[0x10]; +#endif + struct clock_rcg_mnd clk; + struct clock_rcg_dfsr dfsr_clk; +}; + /* PLL Configuration */ struct alpha_pll_reg_val_config { void *reg_mode; diff --git a/src/soc/qualcomm/x1p42100/clock.c b/src/soc/qualcomm/x1p42100/clock.c index 614490104a..377f529a08 100644 --- a/src/soc/qualcomm/x1p42100/clock.c +++ b/src/soc/qualcomm/x1p42100/clock.c @@ -317,37 +317,122 @@ void clock_configure_qspi(uint32_t hz) clock_enable(&gcc->qspi_core_cbcr); } +/* Helper function to get SE index within a wrap */ +static inline int get_qup_se_index(int qup) +{ + return qup % QUP_WRAP1_S0; +} + +/* Helper function to get pointer to QUP SE clock structure */ +static void *get_qup_se_clk(int qup, int s) +{ + struct x1p42100_qupv3_wrap *wrap; + void *se_clk_array[8]; + + /* Determine which wrap based on qup value */ + if (qup <= QUP_WRAP0_S7) + wrap = qup_wrap0_clk; + else if (qup <= QUP_WRAP1_S7) + wrap = qup_wrap1_clk; + else + wrap = qup_wrap2_clk; + + /* Build array of pointers to SE clock structures */ + se_clk_array[0] = &wrap->qupv3_s0; + se_clk_array[1] = &wrap->qupv3_s1; + se_clk_array[2] = &wrap->qupv3_s2; + se_clk_array[3] = &wrap->qupv3_s3; + se_clk_array[4] = &wrap->qupv3_s4; + se_clk_array[5] = &wrap->qupv3_s5; + se_clk_array[6] = &wrap->qupv3_s6; + se_clk_array[7] = &wrap->qupv3_s7; + + return se_clk_array[s]; +} + void clock_enable_qup(int qup) { - struct qupv3_clock *qup_clk; - int s = qup % QUP_WRAP1_S0, clk_en_off; - void *clk_br_en_ptr = NULL; // Pointer to the correct apcs_clk_br_enX - qup_clk = qup < QUP_WRAP1_S0 ? &gcc->qup_wrap0_s[s] : qup < QUP_WRAP2_S0 ? - &gcc->qup_wrap1_s[s] : &gcc->qup_wrap2_s[s]; + int s = get_qup_se_index(qup), clk_en_off; + void *clk_br_en_ptr = NULL; + u32 *cbcr; if (qup <= QUP_WRAP0_S7) { clk_en_off = QUPV3_WRAP0_CLK_ENA_S(s); clk_br_en_ptr = &gcc->apcs_clk_br_en4; - } else if (qup >= QUP_WRAP1_S0 && qup <= QUP_WRAP1_S6) { - clk_en_off = QUPV3_WRAP1_CLK_ENA_S(s); - clk_br_en_ptr = &gcc->apcs_clk_br_en1; - } else if (qup >= QUP_WRAP2_S0 && qup <= QUP_WRAP2_S6) { - clk_en_off = QUPV3_WRAP2_CLK_ENA_S(s); - clk_br_en_ptr = &gcc->apcs_clk_br_en2; - } else if (qup == QUP_WRAP1_S7 || qup == QUP_WRAP2_S7) { - clk_en_off = qup == QUP_WRAP1_S7 ? QUPV3_WRAP1_SE7_CLK_ENA : QUPV3_WRAP2_SE7_CLK_ENA; + } else if (qup <= QUP_WRAP1_S7) { + clk_en_off = (qup == QUP_WRAP1_S7) ? QUPV3_WRAP1_SE7_CLK_ENA : QUPV3_WRAP1_CLK_ENA_S(s); + clk_br_en_ptr = (qup == QUP_WRAP1_S7) ? &gcc->apcs_clk_br_en2 : &gcc->apcs_clk_br_en1; + } else { + clk_en_off = (qup == QUP_WRAP2_S7) ? QUPV3_WRAP2_SE7_CLK_ENA : QUPV3_WRAP2_CLK_ENA_S(s); clk_br_en_ptr = &gcc->apcs_clk_br_en2; } + if (s == 2 || s == 3) + cbcr = &((struct qupv3_clock_v2 *)get_qup_se_clk(qup, s))->cbcr; + else + cbcr = &((struct qupv3_clock *)get_qup_se_clk(qup, s))->cbcr; + /* Only call if a valid pointer was assigned */ if (clk_br_en_ptr) - clock_enable_vote(&qup_clk->cbcr, clk_br_en_ptr, clk_en_off); + clock_enable_vote(cbcr, clk_br_en_ptr, clk_en_off); +} + +/* Clock Root clock Generator with DFS Operations */ +void clock_configure_dfsr_table_x1p42100(int qup, struct clock_freq_config *clk_cfg, + uint32_t num_perfs) +{ + unsigned int idx; + int s = get_qup_se_index(qup); + uint32_t reg_val; + struct clock_rcg_dfsr *dfsr_clk; + + /* Validate s value is within bounds */ + if (s > 7) { + printk(BIOS_ERR, "Invalid QUP index: s=%d\n", s); + return; + } + + /* Get DFSR clock pointer - cast based on SE type + * (s2, s3 are qupv3_clock_v2, others are qupv3_clock) + */ + if (s == 2 || s == 3) + dfsr_clk = &((struct qupv3_clock_v2 *)get_qup_se_clk(qup, s))->dfsr_clk; + else + dfsr_clk = &((struct qupv3_clock *)get_qup_se_clk(qup, s))->dfsr_clk; + + clrsetbits32(&dfsr_clk->cmd_dfsr, + BIT(CLK_CTL_CMD_RCG_SW_CTL_SHFT), + BIT(CLK_CTL_CMD_DFSR_SHFT)); + + for (idx = 0; idx < num_perfs; idx++) { + reg_val = (clk_cfg[idx].src << CLK_CTL_CFG_SRC_SEL_SHFT) | + (clk_cfg[idx].div << CLK_CTL_CFG_SRC_DIV_SHFT); + + write32(&dfsr_clk->perf_dfsr[idx], reg_val); + + if (clk_cfg[idx].m == 0) + continue; + + setbits32(&dfsr_clk->perf_dfsr[idx], RCG_MODE_DUAL_EDGE << CLK_CTL_CFG_MODE_SHFT); + + reg_val = clk_cfg[idx].m & CLK_CTL_RCG_MND_BMSK; + write32(&dfsr_clk->perf_m_dfsr[idx], reg_val); + + reg_val = ~(clk_cfg[idx].n - clk_cfg[idx].m) & CLK_CTL_RCG_MND_BMSK; + write32(&dfsr_clk->perf_n_dfsr[idx], reg_val); + + reg_val = ~(clk_cfg[idx].d_2) & CLK_CTL_RCG_MND_BMSK; + write32(&dfsr_clk->perf_d_dfsr[idx], reg_val); + } } void clock_configure_dfsr(int qup) { - clock_configure_dfsr_table(qup, qupv3_wrap_cfg, - ARRAY_SIZE(qupv3_wrap_cfg)); + int s = get_qup_se_index(qup); + uint32_t qupv3_cfg_size = (s < 4) ? (ARRAY_SIZE(qupv3_wrap_cfg) - 1) : + ARRAY_SIZE(qupv3_wrap_cfg); + + clock_configure_dfsr_table_x1p42100(qup, qupv3_wrap_cfg, qupv3_cfg_size); } static enum cb_err clock_configure_gpll0(void) { diff --git a/src/soc/qualcomm/x1p42100/include/soc/addressmap.h b/src/soc/qualcomm/x1p42100/include/soc/addressmap.h index 90c85bff59..4df4cc99eb 100644 --- a/src/soc/qualcomm/x1p42100/include/soc/addressmap.h +++ b/src/soc/qualcomm/x1p42100/include/soc/addressmap.h @@ -10,6 +10,9 @@ #define TLMM_TILE_BASE 0x0F100000 #define GCC_BASE 0x00100000 #define NCC0_BASE 0x19A30000 +#define GCC_QUPV3_WRAP0_BASE 0x142004 +#define GCC_QUPV3_WRAP1_BASE 0x118004 +#define GCC_QUPV3_WRAP2_BASE 0x11e004 #define CBMEM_TOP 0xC7800000 /* X1P42100 NCC0 PLL CONFIG ADDRESSES */ diff --git a/src/soc/qualcomm/x1p42100/include/soc/clock.h b/src/soc/qualcomm/x1p42100/include/soc/clock.h index 988bba9eea..a0a6eae8a0 100644 --- a/src/soc/qualcomm/x1p42100/include/soc/clock.h +++ b/src/soc/qualcomm/x1p42100/include/soc/clock.h @@ -447,6 +447,18 @@ check_member(x1p42100_gcc, apcs_pll_br_en, 0x52030); check_member(x1p42100_gcc, pcie_6_phy_gdscr, 0x8e000); check_member(x1p42100_gcc, pcie_6a_phy_bcr, 0xac01c); +/* Generic QUPV3 wrapper structure - all wrappers have identical layout */ +struct x1p42100_qupv3_wrap { + struct qupv3_clock qupv3_s0; + struct qupv3_clock qupv3_s1; + struct qupv3_clock_v2 qupv3_s2; + struct qupv3_clock_v2 qupv3_s3; + struct qupv3_clock qupv3_s4; + struct qupv3_clock qupv3_s5; + struct qupv3_clock qupv3_s6; + struct qupv3_clock qupv3_s7; +}; + enum clk_qup { QUP_WRAP0_S0, QUP_WRAP0_S1, @@ -619,6 +631,8 @@ enum cb_err usb_clock_enable(enum clk_usb clk_type); enum cb_err clock_enable_usb_gdsc(enum clk_usb_gdsc gdsc_type); enum cb_err usb_prim_clock_enable(enum clk_usb_prim clk_type); enum cb_err usb_sec_clock_enable(enum clk_usb_sec clk_type); +void clock_configure_dfsr_table_x1p42100(int qup, struct clock_freq_config *clk_cfg, + uint32_t num_perfs); void usb_clock_reset(enum clk_usb clk_type, bool assert); void usb_prim_clock_reset(enum clk_usb_prim clk_type, bool assert); @@ -628,6 +642,9 @@ void usb_sec_clock_reset(enum clk_usb_sec clk_type, bool assert); static struct aoss *const aoss = (void *)AOSS_CC_BASE; static struct x1p42100_gcc *const gcc = (void *)GCC_BASE; static struct x1p42100_ncc0_clock *const apss_ncc0 = (void *)NCC0_BASE; +static struct x1p42100_qupv3_wrap *const qup_wrap0_clk = (void *)GCC_QUPV3_WRAP0_BASE; +static struct x1p42100_qupv3_wrap *const qup_wrap1_clk = (void *)GCC_QUPV3_WRAP1_BASE; +static struct x1p42100_qupv3_wrap *const qup_wrap2_clk = (void *)GCC_QUPV3_WRAP2_BASE; /* Does nothing */ #define clock_reset_aop() do {} while (0)