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 <[email protected]>
> ---
>  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
> [email protected]
> 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
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to