clk: stm32mp1: add set_rate for DDRPHYC clock
Add the DDRPHYC support for clk_set_rate, used in DDR interactive mode Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
This commit is contained in:
		
							parent
							
								
									27a986d4e4
								
							
						
					
					
						commit
						c3e828bff2
					
				| 
						 | 
					@ -1448,6 +1448,71 @@ static void pll_csg(struct stm32mp1_clk_priv *priv, int pll_id, u32 *csg)
 | 
				
			||||||
	setbits_le32(priv->base + pll[pll_id].pllxcr, RCC_PLLNCR_SSCG_CTRL);
 | 
						setbits_le32(priv->base + pll[pll_id].pllxcr, RCC_PLLNCR_SSCG_CTRL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static  __maybe_unused int pll_set_rate(struct udevice *dev,
 | 
				
			||||||
 | 
										int pll_id,
 | 
				
			||||||
 | 
										int div_id,
 | 
				
			||||||
 | 
										unsigned long clk_rate)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct stm32mp1_clk_priv *priv = dev_get_priv(dev);
 | 
				
			||||||
 | 
						unsigned int pllcfg[PLLCFG_NB];
 | 
				
			||||||
 | 
						ofnode plloff;
 | 
				
			||||||
 | 
						char name[12];
 | 
				
			||||||
 | 
						const struct stm32mp1_clk_pll *pll = priv->data->pll;
 | 
				
			||||||
 | 
						enum stm32mp1_plltype type = pll[pll_id].plltype;
 | 
				
			||||||
 | 
						int divm, divn, divy;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						ulong fck_ref;
 | 
				
			||||||
 | 
						u32 fracv;
 | 
				
			||||||
 | 
						u64 value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (div_id > _DIV_NB)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sprintf(name, "st,pll@%d", pll_id);
 | 
				
			||||||
 | 
						plloff = dev_read_subnode(dev, name);
 | 
				
			||||||
 | 
						if (!ofnode_valid(plloff))
 | 
				
			||||||
 | 
							return -FDT_ERR_NOTFOUND;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ofnode_read_u32_array(plloff, "cfg",
 | 
				
			||||||
 | 
									    pllcfg, PLLCFG_NB);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return -FDT_ERR_NOTFOUND;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fck_ref = pll_get_fref_ck(priv, pll_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						divm = pllcfg[PLLCFG_M];
 | 
				
			||||||
 | 
						/* select output divider = 0: for _DIV_P, 1:_DIV_Q 2:_DIV_R */
 | 
				
			||||||
 | 
						divy = pllcfg[PLLCFG_P + div_id];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* For: PLL1 & PLL2 => VCO is * 2 but ck_pll_y is also / 2
 | 
				
			||||||
 | 
						 * So same final result than PLL2 et 4
 | 
				
			||||||
 | 
						 * with FRACV
 | 
				
			||||||
 | 
						 * Fck_pll_y = Fck_ref * ((DIVN + 1) + FRACV / 2^13)
 | 
				
			||||||
 | 
						 *             / (DIVy + 1) * (DIVM + 1)
 | 
				
			||||||
 | 
						 * value = (DIVN + 1) * 2^13 + FRACV / 2^13
 | 
				
			||||||
 | 
						 *       = Fck_pll_y (DIVy + 1) * (DIVM + 1) * 2^13 / Fck_ref
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						value = ((u64)clk_rate * (divy + 1) * (divm + 1)) << 13;
 | 
				
			||||||
 | 
						value = lldiv(value, fck_ref);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						divn = (value >> 13) - 1;
 | 
				
			||||||
 | 
						if (divn < DIVN_MIN ||
 | 
				
			||||||
 | 
						    divn > stm32mp1_pll[type].divn_max) {
 | 
				
			||||||
 | 
							pr_err("divn invalid = %d", divn);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fracv = value - ((divn + 1) << 13);
 | 
				
			||||||
 | 
						pllcfg[PLLCFG_N] = divn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* reconfigure PLL */
 | 
				
			||||||
 | 
						pll_stop(priv, pll_id);
 | 
				
			||||||
 | 
						pll_config(priv, pll_id, pllcfg, fracv);
 | 
				
			||||||
 | 
						pll_start(priv, pll_id);
 | 
				
			||||||
 | 
						pll_output(priv, pll_id, pllcfg[PLLCFG_O]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int set_clksrc(struct stm32mp1_clk_priv *priv, unsigned int clksrc)
 | 
					static int set_clksrc(struct stm32mp1_clk_priv *priv, unsigned int clksrc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 address = priv->base + (clksrc >> 4);
 | 
						u32 address = priv->base + (clksrc >> 4);
 | 
				
			||||||
| 
						 | 
					@ -1820,6 +1885,11 @@ static ulong stm32mp1_clk_set_rate(struct clk *clk, unsigned long clk_rate)
 | 
				
			||||||
	int p;
 | 
						int p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (clk->id) {
 | 
						switch (clk->id) {
 | 
				
			||||||
 | 
					#if defined(STM32MP1_CLOCK_TREE_INIT) && \
 | 
				
			||||||
 | 
						defined(CONFIG_STM32MP1_DDR_INTERACTIVE)
 | 
				
			||||||
 | 
						case DDRPHYC:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	case LTDC_PX:
 | 
						case LTDC_PX:
 | 
				
			||||||
	case DSI_PX:
 | 
						case DSI_PX:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -1833,6 +1903,19 @@ static ulong stm32mp1_clk_set_rate(struct clk *clk, unsigned long clk_rate)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (p) {
 | 
						switch (p) {
 | 
				
			||||||
 | 
					#if defined(STM32MP1_CLOCK_TREE_INIT) && \
 | 
				
			||||||
 | 
						defined(CONFIG_STM32MP1_DDR_INTERACTIVE)
 | 
				
			||||||
 | 
						case _PLL2_R: /* DDRPHYC */
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* only for change DDR clock in interactive mode */
 | 
				
			||||||
 | 
							ulong result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							set_clksrc(priv, CLK_AXI_HSI);
 | 
				
			||||||
 | 
							result = pll_set_rate(clk->dev,  _PLL2, _DIV_R, clk_rate);
 | 
				
			||||||
 | 
							set_clksrc(priv, CLK_AXI_PLL2P);
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	case _PLL4_Q:
 | 
						case _PLL4_Q:
 | 
				
			||||||
		/* for LTDC_PX and DSI_PX case */
 | 
							/* for LTDC_PX and DSI_PX case */
 | 
				
			||||||
		return pll_set_output_rate(clk->dev, _PLL4, _DIV_Q, clk_rate);
 | 
							return pll_set_output_rate(clk->dev, _PLL4, _DIV_Q, clk_rate);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue