mmc: tmio: Switch to clock framework
Switch the driver to using clk_get_rate()/clk_set_rate() instead of
caching the mclk frequency in it's private data. This is required on
the SDHI variant of the controller, where the upstream mclk need to
be adjusted when using UHS modes.
Platforms which do not support clock framework or do not support it
in eg. SPL default to 100 MHz clock.
Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
---
V2: - Fix build on certain platforms using SPL without clock framework
V3: - Turn clk_get_rate into a callback and fill it as needed on both
      renesas and socionext platforms
			
			
This commit is contained in:
		
							parent
							
								
									eb2acbafff
								
							
						
					
					
						commit
						8ec6a04b6b
					
				|  | @ -358,15 +358,21 @@ static const struct udevice_id renesas_sdhi_match[] = { | ||||||
| 	{ /* sentinel */ } | 	{ /* sentinel */ } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static ulong renesas_sdhi_clk_get_rate(struct tmio_sd_priv *priv) | ||||||
|  | { | ||||||
|  | 	return clk_get_rate(&priv->clk); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int renesas_sdhi_probe(struct udevice *dev) | static int renesas_sdhi_probe(struct udevice *dev) | ||||||
| { | { | ||||||
| 	struct tmio_sd_priv *priv = dev_get_priv(dev); | 	struct tmio_sd_priv *priv = dev_get_priv(dev); | ||||||
| 	u32 quirks = dev_get_driver_data(dev); | 	u32 quirks = dev_get_driver_data(dev); | ||||||
| 	struct fdt_resource reg_res; | 	struct fdt_resource reg_res; | ||||||
| 	struct clk clk; |  | ||||||
| 	DECLARE_GLOBAL_DATA_PTR; | 	DECLARE_GLOBAL_DATA_PTR; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
|  | 	priv->clk_get_rate = renesas_sdhi_clk_get_rate; | ||||||
|  | 
 | ||||||
| 	if (quirks == RENESAS_GEN2_QUIRKS) { | 	if (quirks == RENESAS_GEN2_QUIRKS) { | ||||||
| 		ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), | 		ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), | ||||||
| 				       "reg", 0, ®_res); | 				       "reg", 0, ®_res); | ||||||
|  | @ -380,22 +386,21 @@ static int renesas_sdhi_probe(struct udevice *dev) | ||||||
| 			quirks |= TMIO_SD_CAP_16BIT; | 			quirks |= TMIO_SD_CAP_16BIT; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = clk_get_by_index(dev, 0, &clk); | 	ret = clk_get_by_index(dev, 0, &priv->clk); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		dev_err(dev, "failed to get host clock\n"); | 		dev_err(dev, "failed to get host clock\n"); | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* set to max rate */ | 	/* set to max rate */ | ||||||
| 	priv->mclk = clk_set_rate(&clk, ULONG_MAX); | 	ret = clk_set_rate(&priv->clk, 200000000); | ||||||
| 	if (IS_ERR_VALUE(priv->mclk)) { | 	if (ret < 0) { | ||||||
| 		dev_err(dev, "failed to set rate for host clock\n"); | 		dev_err(dev, "failed to set rate for host clock\n"); | ||||||
| 		clk_free(&clk); | 		clk_free(&priv->clk); | ||||||
| 		return priv->mclk; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = clk_enable(&clk); | 	ret = clk_enable(&priv->clk); | ||||||
| 	clk_free(&clk); |  | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		dev_err(dev, "failed to enable host clock\n"); | 		dev_err(dev, "failed to enable host clock\n"); | ||||||
| 		return ret; | 		return ret; | ||||||
|  |  | ||||||
|  | @ -555,16 +555,24 @@ static void tmio_sd_set_ddr_mode(struct tmio_sd_priv *priv, | ||||||
| 	tmio_sd_writel(priv, tmp, TMIO_SD_IF_MODE); | 	tmio_sd_writel(priv, tmp, TMIO_SD_IF_MODE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static ulong tmio_sd_clk_get_rate(struct tmio_sd_priv *priv) | ||||||
|  | { | ||||||
|  | 	return priv->clk_get_rate(priv); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv, | static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv, | ||||||
| 				     struct mmc *mmc) | 				     struct mmc *mmc) | ||||||
| { | { | ||||||
| 	unsigned int divisor; | 	unsigned int divisor; | ||||||
| 	u32 val, tmp; | 	u32 val, tmp; | ||||||
|  | 	ulong mclk; | ||||||
| 
 | 
 | ||||||
| 	if (!mmc->clock) | 	if (!mmc->clock) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	divisor = DIV_ROUND_UP(priv->mclk, mmc->clock); | 	mclk = tmio_sd_clk_get_rate(priv); | ||||||
|  | 
 | ||||||
|  | 	divisor = DIV_ROUND_UP(mclk, mmc->clock); | ||||||
| 
 | 
 | ||||||
| 	if (divisor <= 1) | 	if (divisor <= 1) | ||||||
| 		val = (priv->caps & TMIO_SD_CAP_RCAR) ? | 		val = (priv->caps & TMIO_SD_CAP_RCAR) ? | ||||||
|  | @ -708,6 +716,7 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks) | ||||||
| 	struct tmio_sd_priv *priv = dev_get_priv(dev); | 	struct tmio_sd_priv *priv = dev_get_priv(dev); | ||||||
| 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); | 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); | ||||||
| 	fdt_addr_t base; | 	fdt_addr_t base; | ||||||
|  | 	ulong mclk; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	base = devfdt_get_addr(dev); | 	base = devfdt_get_addr(dev); | ||||||
|  | @ -750,10 +759,12 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks) | ||||||
| 
 | 
 | ||||||
| 	tmio_sd_host_init(priv); | 	tmio_sd_host_init(priv); | ||||||
| 
 | 
 | ||||||
|  | 	mclk = tmio_sd_clk_get_rate(priv); | ||||||
|  | 
 | ||||||
| 	plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; | 	plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; | ||||||
| 	plat->cfg.f_min = priv->mclk / | 	plat->cfg.f_min = mclk / | ||||||
| 			(priv->caps & TMIO_SD_CAP_DIV1024 ? 1024 : 512); | 			(priv->caps & TMIO_SD_CAP_DIV1024 ? 1024 : 512); | ||||||
| 	plat->cfg.f_max = priv->mclk; | 	plat->cfg.f_max = mclk; | ||||||
| 	plat->cfg.b_max = U32_MAX; /* max value of TMIO_SD_SECCNT */ | 	plat->cfg.b_max = U32_MAX; /* max value of TMIO_SD_SECCNT */ | ||||||
| 
 | 
 | ||||||
| 	upriv->mmc = &plat->mmc; | 	upriv->mmc = &plat->mmc; | ||||||
|  |  | ||||||
|  | @ -117,7 +117,6 @@ struct tmio_sd_plat { | ||||||
| 
 | 
 | ||||||
| struct tmio_sd_priv { | struct tmio_sd_priv { | ||||||
| 	void __iomem			*regbase; | 	void __iomem			*regbase; | ||||||
| 	unsigned long			mclk; |  | ||||||
| 	unsigned int			version; | 	unsigned int			version; | ||||||
| 	u32				caps; | 	u32				caps; | ||||||
| #define TMIO_SD_CAP_NONREMOVABLE	BIT(0)	/* Nonremovable e.g. eMMC */ | #define TMIO_SD_CAP_NONREMOVABLE	BIT(0)	/* Nonremovable e.g. eMMC */ | ||||||
|  | @ -133,6 +132,10 @@ struct tmio_sd_priv { | ||||||
| #ifdef CONFIG_DM_REGULATOR | #ifdef CONFIG_DM_REGULATOR | ||||||
| 	struct udevice *vqmmc_dev; | 	struct udevice *vqmmc_dev; | ||||||
| #endif | #endif | ||||||
|  | #if CONFIG_IS_ENABLED(CLK) | ||||||
|  | 	struct clk			clk; | ||||||
|  | #endif | ||||||
|  | 	ulong (*clk_get_rate)(struct tmio_sd_priv *); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, | int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, | ||||||
|  |  | ||||||
|  | @ -31,35 +31,45 @@ static const struct udevice_id uniphier_sd_match[] = { | ||||||
| 	{ /* sentinel */ } | 	{ /* sentinel */ } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static ulong uniphier_sd_clk_get_rate(struct tmio_sd_priv *priv) | ||||||
|  | { | ||||||
|  | #if CONFIG_IS_ENABLED(CLK) | ||||||
|  | 	return clk_get_rate(&priv->clk); | ||||||
|  | #elif CONFIG_SPL_BUILD | ||||||
|  | 	return 100000000; | ||||||
|  | #else | ||||||
|  | 	return 0; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int uniphier_sd_probe(struct udevice *dev) | static int uniphier_sd_probe(struct udevice *dev) | ||||||
| { | { | ||||||
| 	struct tmio_sd_priv *priv = dev_get_priv(dev); | 	struct tmio_sd_priv *priv = dev_get_priv(dev); | ||||||
|  | 
 | ||||||
|  | 	priv->clk_get_rate = uniphier_sd_clk_get_rate; | ||||||
|  | 
 | ||||||
| #ifndef CONFIG_SPL_BUILD | #ifndef CONFIG_SPL_BUILD | ||||||
| 	struct clk clk; |  | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	ret = clk_get_by_index(dev, 0, &clk); | 	ret = clk_get_by_index(dev, 0, &priv->clk); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		dev_err(dev, "failed to get host clock\n"); | 		dev_err(dev, "failed to get host clock\n"); | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* set to max rate */ | 	/* set to max rate */ | ||||||
| 	priv->mclk = clk_set_rate(&clk, ULONG_MAX); | 	ret = clk_set_rate(&priv->clk, ULONG_MAX); | ||||||
| 	if (IS_ERR_VALUE(priv->mclk)) { | 	if (ret < 0) { | ||||||
| 		dev_err(dev, "failed to set rate for host clock\n"); | 		dev_err(dev, "failed to set rate for host clock\n"); | ||||||
| 		clk_free(&clk); | 		clk_free(&priv->clk); | ||||||
| 		return priv->mclk; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = clk_enable(&clk); | 	ret = clk_enable(&priv->clk); | ||||||
| 	clk_free(&clk); |  | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		dev_err(dev, "failed to enable host clock\n"); | 		dev_err(dev, "failed to enable host clock\n"); | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
| #else |  | ||||||
| 	priv->mclk = 100000000; |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	return tmio_sd_probe(dev, 0); | 	return tmio_sd_probe(dev, 0); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue