1 /* $OpenBSD: dwmshc.c,v 1.8 2024/07/15 09:56:30 patrick Exp $ */
2
3 /*
4 * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/param.h>
20 #include <sys/malloc.h>
21 #include <sys/systm.h>
22
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25 #include <machine/intr.h>
26
27 #include <dev/ofw/openfirm.h>
28 #include <dev/ofw/ofw_clock.h>
29 #include <dev/ofw/ofw_gpio.h>
30 #include <dev/ofw/ofw_misc.h>
31 #include <dev/ofw/ofw_pinctrl.h>
32 #include <dev/ofw/ofw_regulator.h>
33 #include <dev/ofw/fdt.h>
34
35 #include <dev/sdmmc/sdhcreg.h>
36 #include <dev/sdmmc/sdhcvar.h>
37 #include <dev/sdmmc/sdmmcvar.h>
38
39 #define EMMC_VER_ID 0x500
40 #define EMMC_VER_TYPE 0x504
41 #define EMMC_HOST_CTRL3 0x508 /* B */
42 #define EMMC_HOST_CTRL3_CMD_CONFLICT_CHECK (1U << 0)
43 #define EMMC_HOST_CTRL3_SW_CG_DIS (1U << 4)
44 #define EMMC_EMMC_CTRL 0x52c /* HW */
45 #define EMMC_EMMC_CTRL_CARD_IS_EMMC (1U << 0)
46 #define EMMC_EMMC_CTRL_DISABLE_DATA_CRC_CHK (1U << 1)
47 #define EMMC_EMMC_CTRL_EMMC_RST_N (1U << 2)
48 #define EMMC_EMMC_CTRL_EMMC_RST_N_OE (1U << 3)
49 #define EMMC_EMMC_CTRL_ENH_STROBE_ENABLE (1U << 8)
50 #define EMMC_EMMC_CTRL_CQE_ALGO_SEL (1U << 9)
51 #define EMMC_EMMC_CTRL_CQE_PREFETCH_DISABLE (1U << 10)
52 #define EMMC_BOOT_CTRL 0x52e /* HW */
53 #define EMMC_BOOT_CTRL_MAN_BOOT_EN (1U << 0)
54 #define EMMC_BOOT_CTRL_VALIDATE_BOOT (1U << 1)
55 #define EMMC_BOOT_CTRL_BOOT_ACK_ENABLE (1U << 8)
56 #define EMMC_BOOT_CTRL_BOOT_TOUT_CNT_SHIFT 12
57 #define EMMC_BOOT_CTRL_BOOT_TOUT_CNT_MASK 0xf
58 #define EMMC_AT_CTRL 0x540
59 #define EMMC_AT_CTRL_SWIN_TH_EN (1U << 2)
60 #define EMMC_AT_CTRL_RPT_TUNE_ERR (1U << 3)
61 #define EMMC_AT_CTRL_SW_TUNE_EN (1U << 4)
62 #define EMMC_AT_CTRL_TUNE_CLK_STOP_EN (1U << 16)
63 #define EMMC_AT_CTRL_PRE_CHANGE_DLY_MASK (0x3 << 17)
64 #define EMMC_AT_CTRL_PRE_CHANGE_DLY_LT1 (0x0 << 17)
65 #define EMMC_AT_CTRL_PRE_CHANGE_DLY_LT2 (0x1 << 17)
66 #define EMMC_AT_CTRL_PRE_CHANGE_DLY_LT3 (0x2 << 17)
67 #define EMMC_AT_CTRL_PRE_CHANGE_DLY_LT4 (0x3 << 17)
68 #define EMMC_AT_CTRL_POST_CHANGE_DLY_MASK (0x3 << 19)
69 #define EMMC_AT_CTRL_POST_CHANGE_DLY_LT1 (0x0 << 19)
70 #define EMMC_AT_CTRL_POST_CHANGE_DLY_LT2 (0x1 << 19)
71 #define EMMC_AT_CTRL_POST_CHANGE_DLY_LT3 (0x2 << 19)
72 #define EMMC_AT_CTRL_POST_CHANGE_DLY_LT4 (0x3 << 19)
73 #define EMMC_AT_STAT 0x544
74 #define EMMC_AT_STAT_CENTER_PH_CODE_SHIFT 0
75 #define EMMC_AT_STAT_CENTER_PH_CODE_MASK 0xff
76 #define EMMC_AT_STAT_R_EDGE_PH_CODE_SHIFT 8
77 #define EMMC_AT_STAT_R_EDGE_PH_CODE_MASK 0xff
78 #define EMMC_AT_STAT_L_EDGE_PH_CODE_SHIFT 16
79 #define EMMC_AT_STAT_L_EDGE_PH_CODE_MASK 0xff
80 #define EMMC_DLL_CTRL 0x800
81 #define EMMC_DLL_CTRL_DLL_START (1U << 0)
82 #define EMMC_DLL_CTRL_DLL_SRST (1U << 1)
83 #define EMMC_DLL_CTRL_DLL_INCREMENT_SHIFT 8
84 #define EMMC_DLL_CTRL_DLL_INCREMENT_MASK 0xff
85 #define EMMC_DLL_CTRL_DLL_START_POINT_SHIFT 16
86 #define EMMC_DLL_CTRL_DLL_START_POINT_MASK 0xff
87 #define EMMC_DLL_CTRL_DLL_BYPASS_MODE (1U << 24)
88 #define EMMC_DLL_RXCLK 0x804
89 #define EMMC_DLL_RXCLK_RX_TAP_NUM_SHIFT 0
90 #define EMMC_DLL_RXCLK_RX_TAP_NUM_MASK 0x1f
91 #define EMMC_DLL_RXCLK_RX_TAP_VALUE_SHIFT 8
92 #define EMMC_DLL_RXCLK_RX_TAP_VALUE_MASK 0xff
93 #define EMMC_DLL_RXCLK_RX_DELAY_NUM_SHIFT 16
94 #define EMMC_DLL_RXCLK_RX_DELAY_NUM_MASK 0xff
95 #define EMMC_DLL_RXCLK_RX_TAP_NUM_SEL (1U << 24)
96 #define EMMC_DLL_RXCLK_RX_TAP_VALUE_SEL (1U << 25)
97 #define EMMC_DLL_RXCLK_RX_DELAY_NUM_SEL (1U << 26)
98 #define EMMC_DLL_RXCLK_RX_CLK_OUT_SEL (1U << 27)
99 #define EMMC_DLL_RXCLK_RX_CLK_CHANGE_WINDOW (1U << 28)
100 #define EMMC_DLL_RXCLK_RX_CLK_SRC_SEL (1U << 29)
101 #define EMMC_DLL_TXCLK 0x808
102 #define EMMC_DLL_TXCLK_TX_TAP_NUM_SHIFT 0
103 #define EMMC_DLL_TXCLK_TX_TAP_NUM_MASK 0x1f
104 #define EMMC_DLL_TXCLK_TX_TAP_NUM_90_DEG 0x8
105 #define EMMC_DLL_TXCLK_TX_TAP_NUM_DEFAULT 0x10
106 #define EMMC_DLL_TXCLK_TX_TAP_VALUE_SHIFT 8
107 #define EMMC_DLL_TXCLK_TX_TAP_VALUE_MASK 0xff
108 #define EMMC_DLL_TXCLK_TX_DELAY_SHIFT 16
109 #define EMMC_DLL_TXCLK_TX_DELAY_MASK 0xff
110 #define EMMC_DLL_TXCLK_TX_TAP_NUM_SEL (1U << 24)
111 #define EMMC_DLL_TXCLK_TX_TAP_VALUE_SEL (1U << 25)
112 #define EMMC_DLL_TXCLK_TX_DELAY_SEL (1U << 26)
113 #define EMMC_DLL_TXCLK_TX_CLK_OUT_SEL (1U << 27)
114 #define EMMC_DLL_STRBIN 0x80c
115 #define EMMC_DLL_STRBIN_TAP_NUM_SHIFT 0
116 #define EMMC_DLL_STRBIN_TAP_NUM_MASK 0x1f
117 #define EMMC_DLL_STRBIN_TAP_NUM_90_DEG 0x8
118 #define EMMC_DLL_STRBIN_TAP_VALUE_SHIFT 8
119 #define EMMC_DLL_STRBIN_TAP_VALUE_MASK 0xff
120 #define EMMC_DLL_STRBIN_DELAY_NUM_SHIFT 16
121 #define EMMC_DLL_STRBIN_DELAY_NUM_MASK 0xff
122 #define EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT 0x16
123 #define EMMC_DLL_STRBIN_TAP_NUM_SEL (1U << 24)
124 #define EMMC_DLL_STRBIN_TAP_VALUE_SEL (1U << 25)
125 #define EMMC_DLL_STRBIN_DELAY_NUM_SEL (1U << 26)
126 #define EMMC_DLL_STRBIN_DELAY_ENA (1U << 27)
127 #define EMMC_DLL_CMDOUT 0x810
128 #define EMMC_DLL_CMDOUT_TAP_NUM_SHIFT 0
129 #define EMMC_DLL_CMDOUT_TAP_NUM_MASK 0x1f
130 #define EMMC_DLL_CMDOUT_TAP_NUM_90_DEG 0x8
131 #define EMMC_DLL_CMDOUT_TAP_VALUE_SHIFT 8
132 #define EMMC_DLL_CMDOUT_TAP_VALUE_MASK 0xff
133 #define EMMC_DLL_CMDOUT_DELAY_NUM_SHIFT 16
134 #define EMMC_DLL_CMDOUT_DELAY_NUM_MASK 0xff
135 #define EMMC_DLL_CMDOUT_TAP_NUM_SEL (1U << 24)
136 #define EMMC_DLL_CMDOUT_TAP_VALUE_SEL (1U << 25)
137 #define EMMC_DLL_CMDOUT_DELAY_NUM_SEL (1U << 26)
138 #define EMMC_DLL_CMDOUT_DELAY_ENA (1U << 27)
139 #define EMMC_DLL_CMDOUT_SRC_SEL (1U << 28)
140 #define EMMC_DLL_CMDOUT_EN_SRC_SEL (1U << 29)
141 #define EMMC_DLL_STATUS0 0x840
142 #define EMMC_DLL_STATUS0_DLL_LOCK_VALUE_SHIFT 0
143 #define EMMC_DLL_STATUS0_DLL_LOCK_VALUE_MASK 0xff
144 #define EMMC_DLL_STATUS0_DLL_LOCK (1U << 8)
145 #define EMMC_DLL_STATUS0_DLL_LOCK_TIMEOUT (1U << 9)
146 #define EMMC_DLL_STATUS1 0x844
147 #define EMMC_DLL_STATUS1_DLL_TXCLK_DELAY_VALUE_SHIFT \
148 0
149 #define EMMC_DLL_STATUS1_DLL_TXCLK_DELAY_VALUE_MASK \
150 0xff
151 #define EMMC_DLL_STATUS1_DLL_RXCLK_DELAY_VALUE_SHIFT \
152 8
153 #define EMMC_DLL_STATUS1_DLL_RXCLK_DELAY_VALUE_MASK \
154 0xff
155 #define EMMC_DLL_STATUS1_DLL_STRBIN_DELAY_VALUE_SHIFT \
156 16
157 #define EMMC_DLL_STATUS1_DLL_STRBIN_DELAY_VALUE_MASK \
158 0xff
159
160 struct dwmshc_softc {
161 struct sdhc_softc sc_sdhc;
162
163 int sc_node;
164
165 bus_space_tag_t sc_iot;
166 bus_space_handle_t sc_ioh;
167 bus_size_t sc_ios;
168 bus_dma_tag_t sc_dmat;
169 void *sc_ih;
170
171 struct sdhc_host *sc_host;
172 };
173
174 static int dwmshc_match(struct device *, void *, void *);
175 static void dwmshc_attach(struct device *, struct device *,
176 void *);
177
178 static inline void dwmshc_wr1(struct dwmshc_softc *,
179 bus_size_t, uint8_t);
180 static inline void dwmshc_wr4(struct dwmshc_softc *,
181 bus_size_t, uint32_t);
182 static inline uint32_t dwmshc_rd4(struct dwmshc_softc *, bus_size_t);
183
184 static void dwmshc_clock_pre(struct sdhc_softc *, int, int);
185 static void dwmshc_clock_post(struct sdhc_softc *, int, int);
186 static int dwmshc_non_removable(struct sdhc_softc *);
187
188 const struct cfattach dwmshc_ca = {
189 sizeof(struct dwmshc_softc), dwmshc_match, dwmshc_attach
190 };
191
192 struct cfdriver dwmshc_cd = {
193 NULL, "dwmshc", DV_DULL
194 };
195
196 int
dwmshc_match(struct device * parent,void * match,void * aux)197 dwmshc_match(struct device *parent, void *match, void *aux)
198 {
199 struct fdt_attach_args *faa = aux;
200
201 return (OF_is_compatible(faa->fa_node, "rockchip,rk3568-dwcmshc") ||
202 OF_is_compatible(faa->fa_node, "rockchip,rk3588-dwcmshc"));
203 }
204 static void
dwmshc_attach(struct device * parent,struct device * self,void * aux)205 dwmshc_attach(struct device *parent, struct device *self, void *aux)
206 {
207 struct dwmshc_softc *sc = (struct dwmshc_softc *)self;
208 struct sdhc_softc *sdhc = &sc->sc_sdhc;
209 struct fdt_attach_args *faa = aux;
210 uint64_t capmask = 0;
211 uint16_t capset = 0;
212 int bus_width;
213 uint32_t freq;
214
215 sc->sc_node = faa->fa_node;
216 sc->sc_iot = faa->fa_iot;
217 sc->sc_ios = faa->fa_reg[0].size;
218 sc->sc_dmat = faa->fa_dmat;
219
220 if (faa->fa_nreg < 1) {
221 printf(": no registers\n");
222 return;
223 }
224
225 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
226 faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
227 printf(": can't map registers\n");
228 return;
229 }
230
231 pinctrl_byname(sc->sc_node, "default");
232
233 clock_set_assigned(sc->sc_node);
234 clock_enable_all(sc->sc_node);
235 reset_deassert_all(sc->sc_node);
236
237 sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO,
238 sdhc_intr, sdhc, DEVNAME(sdhc));
239 if (sc->sc_ih == NULL) {
240 printf(": can't establish interrupt\n");
241 return;
242 }
243
244 printf("\n");
245
246 /* Disable Command Conflict Check */
247 dwmshc_wr1(sc, EMMC_HOST_CTRL3, 0);
248
249 sdhc->sc_host = &sc->sc_host;
250 sdhc->sc_dmat = faa->fa_dmat;
251 sdhc->sc_dma_boundary = 128 * 1024 * 1024;
252
253 sdhc->sc_bus_clock_pre = dwmshc_clock_pre;
254 sdhc->sc_bus_clock_post = dwmshc_clock_post;
255
256 if (OF_getpropbool(sc->sc_node, "non-removable")) {
257 SET(sdhc->sc_flags, SDHC_F_NONREMOVABLE);
258 sdhc->sc_card_detect = dwmshc_non_removable;
259 }
260
261 bus_width = OF_getpropint(faa->fa_node, "bus-width", 1);
262 if (bus_width < 8)
263 SET(capmask, SDHC_8BIT_MODE_SUPP);
264
265 freq = clock_get_frequency(faa->fa_node, "block");
266 sdhc->sc_clkbase = freq / 1000;
267
268 SET(sdhc->sc_flags, SDHC_F_NOPWR0);
269 SET(capmask, (uint64_t)SDHC_DDR50_SUPP << 32);
270
271 sdhc_host_found(sdhc, sc->sc_iot, sc->sc_ioh, sc->sc_ios, 1,
272 capmask, capset);
273 }
274
275 static void
dwmshc_clock_pre(struct sdhc_softc * sdhc,int freq,int timing)276 dwmshc_clock_pre(struct sdhc_softc *sdhc, int freq, int timing)
277 {
278 #if 0
279 struct dwmshc_softc *sc = (struct dwmshc_softc *)sdhc;
280
281 /*
282 * before switching to hs400es the driver needs to enable
283 * enhanced strobe. i think this is the right place to do
284 * that.
285 */
286 if (timing == hs400es) {
287 dwmshc_wr4(sc, EMMC_DLL_STRBIN, EMMC_DLL_STRBIN_DELAY_ENA |
288 EMMC_DLL_STRBIN_DELAY_NUM_SEL |
289 (EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT <<
290 EMMC_DLL_STRBIN_DELAY_NUM_SHIFT));
291 }
292 #endif
293 }
294
295 static int
dwmshc_dll_wait(struct dwmshc_softc * sc)296 dwmshc_dll_wait(struct dwmshc_softc *sc)
297 {
298 uint32_t status0;
299 int i;
300
301 for (i = 0; i < 500 * 1000; i++) {
302 delay(1);
303
304 status0 = dwmshc_rd4(sc, EMMC_DLL_STATUS0);
305 if (ISSET(status0, EMMC_DLL_STATUS0_DLL_LOCK)) {
306 if (ISSET(status0, EMMC_DLL_STATUS0_DLL_LOCK_TIMEOUT)) {
307 printf("%s: lock timeout\n",
308 DEVNAME(&sc->sc_sdhc));
309 return (EIO);
310 }
311 return (0);
312 }
313 }
314
315 printf("%s: poll timeout\n", DEVNAME(&sc->sc_sdhc));
316 return (ETIMEDOUT);
317 }
318
319 static void
dwmshc_clock_post(struct sdhc_softc * sdhc,int freq,int timing)320 dwmshc_clock_post(struct sdhc_softc *sdhc, int freq, int timing)
321 {
322 struct dwmshc_softc *sc = (struct dwmshc_softc *)sdhc;
323 uint32_t txclk_tapnum = EMMC_DLL_TXCLK_TX_TAP_NUM_DEFAULT;
324
325 clock_set_frequency(sc->sc_node, 0, freq * 1000);
326
327 if (timing == SDMMC_TIMING_LEGACY) { /* disable dll */
328 /*
329 * the bypass and start bits need to be set if dll
330 * is not locked.
331 */
332 dwmshc_wr4(sc, EMMC_DLL_CTRL,
333 EMMC_DLL_CTRL_DLL_START | EMMC_DLL_CTRL_DLL_BYPASS_MODE);
334 dwmshc_wr4(sc, EMMC_DLL_RXCLK, 0);
335 dwmshc_wr4(sc, EMMC_DLL_TXCLK, 0);
336 dwmshc_wr4(sc, EMMC_DLL_STRBIN, 0);
337 return;
338 }
339
340 dwmshc_wr4(sc, EMMC_DLL_CTRL, EMMC_DLL_CTRL_DLL_SRST);
341 delay(1);
342 dwmshc_wr4(sc, EMMC_DLL_CTRL, 0);
343
344 if (OF_is_compatible(sc->sc_node, "rockchip,rk3568-dwcmshc"))
345 dwmshc_wr4(sc, EMMC_DLL_RXCLK, EMMC_DLL_RXCLK_RX_CLK_OUT_SEL |
346 EMMC_DLL_RXCLK_RX_CLK_SRC_SEL);
347 else
348 dwmshc_wr4(sc, EMMC_DLL_RXCLK, EMMC_DLL_RXCLK_RX_CLK_OUT_SEL);
349 dwmshc_wr4(sc, EMMC_DLL_CTRL, EMMC_DLL_CTRL_DLL_START |
350 0x5 << EMMC_DLL_CTRL_DLL_START_POINT_SHIFT |
351 0x2 << EMMC_DLL_CTRL_DLL_INCREMENT_SHIFT);
352
353 if (dwmshc_dll_wait(sc) != 0)
354 return;
355
356 dwmshc_wr4(sc, EMMC_AT_CTRL, EMMC_AT_CTRL_TUNE_CLK_STOP_EN |
357 EMMC_AT_CTRL_PRE_CHANGE_DLY_LT4 |
358 EMMC_AT_CTRL_POST_CHANGE_DLY_LT4);
359
360 if (timing >= SDMMC_TIMING_MMC_HS200) {
361 txclk_tapnum = OF_getpropint(sc->sc_node,
362 "rockchip,txclk-tapnum", txclk_tapnum);
363
364 #ifdef notyet
365 if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-dwcmshc") &&
366 timing == SDMMC_TIMING_MMC_HS400) {
367 txclk_tapnum = EMMC_DLL_TXCLK_TX_TAP_NUM_90_DEG;
368 dwmshc_wr4(sc, EMMC_DLL_CMDOUT,
369 EMMC_DLL_CMDOUT_TAP_NUM_90_DEG |
370 EMMC_DLL_CMDOUT_TAP_NUM_SEL |
371 EMMC_DLL_CMDOUT_DELAY_ENA |
372 EMMC_DLL_CMDOUT_SRC_SEL |
373 EMMC_DLL_CMDOUT_EN_SRC_SEL);
374 }
375 #endif
376 }
377
378 dwmshc_wr4(sc, EMMC_DLL_TXCLK, EMMC_DLL_TXCLK_TX_CLK_OUT_SEL |
379 EMMC_DLL_TXCLK_TX_TAP_NUM_SEL |
380 txclk_tapnum << EMMC_DLL_TXCLK_TX_TAP_NUM_SHIFT);
381 dwmshc_wr4(sc, EMMC_DLL_STRBIN, EMMC_DLL_STRBIN_DELAY_ENA |
382 EMMC_DLL_STRBIN_TAP_NUM_SEL |
383 (EMMC_DLL_STRBIN_TAP_NUM_90_DEG <<
384 EMMC_DLL_STRBIN_TAP_NUM_SHIFT));
385 }
386
387 static int
dwmshc_non_removable(struct sdhc_softc * sdhc)388 dwmshc_non_removable(struct sdhc_softc *sdhc)
389 {
390 return (1);
391 }
392
393 static inline void
dwmshc_wr1(struct dwmshc_softc * sc,bus_size_t off,uint8_t v)394 dwmshc_wr1(struct dwmshc_softc *sc, bus_size_t off, uint8_t v)
395 {
396 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, v);
397 }
398
399 static inline void
dwmshc_wr4(struct dwmshc_softc * sc,bus_size_t off,uint32_t v)400 dwmshc_wr4(struct dwmshc_softc *sc, bus_size_t off, uint32_t v)
401 {
402 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, v);
403 }
404
405 static inline uint32_t
dwmshc_rd4(struct dwmshc_softc * sc,bus_size_t off)406 dwmshc_rd4(struct dwmshc_softc *sc, bus_size_t off)
407 {
408 return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off));
409 }
410