xref: /rk3399_rockchip-uboot/drivers/mmc/rockchip_dw_mmc.c (revision 4a2b8db466479ddec6ee85f9fe9d7f934016be9a)
1 /*
2  * Copyright (c) 2013 Google, Inc
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <clk.h>
9 #include <dm.h>
10 #include <dt-structs.h>
11 #include <dwmmc.h>
12 #include <errno.h>
13 #include <mapmem.h>
14 #include <pwrseq.h>
15 #include <syscon.h>
16 #include <asm/gpio.h>
17 #include <asm/arch/clock.h>
18 #include <asm/arch/periph.h>
19 #include <linux/err.h>
20 
21 DECLARE_GLOBAL_DATA_PTR;
22 
23 struct rockchip_mmc_plat {
24 #if CONFIG_IS_ENABLED(OF_PLATDATA)
25 	struct dtd_rockchip_rk3288_dw_mshc dtplat;
26 #endif
27 	struct mmc_config cfg;
28 	struct mmc mmc;
29 };
30 
31 struct rockchip_dwmmc_priv {
32 	struct clk clk;
33 	struct clk sample_clk;
34 	struct dwmci_host host;
35 	int fifo_depth;
36 	bool fifo_mode;
37 	u32 minmax[2];
38 };
39 
40 #ifdef CONFIG_USING_KERNEL_DTB
41 int board_mmc_dm_reinit(struct udevice *dev)
42 {
43 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
44 
45 	if (!priv || !&priv->clk)
46 		return 0;
47 
48 	if (!memcmp(dev->name, "dwmmc", strlen("dwmmc")))
49 		return clk_get_by_index(dev, 0, &priv->clk);
50 	else
51 		return 0;
52 }
53 #endif
54 
55 #ifdef CONFIG_SPL_BUILD
56 __weak void mmc_gpio_init_direct(void) {}
57 #endif
58 
59 static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq)
60 {
61 	struct udevice *dev = host->priv;
62 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
63 	int ret;
64 
65 	/*
66 	 * If DDR52 8bit mode(only emmc work in 8bit mode),
67 	 * divider must be set 1
68 	 */
69 	if (mmc_card_ddr52(host->mmc) && host->mmc->bus_width == 8)
70 		freq *= 2;
71 
72 	ret = clk_set_rate(&priv->clk, freq);
73 	if (ret < 0) {
74 		debug("%s: err=%d\n", __func__, ret);
75 		return ret;
76 	}
77 
78 	return freq;
79 }
80 
81 static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev)
82 {
83 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
84 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
85 	struct dwmci_host *host = &priv->host;
86 
87 	host->name = dev->name;
88 	host->ioaddr = dev_read_addr_ptr(dev);
89 	host->buswidth = dev_read_u32_default(dev, "bus-width", 4);
90 	host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk;
91 	host->priv = dev;
92 
93 	/* use non-removeable as sdcard and emmc as judgement */
94 	if (dev_read_bool(dev, "non-removable"))
95 		host->dev_index = 0;
96 	else
97 		host->dev_index = 1;
98 
99 	priv->fifo_depth = dev_read_u32_default(dev, "fifo-depth", 0);
100 
101 	if (priv->fifo_depth < 0)
102 		return -EINVAL;
103 	priv->fifo_mode = dev_read_bool(dev, "fifo-mode");
104 
105 	/*
106 	 * 'clock-freq-min-max' is deprecated
107 	 * (see https://github.com/torvalds/linux/commit/b023030f10573de738bbe8df63d43acab64c9f7b)
108 	 */
109 	if (dev_read_u32_array(dev, "clock-freq-min-max", priv->minmax, 2)) {
110 		int val = dev_read_u32_default(dev, "max-frequency", -EINVAL);
111 
112 		if (val < 0)
113 			return val;
114 
115 		priv->minmax[0] = 400000;  /* 400 kHz */
116 		priv->minmax[1] = val;
117 	} else {
118 		debug("%s: 'clock-freq-min-max' property was deprecated.\n",
119 		      __func__);
120 	}
121 #endif
122 	return 0;
123 }
124 
125 static int rockchip_dwmmc_execute_tuning(struct dwmci_host *host, u32 opcode)
126 {
127 	int i = 0;
128 	int ret = -1;
129 	struct mmc *mmc = host->mmc;
130 	struct udevice *dev = host->priv;
131 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
132 
133 	if (IS_ERR(&priv->sample_clk))
134 		return -EIO;
135 
136 	if (mmc->default_phase > 0 && mmc->default_phase < 360) {
137 		ret = clk_set_phase(&priv->sample_clk, mmc->default_phase);
138 		if (ret)
139 			printf("set clk phase fail\n");
140 		else
141 			ret = mmc_send_tuning(mmc, opcode);
142 		mmc->default_phase = 0;
143 	}
144 	/*
145 	 * If use default_phase to tune successfully, return.
146 	 * Otherwise, use the othe phase to tune.
147 	 */
148 	if (!ret)
149 		return ret;
150 
151 	for (i = 0; i < 5; i++) {
152 		/* mmc->init_retry must be 0, 1, 2, 3 */
153 		if (mmc->init_retry == 4)
154 			mmc->init_retry = 0;
155 
156 		ret = clk_set_phase(&priv->sample_clk, 90 * mmc->init_retry);
157 		if (ret) {
158 			printf("set clk phase fail\n");
159 			break;
160 		}
161 		ret = mmc_send_tuning(mmc, opcode);
162 		debug("Tuning phase is %d, ret is %d\n", mmc->init_retry * 90, ret);
163 		mmc->init_retry++;
164 		if (!ret)
165 			break;
166 	}
167 
168 	return ret;
169 }
170 
171 static int rockchip_dwmmc_probe(struct udevice *dev)
172 {
173 	struct rockchip_mmc_plat *plat = dev_get_platdata(dev);
174 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
175 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
176 	struct dwmci_host *host = &priv->host;
177 	struct udevice *pwr_dev __maybe_unused;
178 	int ret;
179 
180 #ifdef CONFIG_SPL_BUILD
181 	mmc_gpio_init_direct();
182 #endif
183 #if CONFIG_IS_ENABLED(OF_PLATDATA)
184 	struct dtd_rockchip_rk3288_dw_mshc *dtplat = &plat->dtplat;
185 
186 	host->name = dev->name;
187 	host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
188 	host->buswidth = dtplat->bus_width;
189 	host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk;
190 	host->execute_tuning = rockchip_dwmmc_execute_tuning;
191 	host->priv = dev;
192 	host->dev_index = 0;
193 	priv->fifo_depth = dtplat->fifo_depth;
194 	priv->fifo_mode = 0;
195 	priv->minmax[0] = 400000;  /*  400 kHz */
196 	priv->minmax[1] = dtplat->max_frequency;
197 
198 	ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk);
199 	if (ret < 0)
200 		return ret;
201 #else
202 	ret = clk_get_by_index(dev, 0, &priv->clk);
203 	if (ret < 0)
204 		return ret;
205 
206 	ret = clk_get_by_name(dev, "ciu-sample", &priv->sample_clk);
207 	if (ret < 0)
208 		debug("MMC: sample clock not found, not support hs200!\n");
209 	host->execute_tuning = rockchip_dwmmc_execute_tuning;
210 #endif
211 	host->fifoth_val = MSIZE(DWMCI_MSIZE) |
212 		RX_WMARK(priv->fifo_depth / 2 - 1) |
213 		TX_WMARK(priv->fifo_depth / 2);
214 
215 	host->fifo_mode = priv->fifo_mode;
216 
217 #ifdef CONFIG_ROCKCHIP_RK3128
218 	host->stride_pio = true;
219 #else
220 	host->stride_pio = false;
221 #endif
222 
223 #ifdef CONFIG_PWRSEQ
224 	/* Enable power if needed */
225 	ret = uclass_get_device_by_phandle(UCLASS_PWRSEQ, dev, "mmc-pwrseq",
226 					   &pwr_dev);
227 	if (!ret) {
228 		ret = pwrseq_set_power(pwr_dev, true);
229 		if (ret)
230 			return ret;
231 	}
232 #endif
233 	dwmci_setup_cfg(&plat->cfg, host, priv->minmax[1], priv->minmax[0]);
234 	if (dev_read_bool(dev, "mmc-hs200-1_8v"))
235 		plat->cfg.host_caps |= MMC_MODE_HS200;
236 	plat->mmc.default_phase =
237 		dev_read_u32_default(dev, "default-sample-phase", 0);
238 	plat->mmc.init_retry = 0;
239 	host->mmc = &plat->mmc;
240 	host->mmc->priv = &priv->host;
241 	host->mmc->dev = dev;
242 	upriv->mmc = host->mmc;
243 
244 	return dwmci_probe(dev);
245 }
246 
247 static int rockchip_dwmmc_bind(struct udevice *dev)
248 {
249 	struct rockchip_mmc_plat *plat = dev_get_platdata(dev);
250 
251 	return dwmci_bind(dev, &plat->mmc, &plat->cfg);
252 }
253 
254 static const struct udevice_id rockchip_dwmmc_ids[] = {
255 	{ .compatible = "rockchip,rk3288-dw-mshc" },
256 	{ .compatible = "rockchip,rk2928-dw-mshc" },
257 	{ }
258 };
259 
260 U_BOOT_DRIVER(rockchip_dwmmc_drv) = {
261 	.name		= "rockchip_rk3288_dw_mshc",
262 	.id		= UCLASS_MMC,
263 	.of_match	= rockchip_dwmmc_ids,
264 	.ofdata_to_platdata = rockchip_dwmmc_ofdata_to_platdata,
265 	.ops		= &dm_dwmci_ops,
266 	.bind		= rockchip_dwmmc_bind,
267 	.probe		= rockchip_dwmmc_probe,
268 	.priv_auto_alloc_size = sizeof(struct rockchip_dwmmc_priv),
269 	.platdata_auto_alloc_size = sizeof(struct rockchip_mmc_plat),
270 };
271 
272 #ifdef CONFIG_PWRSEQ
273 static int rockchip_dwmmc_pwrseq_set_power(struct udevice *dev, bool enable)
274 {
275 	struct gpio_desc reset;
276 	int ret;
277 
278 	ret = gpio_request_by_name(dev, "reset-gpios", 0, &reset, GPIOD_IS_OUT);
279 	if (ret)
280 		return ret;
281 	dm_gpio_set_value(&reset, 1);
282 	udelay(1);
283 	dm_gpio_set_value(&reset, 0);
284 	udelay(200);
285 
286 	return 0;
287 }
288 
289 static const struct pwrseq_ops rockchip_dwmmc_pwrseq_ops = {
290 	.set_power	= rockchip_dwmmc_pwrseq_set_power,
291 };
292 
293 static const struct udevice_id rockchip_dwmmc_pwrseq_ids[] = {
294 	{ .compatible = "mmc-pwrseq-emmc" },
295 	{ }
296 };
297 
298 U_BOOT_DRIVER(rockchip_dwmmc_pwrseq_drv) = {
299 	.name		= "mmc_pwrseq_emmc",
300 	.id		= UCLASS_PWRSEQ,
301 	.of_match	= rockchip_dwmmc_pwrseq_ids,
302 	.ops		= &rockchip_dwmmc_pwrseq_ops,
303 };
304 #endif
305