On Sun, Dec 27, 2020 at 10:50:38PM +0100, Lucas Stach wrote: > The i.MX8MQ uses a different PLL type than the later i.MX8M family > members, so the PLL setup did not actually work on this SoC. In U-Boot > the used PLL setup routine is a compile time decision. As we want > our DRAM init code to work for multi-image builds, this passes the > SoC type through to the PLL init, so we can use the correct setup > routine depending on the SoC we are running on. > > Signed-off-by: Lucas Stach <dev@xxxxxxxxxx> > --- > drivers/ddr/imx8m/ddr_init.c | 4 +- > drivers/ddr/imx8m/ddrphy_train.c | 4 +- > drivers/ddr/imx8m/ddrphy_utils.c | 107 ++++++++++++++++++++++++++++--- > include/soc/imx8m/ddr.h | 4 +- > 4 files changed, 104 insertions(+), 15 deletions(-) Applied, thanks Sascha > > diff --git a/drivers/ddr/imx8m/ddr_init.c b/drivers/ddr/imx8m/ddr_init.c > index 1cd7b7406dc7..34da44af6446 100644 > --- a/drivers/ddr/imx8m/ddr_init.c > +++ b/drivers/ddr/imx8m/ddr_init.c > @@ -62,7 +62,7 @@ static int imx8m_ddr_init(struct dram_timing_info *dram_timing, > > initial_drate = dram_timing->fsp_msg[0].drate; > /* default to the frequency point 0 clock */ > - ddrphy_init_set_dfi_clk(initial_drate); > + ddrphy_init_set_dfi_clk(initial_drate, type); > > /* D-aasert the presetn */ > reg32_write(src_ddrc_rcr, 0x8F000006); > @@ -115,7 +115,7 @@ static int imx8m_ddr_init(struct dram_timing_info *dram_timing, > */ > pr_debug("ddrphy config start\n"); > > - ret = ddr_cfg_phy(dram_timing); > + ret = ddr_cfg_phy(dram_timing, type); > if (ret) > return ret; > > diff --git a/drivers/ddr/imx8m/ddrphy_train.c b/drivers/ddr/imx8m/ddrphy_train.c > index 9280c853aa1c..a4677f903c6b 100644 > --- a/drivers/ddr/imx8m/ddrphy_train.c > +++ b/drivers/ddr/imx8m/ddrphy_train.c > @@ -31,7 +31,7 @@ void ddr_load_train_code(enum fw_type type) > DDRC_PHY_DMEM, dmem, dsize); > } > > -int ddr_cfg_phy(struct dram_timing_info *dram_timing) > +int ddr_cfg_phy(struct dram_timing_info *dram_timing, enum ddrc_type type) > { > struct dram_cfg_param *dram_cfg; > struct dram_fsp_msg *fsp_msg; > @@ -54,7 +54,7 @@ int ddr_cfg_phy(struct dram_timing_info *dram_timing) > for (i = 0; i < dram_timing->fsp_msg_num; i++) { > pr_debug("DRAM PHY training for %dMTS\n", fsp_msg->drate); > /* set dram PHY input clocks to desired frequency */ > - ddrphy_init_set_dfi_clk(fsp_msg->drate); > + ddrphy_init_set_dfi_clk(fsp_msg->drate, type); > > /* load the dram training firmware image */ > dwc_ddrphy_apb_wr(0xd0000, 0x0); > diff --git a/drivers/ddr/imx8m/ddrphy_utils.c b/drivers/ddr/imx8m/ddrphy_utils.c > index c48372491015..9a4e1a22ee5e 100644 > --- a/drivers/ddr/imx8m/ddrphy_utils.c > +++ b/drivers/ddr/imx8m/ddrphy_utils.c > @@ -214,7 +214,7 @@ static struct imx_int_pll_rate_table *fracpll(u32 freq) > return NULL; > } > > -static int dram_pll_init(u32 freq) > +static int dram_frac_pll_init(u32 freq) > { > volatile int i; > u32 tmp; > @@ -261,35 +261,124 @@ static int dram_pll_init(u32 freq) > return 0; > } > > -void ddrphy_init_set_dfi_clk(unsigned int drate) > +#define SSCG_PLL_LOCK BIT(31) > +#define SSCG_PLL_DRAM_PLL_CLKE BIT(9) > +#define SSCG_PLL_PD BIT(7) > +#define SSCG_PLL_BYPASS1 BIT(5) > +#define SSCG_PLL_BYPASS2 BIT(4) > + > +#define SSCG_PLL_REF_DIVR2_MASK (0x3f << 19) > +#define SSCG_PLL_REF_DIVR2_VAL(n) (((n) << 19) & SSCG_PLL_REF_DIVR2_MASK) > +#define SSCG_PLL_FEEDBACK_DIV_F1_MASK (0x3f << 13) > +#define SSCG_PLL_FEEDBACK_DIV_F1_VAL(n) (((n) << 13) & SSCG_PLL_FEEDBACK_DIV_F1_MASK) > +#define SSCG_PLL_FEEDBACK_DIV_F2_MASK (0x3f << 7) > +#define SSCG_PLL_FEEDBACK_DIV_F2_VAL(n) (((n) << 7) & SSCG_PLL_FEEDBACK_DIV_F2_MASK) > +#define SSCG_PLL_OUTPUT_DIV_VAL_MASK (0x3f << 1) > +#define SSCG_PLL_OUTPUT_DIV_VAL(n) (((n) << 1) & SSCG_PLL_OUTPUT_DIV_VAL_MASK) > + > +static int dram_sscg_pll_init(u32 freq) > +{ > + u32 val; > + void __iomem *pll_base = IOMEM(MX8M_ANATOP_BASE_ADDR) + 0x60; > + > + /* Bypass */ > + setbits_le32(pll_base, SSCG_PLL_BYPASS1 | SSCG_PLL_BYPASS2); > + > + val = readl(pll_base + 0x8); > + val &= ~(SSCG_PLL_OUTPUT_DIV_VAL_MASK | > + SSCG_PLL_FEEDBACK_DIV_F2_MASK | > + SSCG_PLL_FEEDBACK_DIV_F1_MASK | > + SSCG_PLL_REF_DIVR2_MASK); > + > + switch (freq) { > + case MHZ(800): > + val |= SSCG_PLL_OUTPUT_DIV_VAL(0); > + val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(11); > + val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(39); > + val |= SSCG_PLL_REF_DIVR2_VAL(29); > + break; > + case MHZ(600): > + val |= SSCG_PLL_OUTPUT_DIV_VAL(1); > + val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(17); > + val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(39); > + val |= SSCG_PLL_REF_DIVR2_VAL(29); > + break; > + case MHZ(400): > + val |= SSCG_PLL_OUTPUT_DIV_VAL(1); > + val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(11); > + val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(39); > + val |= SSCG_PLL_REF_DIVR2_VAL(29); > + break; > + case MHZ(167): > + val |= SSCG_PLL_OUTPUT_DIV_VAL(3); > + val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(8); > + val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(45); > + val |= SSCG_PLL_REF_DIVR2_VAL(30); > + break; > + default: > + break; > + } > + > + writel(val, pll_base + 0x8); > + > + /* Clear power down bit */ > + clrbits_le32(pll_base, SSCG_PLL_PD); > + /* Enable PLL */ > + setbits_le32(pll_base, SSCG_PLL_DRAM_PLL_CLKE); > + > + /* Clear bypass */ > + clrbits_le32(pll_base, SSCG_PLL_BYPASS1); > + udelay(100); > + clrbits_le32(pll_base, SSCG_PLL_BYPASS2); > + /* Wait lock */ > + while (!(readl(pll_base) & SSCG_PLL_LOCK)) > + ; > + > + return 0; > +} > + > +static int dram_pll_init(u32 freq, enum ddrc_type type) > +{ > + switch (type) { > + case DDRC_TYPE_MQ: > + return dram_sscg_pll_init(freq); > + case DDRC_TYPE_MM: > + case DDRC_TYPE_MP: > + return dram_frac_pll_init(freq); > + default: > + return -ENODEV; > + } > +} > + > +void ddrphy_init_set_dfi_clk(unsigned int drate, enum ddrc_type type) > { > switch (drate) { > case 4000: > - dram_pll_init(MHZ(1000)); > + dram_pll_init(MHZ(1000), type); > dram_disable_bypass(); > break; > case 3200: > - dram_pll_init(MHZ(800)); > + dram_pll_init(MHZ(800), type); > dram_disable_bypass(); > break; > case 3000: > - dram_pll_init(MHZ(750)); > + dram_pll_init(MHZ(750), type); > dram_disable_bypass(); > break; > case 2400: > - dram_pll_init(MHZ(600)); > + dram_pll_init(MHZ(600), type); > dram_disable_bypass(); > break; > case 1600: > - dram_pll_init(MHZ(400)); > + dram_pll_init(MHZ(400), type); > dram_disable_bypass(); > break; > case 1066: > - dram_pll_init(MHZ(266)); > + dram_pll_init(MHZ(266),type); > dram_disable_bypass(); > break; > case 667: > - dram_pll_init(MHZ(167)); > + dram_pll_init(MHZ(167), type); > dram_disable_bypass(); > break; > case 400: > diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h > index a5a610909212..78b15f1d461a 100644 > --- a/include/soc/imx8m/ddr.h > +++ b/include/soc/imx8m/ddr.h > @@ -372,14 +372,14 @@ enum ddrc_type { > int imx8mm_ddr_init(struct dram_timing_info *timing_info); > int imx8mq_ddr_init(struct dram_timing_info *timing_info); > int imx8mp_ddr_init(struct dram_timing_info *timing_info); > -int ddr_cfg_phy(struct dram_timing_info *timing_info); > +int ddr_cfg_phy(struct dram_timing_info *timing_info, enum ddrc_type type); > void load_lpddr4_phy_pie(void); > void ddrphy_trained_csr_save(struct dram_cfg_param *param, unsigned int num); > void dram_config_save(struct dram_timing_info *info, unsigned long base); > > /* utils function for ddr phy training */ > int wait_ddrphy_training_complete(void); > -void ddrphy_init_set_dfi_clk(unsigned int drate); > +void ddrphy_init_set_dfi_clk(unsigned int drate, enum ddrc_type type); > void ddrphy_init_read_msg_block(enum fw_type type); > > void update_umctl2_rank_space_setting(unsigned int pstat_num, > -- > 2.29.2 > > > _______________________________________________ > barebox mailing list > barebox@xxxxxxxxxxxxxxxxxxx > http://lists.infradead.org/mailman/listinfo/barebox > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox