1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2016 Nexell
4  * Youngbok, Park <park@nexell.co.kr>
5  *
6  * (C) Copyright 2019 Stefan Bosch <stefan_b@posteo.net>
7  */
8 
9 #include <common.h>
10 #include <dm.h>
11 #include <dt-structs.h>
12 #include <dwmmc.h>
13 #include <log.h>
14 #include <syscon.h>
15 #include <asm/arch/reset.h>
16 #include <asm/arch/clk.h>
17 
18 #define DWMCI_CLKSEL			0x09C
19 #define DWMCI_SHIFT_0			0x0
20 #define DWMCI_SHIFT_1			0x1
21 #define DWMCI_SHIFT_2			0x2
22 #define DWMCI_SHIFT_3			0x3
23 #define DWMCI_SET_SAMPLE_CLK(x)	(x)
24 #define DWMCI_SET_DRV_CLK(x)	((x) << 16)
25 #define DWMCI_SET_DIV_RATIO(x)	((x) << 24)
26 #define DWMCI_CLKCTRL			0x114
27 #define NX_MMC_CLK_DELAY(x, y, a, b)	((((x) & 0xFF) << 0) |\
28 					(((y) & 0x03) << 16) |\
29 					(((a) & 0xFF) << 8)  |\
30 					(((b) & 0x03) << 24))
31 
32 struct nexell_mmc_plat {
33 	struct mmc_config cfg;
34 	struct mmc mmc;
35 };
36 
37 struct nexell_dwmmc_priv {
38 	struct clk *clk;
39 	struct dwmci_host host;
40 	int fifo_size;
41 	bool fifo_mode;
42 	int frequency;
43 	u32 min_freq;
44 	u32 max_freq;
45 	int d_delay;
46 	int d_shift;
47 	int s_delay;
48 	int s_shift;
49 	bool mmcboost;
50 };
51 
52 struct clk *clk_get(const char *id);
53 
nx_dw_mmc_clksel(struct dwmci_host * host)54 static int nx_dw_mmc_clksel(struct dwmci_host *host)
55 {
56 	/* host->priv is pointer to "struct udevice" */
57 	struct nexell_dwmmc_priv *priv = dev_get_priv(host->priv);
58 	u32 val;
59 
60 	if (priv->mmcboost)
61 		val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
62 		      DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(1);
63 	else
64 		val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
65 		      DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(3);
66 
67 	dwmci_writel(host, DWMCI_CLKSEL, val);
68 
69 	return 0;
70 }
71 
nx_dw_mmc_reset(int ch)72 static void nx_dw_mmc_reset(int ch)
73 {
74 	int rst_id = RESET_ID_SDMMC0 + ch;
75 
76 	nx_rstcon_setrst(rst_id, 0);
77 	nx_rstcon_setrst(rst_id, 1);
78 }
79 
nx_dw_mmc_clk_delay(struct udevice * dev)80 static void nx_dw_mmc_clk_delay(struct udevice *dev)
81 {
82 	unsigned int delay;
83 	struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
84 	struct dwmci_host *host = &priv->host;
85 
86 	delay = NX_MMC_CLK_DELAY(priv->d_delay,
87 				 priv->d_shift, priv->s_delay, priv->s_shift);
88 
89 	writel(delay, (host->ioaddr + DWMCI_CLKCTRL));
90 	debug("%s: Values set: d_delay==%d, d_shift==%d, s_delay==%d, "
91 	      "s_shift==%d\n", __func__, priv->d_delay, priv->d_shift,
92 	      priv->s_delay, priv->s_shift);
93 }
94 
nx_dw_mmc_get_clk(struct dwmci_host * host,uint freq)95 static unsigned int nx_dw_mmc_get_clk(struct dwmci_host *host, uint freq)
96 {
97 	struct clk *clk;
98 	struct udevice *dev = host->priv;
99 	struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
100 
101 	int index = host->dev_index;
102 	char name[50] = { 0, };
103 
104 	clk = priv->clk;
105 	if (!clk) {
106 		sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
107 		clk = clk_get((const char *)name);
108 		if (!clk)
109 			return 0;
110 		priv->clk = clk;
111 	}
112 
113 	return clk_get_rate(clk) / 2;
114 }
115 
nx_dw_mmc_set_clk(struct dwmci_host * host,unsigned int rate)116 static unsigned long nx_dw_mmc_set_clk(struct dwmci_host *host,
117 				       unsigned int rate)
118 {
119 	struct clk *clk;
120 	char name[50] = { 0, };
121 	struct udevice *dev = host->priv;
122 	struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
123 
124 	int index = host->dev_index;
125 
126 	clk = priv->clk;
127 	if (!clk) {
128 		sprintf(name, "%s.%d", DEV_NAME_SDHC, index);
129 		clk = clk_get((const char *)name);
130 		if (!clk) {
131 			debug("%s: clk_get(\"%s\") failed!\n", __func__, name);
132 			return 0;
133 		}
134 		priv->clk = clk;
135 	}
136 
137 	clk_disable(clk);
138 	rate = clk_set_rate(clk, rate);
139 	clk_enable(clk);
140 
141 	return rate;
142 }
143 
nexell_dwmmc_of_to_plat(struct udevice * dev)144 static int nexell_dwmmc_of_to_plat(struct udevice *dev)
145 {
146 	struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
147 	struct dwmci_host *host = &priv->host;
148 	int val = -1;
149 
150 	debug("%s\n", __func__);
151 
152 	host->name = dev->name;
153 	host->ioaddr = dev_read_addr_ptr(dev);
154 	host->buswidth = dev_read_u32_default(dev, "bus-width", 4);
155 	host->get_mmc_clk = nx_dw_mmc_get_clk;
156 	host->clksel = nx_dw_mmc_clksel;
157 	host->priv = dev;
158 
159 	val = dev_read_u32_default(dev, "index", -1);
160 	if (val < 0 || val > 2) {
161 		debug("  'index' missing/invalid!\n");
162 		return -EINVAL;
163 	}
164 	host->dev_index = val;
165 
166 	priv->fifo_size = dev_read_u32_default(dev, "fifo-size", 0x20);
167 	priv->fifo_mode = dev_read_bool(dev, "fifo-mode");
168 	priv->frequency = dev_read_u32_default(dev, "frequency", 50000000);
169 	priv->max_freq = dev_read_u32_default(dev, "max-frequency", 50000000);
170 	priv->min_freq = 400000;  /* 400 kHz */
171 	priv->d_delay = dev_read_u32_default(dev, "drive_dly", 0);
172 	priv->d_shift = dev_read_u32_default(dev, "drive_shift", 3);
173 	priv->s_delay = dev_read_u32_default(dev, "sample_dly", 0);
174 	priv->s_shift = dev_read_u32_default(dev, "sample_shift", 2);
175 	priv->mmcboost = dev_read_u32_default(dev, "mmcboost", 0);
176 
177 	debug("  index==%d, name==%s, ioaddr==0x%08x\n",
178 	      host->dev_index, host->name, (u32)host->ioaddr);
179 	return 0;
180 }
181 
nexell_dwmmc_probe(struct udevice * dev)182 static int nexell_dwmmc_probe(struct udevice *dev)
183 {
184 	struct nexell_mmc_plat *plat = dev_get_plat(dev);
185 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
186 	struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
187 	struct dwmci_host *host = &priv->host;
188 	struct udevice *pwr_dev __maybe_unused;
189 
190 	host->fifoth_val = MSIZE(0x2) |
191 		RX_WMARK(priv->fifo_size / 2 - 1) |
192 		TX_WMARK(priv->fifo_size / 2);
193 
194 	host->fifo_mode = priv->fifo_mode;
195 
196 	dwmci_setup_cfg(&plat->cfg, host, priv->max_freq, priv->min_freq);
197 	host->mmc = &plat->mmc;
198 	host->mmc->priv = &priv->host;
199 	host->mmc->dev = dev;
200 	upriv->mmc = host->mmc;
201 
202 	if (nx_dw_mmc_set_clk(host, priv->frequency * 4) !=
203 	    priv->frequency * 4) {
204 		debug("%s: nx_dw_mmc_set_clk(host, %d) failed!\n",
205 		      __func__, priv->frequency * 4);
206 		return -EIO;
207 	}
208 	debug("%s: nx_dw_mmc_set_clk(host, %d) OK\n",
209 	      __func__, priv->frequency * 4);
210 
211 	nx_dw_mmc_reset(host->dev_index);
212 	nx_dw_mmc_clk_delay(dev);
213 
214 	return dwmci_probe(dev);
215 }
216 
nexell_dwmmc_bind(struct udevice * dev)217 static int nexell_dwmmc_bind(struct udevice *dev)
218 {
219 	struct nexell_mmc_plat *plat = dev_get_plat(dev);
220 
221 	return dwmci_bind(dev, &plat->mmc, &plat->cfg);
222 }
223 
224 static const struct udevice_id nexell_dwmmc_ids[] = {
225 	{ .compatible = "nexell,nexell-dwmmc" },
226 	{ }
227 };
228 
229 U_BOOT_DRIVER(nexell_dwmmc_drv) = {
230 	.name		= "nexell_dwmmc",
231 	.id		= UCLASS_MMC,
232 	.of_match	= nexell_dwmmc_ids,
233 	.of_to_plat = nexell_dwmmc_of_to_plat,
234 	.ops		= &dm_dwmci_ops,
235 	.bind		= nexell_dwmmc_bind,
236 	.probe		= nexell_dwmmc_probe,
237 	.priv_auto	= sizeof(struct nexell_dwmmc_priv),
238 	.plat_auto	= sizeof(struct nexell_mmc_plat),
239 };
240