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 <tswathi@qualcomm.corp-partner.google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/90145 Reviewed-by: Subrata Banik <subratabanik@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Kapil Porwal <kapilporwal@google.com>
This commit is contained in:
parent
51e99de558
commit
2f9b4ad6a5
4 changed files with 130 additions and 16 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue