99
1010#include <linux/clk.h>
1111#include <linux/dma-mapping.h>
12+ #include <linux/iopoll.h>
1213#include <linux/kernel.h>
1314#include <linux/module.h>
1415#include <linux/of.h>
16+ #include <linux/of_device.h>
1517#include <linux/sizes.h>
1618
1719#include "sdhci-pltfm.h"
2123/* DWCMSHC specific Mode Select value */
2224#define DWCMSHC_CTRL_HS400 0x7
2325
26+ /* DWC IP vendor area 1 pointer */
27+ #define DWCMSHC_P_VENDOR_AREA1 0xe8
28+ #define DWCMSHC_AREA1_MASK GENMASK(11, 0)
29+ /* Offset inside the vendor area 1 */
30+ #define DWCMSHC_HOST_CTRL3 0x8
31+ #define DWCMSHC_EMMC_CONTROL 0x2c
32+ #define DWCMSHC_ENHANCED_STROBE BIT(8)
33+ #define DWCMSHC_EMMC_ATCTRL 0x40
34+
35+ /* Rockchip specific Registers */
36+ #define DWCMSHC_EMMC_DLL_CTRL 0x800
37+ #define DWCMSHC_EMMC_DLL_RXCLK 0x804
38+ #define DWCMSHC_EMMC_DLL_TXCLK 0x808
39+ #define DWCMSHC_EMMC_DLL_STRBIN 0x80c
40+ #define DLL_STRBIN_TAPNUM_FROM_SW BIT(24)
41+ #define DWCMSHC_EMMC_DLL_STATUS0 0x840
42+ #define DWCMSHC_EMMC_DLL_START BIT(0)
43+ #define DWCMSHC_EMMC_DLL_LOCKED BIT(8)
44+ #define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9)
45+ #define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29
46+ #define DWCMSHC_EMMC_DLL_START_POINT 16
47+ #define DWCMSHC_EMMC_DLL_INC 8
48+ #define DWCMSHC_EMMC_DLL_DLYENA BIT(27)
49+ #define DLL_TXCLK_TAPNUM_DEFAULT 0x8
50+ #define DLL_STRBIN_TAPNUM_DEFAULT 0x8
51+ #define DLL_TXCLK_TAPNUM_FROM_SW BIT(24)
52+ #define DLL_RXCLK_NO_INVERTER 1
53+ #define DLL_RXCLK_INVERTER 0
54+ #define DLL_LOCK_WO_TMOUT (x ) \
55+ ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
56+ (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
57+ #define RK3568_MAX_CLKS 3
58+
2459#define BOUNDARY_OK (addr , len ) \
2560 ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
2661
62+ struct rk3568_priv {
63+ /* Rockchip specified optional clocks */
64+ struct clk_bulk_data rockchip_clks [RK3568_MAX_CLKS ];
65+ u8 txclk_tapnum ;
66+ };
67+
2768struct dwcmshc_priv {
2869 struct clk * bus_clk ;
70+ int vendor_specific_area1 ; /* P_VENDOR_SPECIFIC_AREA reg */
71+ void * priv ; /* pointer to SoC private stuff */
2972};
3073
3174/*
@@ -100,6 +143,107 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
100143 sdhci_writew (host , ctrl_2 , SDHCI_HOST_CONTROL2 );
101144}
102145
146+ static void dwcmshc_hs400_enhanced_strobe (struct mmc_host * mmc ,
147+ struct mmc_ios * ios )
148+ {
149+ u32 vendor ;
150+ struct sdhci_host * host = mmc_priv (mmc );
151+ struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
152+ struct dwcmshc_priv * priv = sdhci_pltfm_priv (pltfm_host );
153+ int reg = priv -> vendor_specific_area1 + DWCMSHC_EMMC_CONTROL ;
154+
155+ vendor = sdhci_readl (host , reg );
156+ if (ios -> enhanced_strobe )
157+ vendor |= DWCMSHC_ENHANCED_STROBE ;
158+ else
159+ vendor &= ~DWCMSHC_ENHANCED_STROBE ;
160+
161+ sdhci_writel (host , vendor , reg );
162+ }
163+
164+ static void dwcmshc_rk3568_set_clock (struct sdhci_host * host , unsigned int clock )
165+ {
166+ struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
167+ struct dwcmshc_priv * dwc_priv = sdhci_pltfm_priv (pltfm_host );
168+ struct rk3568_priv * priv = dwc_priv -> priv ;
169+ u8 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT ;
170+ u32 extra , reg ;
171+ int err ;
172+
173+ host -> mmc -> actual_clock = 0 ;
174+
175+ /*
176+ * DO NOT TOUCH THIS SETTING. RX clk inverter unit is enabled
177+ * by default, but it shouldn't be enabled. We should anyway
178+ * disable it before issuing any cmds.
179+ */
180+ extra = DWCMSHC_EMMC_DLL_DLYENA |
181+ DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL ;
182+ sdhci_writel (host , extra , DWCMSHC_EMMC_DLL_RXCLK );
183+
184+ if (clock == 0 )
185+ return ;
186+
187+ /* Rockchip platform only support 375KHz for identify mode */
188+ if (clock <= 400000 )
189+ clock = 375000 ;
190+
191+ err = clk_set_rate (pltfm_host -> clk , clock );
192+ if (err )
193+ dev_err (mmc_dev (host -> mmc ), "fail to set clock %d" , clock );
194+
195+ sdhci_set_clock (host , clock );
196+
197+ /* Disable cmd conflict check */
198+ reg = dwc_priv -> vendor_specific_area1 + DWCMSHC_HOST_CTRL3 ;
199+ extra = sdhci_readl (host , reg );
200+ extra &= ~BIT (0 );
201+ sdhci_writel (host , extra , reg );
202+
203+ if (clock <= 400000 ) {
204+ /* Disable DLL to reset sample clock */
205+ sdhci_writel (host , 0 , DWCMSHC_EMMC_DLL_CTRL );
206+ return ;
207+ }
208+
209+ /* Reset DLL */
210+ sdhci_writel (host , BIT (1 ), DWCMSHC_EMMC_DLL_CTRL );
211+ udelay (1 );
212+ sdhci_writel (host , 0x0 , DWCMSHC_EMMC_DLL_CTRL );
213+
214+ /* Init DLL settings */
215+ extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT |
216+ 0x2 << DWCMSHC_EMMC_DLL_INC |
217+ DWCMSHC_EMMC_DLL_START ;
218+ sdhci_writel (host , extra , DWCMSHC_EMMC_DLL_CTRL );
219+ err = readl_poll_timeout (host -> ioaddr + DWCMSHC_EMMC_DLL_STATUS0 ,
220+ extra , DLL_LOCK_WO_TMOUT (extra ), 1 ,
221+ 500 * USEC_PER_MSEC );
222+ if (err ) {
223+ dev_err (mmc_dev (host -> mmc ), "DLL lock timeout!\n" );
224+ return ;
225+ }
226+
227+ extra = 0x1 << 16 | /* tune clock stop en */
228+ 0x2 << 17 | /* pre-change delay */
229+ 0x3 << 19 ; /* post-change delay */
230+ sdhci_writel (host , extra , dwc_priv -> vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL );
231+
232+ if (host -> mmc -> ios .timing == MMC_TIMING_MMC_HS200 ||
233+ host -> mmc -> ios .timing == MMC_TIMING_MMC_HS400 )
234+ txclk_tapnum = priv -> txclk_tapnum ;
235+
236+ extra = DWCMSHC_EMMC_DLL_DLYENA |
237+ DLL_TXCLK_TAPNUM_FROM_SW |
238+ txclk_tapnum ;
239+ sdhci_writel (host , extra , DWCMSHC_EMMC_DLL_TXCLK );
240+
241+ extra = DWCMSHC_EMMC_DLL_DLYENA |
242+ DLL_STRBIN_TAPNUM_DEFAULT |
243+ DLL_STRBIN_TAPNUM_FROM_SW ;
244+ sdhci_writel (host , extra , DWCMSHC_EMMC_DLL_STRBIN );
245+ }
246+
103247static const struct sdhci_ops sdhci_dwcmshc_ops = {
104248 .set_clock = sdhci_set_clock ,
105249 .set_bus_width = sdhci_set_bus_width ,
@@ -109,21 +253,93 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = {
109253 .adma_write_desc = dwcmshc_adma_write_desc ,
110254};
111255
256+ static const struct sdhci_ops sdhci_dwcmshc_rk3568_ops = {
257+ .set_clock = dwcmshc_rk3568_set_clock ,
258+ .set_bus_width = sdhci_set_bus_width ,
259+ .set_uhs_signaling = dwcmshc_set_uhs_signaling ,
260+ .get_max_clock = sdhci_pltfm_clk_get_max_clock ,
261+ .reset = sdhci_reset ,
262+ .adma_write_desc = dwcmshc_adma_write_desc ,
263+ };
264+
112265static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
113266 .ops = & sdhci_dwcmshc_ops ,
114267 .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
115268 .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN ,
116269};
117270
271+ static const struct sdhci_pltfm_data sdhci_dwcmshc_rk3568_pdata = {
272+ .ops = & sdhci_dwcmshc_rk3568_ops ,
273+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
274+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL ,
275+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
276+ SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN ,
277+ };
278+
279+ static int dwcmshc_rk3568_init (struct sdhci_host * host , struct dwcmshc_priv * dwc_priv )
280+ {
281+ int err ;
282+ struct rk3568_priv * priv = dwc_priv -> priv ;
283+
284+ priv -> rockchip_clks [0 ].id = "axi" ;
285+ priv -> rockchip_clks [1 ].id = "block" ;
286+ priv -> rockchip_clks [2 ].id = "timer" ;
287+ err = devm_clk_bulk_get_optional (mmc_dev (host -> mmc ), RK3568_MAX_CLKS ,
288+ priv -> rockchip_clks );
289+ if (err ) {
290+ dev_err (mmc_dev (host -> mmc ), "failed to get clocks %d\n" , err );
291+ return err ;
292+ }
293+
294+ err = clk_bulk_prepare_enable (RK3568_MAX_CLKS , priv -> rockchip_clks );
295+ if (err ) {
296+ dev_err (mmc_dev (host -> mmc ), "failed to enable clocks %d\n" , err );
297+ return err ;
298+ }
299+
300+ if (of_property_read_u8 (mmc_dev (host -> mmc )-> of_node , "rockchip,txclk-tapnum" ,
301+ & priv -> txclk_tapnum ))
302+ priv -> txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT ;
303+
304+ /* Disable cmd conflict check */
305+ sdhci_writel (host , 0x0 , dwc_priv -> vendor_specific_area1 + DWCMSHC_HOST_CTRL3 );
306+ /* Reset previous settings */
307+ sdhci_writel (host , 0 , DWCMSHC_EMMC_DLL_TXCLK );
308+ sdhci_writel (host , 0 , DWCMSHC_EMMC_DLL_STRBIN );
309+
310+ return 0 ;
311+ }
312+
313+ static const struct of_device_id sdhci_dwcmshc_dt_ids [] = {
314+ {
315+ .compatible = "rockchip,rk3568-dwcmshc" ,
316+ .data = & sdhci_dwcmshc_rk3568_pdata ,
317+ },
318+ {
319+ .compatible = "snps,dwcmshc-sdhci" ,
320+ .data = & sdhci_dwcmshc_pdata ,
321+ },
322+ {},
323+ };
324+ MODULE_DEVICE_TABLE (of , sdhci_dwcmshc_dt_ids );
325+
118326static int dwcmshc_probe (struct platform_device * pdev )
119327{
120328 struct sdhci_pltfm_host * pltfm_host ;
121329 struct sdhci_host * host ;
122330 struct dwcmshc_priv * priv ;
331+ struct rk3568_priv * rk_priv = NULL ;
332+ const struct sdhci_pltfm_data * pltfm_data ;
123333 int err ;
124334 u32 extra ;
125335
126- host = sdhci_pltfm_init (pdev , & sdhci_dwcmshc_pdata ,
336+ pltfm_data = of_device_get_match_data (& pdev -> dev );
337+ if (!pltfm_data ) {
338+ dev_err (& pdev -> dev , "Error: No device match data found\n" );
339+ return - ENODEV ;
340+ }
341+
342+ host = sdhci_pltfm_init (pdev , pltfm_data ,
127343 sizeof (struct dwcmshc_priv ));
128344 if (IS_ERR (host ))
129345 return PTR_ERR (host );
@@ -159,7 +375,23 @@ static int dwcmshc_probe(struct platform_device *pdev)
159375
160376 sdhci_get_of_property (pdev );
161377
378+ priv -> vendor_specific_area1 =
379+ sdhci_readl (host , DWCMSHC_P_VENDOR_AREA1 ) & DWCMSHC_AREA1_MASK ;
380+
162381 host -> mmc_host_ops .request = dwcmshc_request ;
382+ host -> mmc_host_ops .hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe ;
383+
384+ if (pltfm_data == & sdhci_dwcmshc_rk3568_pdata ) {
385+ rk_priv = devm_kzalloc (& pdev -> dev , sizeof (struct rk3568_priv ), GFP_KERNEL );
386+ if (!rk_priv )
387+ goto err_clk ;
388+
389+ priv -> priv = rk_priv ;
390+
391+ err = dwcmshc_rk3568_init (host , priv );
392+ if (err )
393+ goto err_clk ;
394+ }
163395
164396 err = sdhci_add_host (host );
165397 if (err )
@@ -170,6 +402,9 @@ static int dwcmshc_probe(struct platform_device *pdev)
170402err_clk :
171403 clk_disable_unprepare (pltfm_host -> clk );
172404 clk_disable_unprepare (priv -> bus_clk );
405+ if (rk_priv )
406+ clk_bulk_disable_unprepare (RK3568_MAX_CLKS ,
407+ rk_priv -> rockchip_clks );
173408free_pltfm :
174409 sdhci_pltfm_free (pdev );
175410 return err ;
@@ -180,12 +415,15 @@ static int dwcmshc_remove(struct platform_device *pdev)
180415 struct sdhci_host * host = platform_get_drvdata (pdev );
181416 struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
182417 struct dwcmshc_priv * priv = sdhci_pltfm_priv (pltfm_host );
418+ struct rk3568_priv * rk_priv = priv -> priv ;
183419
184420 sdhci_remove_host (host , 0 );
185421
186422 clk_disable_unprepare (pltfm_host -> clk );
187423 clk_disable_unprepare (priv -> bus_clk );
188-
424+ if (rk_priv )
425+ clk_bulk_disable_unprepare (RK3568_MAX_CLKS ,
426+ rk_priv -> rockchip_clks );
189427 sdhci_pltfm_free (pdev );
190428
191429 return 0 ;
@@ -197,6 +435,7 @@ static int dwcmshc_suspend(struct device *dev)
197435 struct sdhci_host * host = dev_get_drvdata (dev );
198436 struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
199437 struct dwcmshc_priv * priv = sdhci_pltfm_priv (pltfm_host );
438+ struct rk3568_priv * rk_priv = priv -> priv ;
200439 int ret ;
201440
202441 ret = sdhci_suspend_host (host );
@@ -207,6 +446,10 @@ static int dwcmshc_suspend(struct device *dev)
207446 if (!IS_ERR (priv -> bus_clk ))
208447 clk_disable_unprepare (priv -> bus_clk );
209448
449+ if (rk_priv )
450+ clk_bulk_disable_unprepare (RK3568_MAX_CLKS ,
451+ rk_priv -> rockchip_clks );
452+
210453 return ret ;
211454}
212455
@@ -215,6 +458,7 @@ static int dwcmshc_resume(struct device *dev)
215458 struct sdhci_host * host = dev_get_drvdata (dev );
216459 struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
217460 struct dwcmshc_priv * priv = sdhci_pltfm_priv (pltfm_host );
461+ struct rk3568_priv * rk_priv = priv -> priv ;
218462 int ret ;
219463
220464 ret = clk_prepare_enable (pltfm_host -> clk );
@@ -227,18 +471,19 @@ static int dwcmshc_resume(struct device *dev)
227471 return ret ;
228472 }
229473
474+ if (rk_priv ) {
475+ ret = clk_bulk_prepare_enable (RK3568_MAX_CLKS ,
476+ rk_priv -> rockchip_clks );
477+ if (ret )
478+ return ret ;
479+ }
480+
230481 return sdhci_resume_host (host );
231482}
232483#endif
233484
234485static SIMPLE_DEV_PM_OPS (dwcmshc_pmops , dwcmshc_suspend , dwcmshc_resume ) ;
235486
236- static const struct of_device_id sdhci_dwcmshc_dt_ids [] = {
237- { .compatible = "snps,dwcmshc-sdhci" },
238- {}
239- };
240- MODULE_DEVICE_TABLE (of , sdhci_dwcmshc_dt_ids );
241-
242487static struct platform_driver sdhci_dwcmshc_driver = {
243488 .driver = {
244489 .name = "sdhci-dwcmshc" ,
0 commit comments