xref: /openbsd-src/sys/dev/fdt/dwmshc.c (revision fff34f16322b467899e7fabd64ebf98c6767fd6c)
1 /*	$OpenBSD: dwmshc.c,v 1.2 2023/04/19 01:38:32 dlg 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			0x804
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_VALUE_SHIFT	8
105 #define  EMMC_DLL_TXCLK_TX_TAP_VALUE_MASK	0xff
106 #define  EMMC_DLL_TXCLK_TX_DELAY_SHIFT		16
107 #define  EMMC_DLL_TXCLK_TX_DELAY_MASK		0xff
108 #define  EMMC_DLL_TXCLK_TX_TAP_NUM_SEL		(1U << 24)
109 #define  EMMC_DLL_TXCLK_TX_TAP_VALUE_SEL	(1U << 25)
110 #define  EMMC_DLL_TXCLK_TX_DELAY_SEL		(1U << 26)
111 #define  EMMC_DLL_TXCLK_TX_CLK_OUT_SEL		(1U << 27)
112 #define EMMC_DLL_STRBIN			0x80c
113 #define  EMMC_DLL_STRBIN_TAP_NUM_SHIFT		0
114 #define  EMMC_DLL_STRBIN_TAP_NUM_MASK		0x1f
115 #define  EMMC_DLL_STRBIN_TAP_NUM_DEFAULT	0x8
116 #define  EMMC_DLL_STRBIN_TAP_VALUE_SHIFT	8
117 #define  EMMC_DLL_STRBIN_TAP_VALUE_MASK		0xff
118 #define  EMMC_DLL_STRBIN_DELAY_NUM_SHIFT	16
119 #define  EMMC_DLL_STRBIN_DELAY_NUM_MASK		0xff
120 #define  EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT	0x16
121 #define  EMMC_DLL_STRBIN_TAP_NUM_SEL		(1U << 24)
122 #define  EMMC_DLL_STRBIN_TAP_VALUE_SEL		(1U << 25)
123 #define  EMMC_DLL_STRBIN_DELAY_NUM_SEL		(1U << 26)
124 #define  EMMC_DLL_STRBIN_DELAY_ENA		(1U << 27)
125 #define EMMC_DLL_STATUS0		0x840
126 #define  EMMC_DLL_STATUS0_DLL_LOCK_VALUE_SHIFT	0
127 #define  EMMC_DLL_STATUS0_DLL_LOCK_VALUE_MASK	0xff
128 #define  EMMC_DLL_STATUS0_DLL_LOCK		(1U << 8)
129 #define  EMMC_DLL_STATUS0_DLL_LOCK_TIMEOUT	(1U << 9)
130 #define EMMC_DLL_STATUS1		0x844
131 #define  EMMC_DLL_STATUS1_DLL_TXCLK_DELAY_VALUE_SHIFT \
132 						0
133 #define  EMMC_DLL_STATUS1_DLL_TXCLK_DELAY_VALUE_MASK \
134 						0xff
135 #define  EMMC_DLL_STATUS1_DLL_RXCLK_DELAY_VALUE_SHIFT \
136 						8
137 #define  EMMC_DLL_STATUS1_DLL_RXCLK_DELAY_VALUE_MASK \
138 						0xff
139 #define  EMMC_DLL_STATUS1_DLL_STRBIN_DELAY_VALUE_SHIFT \
140 						16
141 #define  EMMC_DLL_STATUS1_DLL_STRBIN_DELAY_VALUE_MASK \
142 						0xff
143 
144 struct dwmshc_softc {
145 	struct sdhc_softc	 sc_sdhc;
146 
147 	int			 sc_node;
148 
149 	bus_space_tag_t		 sc_iot;
150 	bus_space_handle_t	 sc_ioh;
151 	bus_size_t		 sc_ios;
152 	bus_dma_tag_t		 sc_dmat;
153 	void			*sc_ih;
154 
155 	struct sdhc_host	*sc_host;
156 };
157 
158 static int		 dwmshc_match(struct device *, void *, void *);
159 static void		 dwmshc_attach(struct device *, struct device *,
160 			     void *);
161 
162 static inline void	 dwmshc_wr1(struct dwmshc_softc *,
163 			     bus_size_t, uint8_t);
164 #if 0
165 static inline void	 dwmshc_wr2(struct dwmshc_softc *,
166 			     bus_size_t, uint16_t);
167 static inline uint16_t	 dwmshc_rd2(struct dwmshc_softc *, bus_size_t);
168 #endif
169 static inline void	 dwmshc_wr4(struct dwmshc_softc *,
170 			     bus_size_t, uint32_t);
171 static inline uint32_t	 dwmshc_rd4(struct dwmshc_softc *, bus_size_t);
172 
173 static void		 dwmshc_clock_pre(struct sdhc_softc *, int, int);
174 static void		 dwmshc_clock_post(struct sdhc_softc *, int, int);
175 static int		 dwmshc_non_removable(struct sdhc_softc *);
176 
177 const struct cfattach dwmshc_ca = {
178 	sizeof(struct dwmshc_softc), dwmshc_match, dwmshc_attach
179 };
180 
181 struct cfdriver dwmshc_cd = {
182 	NULL, "dwmshc", DV_DULL
183 };
184 
185 int
186 dwmshc_match(struct device *parent, void *match, void *aux)
187 {
188 	struct fdt_attach_args *faa = aux;
189 
190 	return (OF_is_compatible(faa->fa_node, "rockchip,rk3568-dwcmshc"));
191 }
192 static void
193 dwmshc_attach(struct device *parent, struct device *self, void *aux)
194 {
195 	struct dwmshc_softc *sc = (struct dwmshc_softc *)self;
196 	struct sdhc_softc *sdhc = &sc->sc_sdhc;
197 	struct fdt_attach_args *faa = aux;
198 	uint64_t capmask = 0;
199 	uint16_t capset = 0;
200 	int bus_width;
201 	uint32_t freq;
202 
203 	sc->sc_node = faa->fa_node;
204 	sc->sc_iot = faa->fa_iot;
205 	sc->sc_ios = faa->fa_reg[0].size;
206 	sc->sc_dmat = faa->fa_dmat;
207 
208 	if (faa->fa_nreg < 1) {
209 		printf(": no registers\n");
210 		return;
211 	}
212 
213 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
214 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
215 		printf(": can't map registers\n");
216 		return;
217 	}
218 
219 	pinctrl_byname(sc->sc_node, "default");
220 
221 	clock_set_assigned(sc->sc_node);
222 	clock_enable_all(sc->sc_node);
223 	reset_deassert_all(sc->sc_node);
224 
225 	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO,
226 	    sdhc_intr, sdhc, DEVNAME(sdhc));
227 	if (sc->sc_ih == NULL) {
228 		printf(": can't establish interrupt\n");
229 		return;
230 	}
231 
232 	printf("\n");
233 
234 	/* Disable Command Conflict Check */
235 	dwmshc_wr1(sc, EMMC_HOST_CTRL3, 0);
236 
237 	sdhc->sc_host = &sc->sc_host;
238 	sdhc->sc_dmat = faa->fa_dmat;
239 
240 	sdhc->sc_bus_clock_pre = dwmshc_clock_pre;
241 	sdhc->sc_bus_clock_post = dwmshc_clock_post;
242 
243 	if (OF_getpropbool(sc->sc_node, "non-removable")) {
244 		SET(sdhc->sc_flags, SDHC_F_NONREMOVABLE);
245 		sdhc->sc_card_detect = dwmshc_non_removable;
246 	}
247 
248 	bus_width = OF_getpropint(faa->fa_node, "bus-width", 1);
249 	if (bus_width < 8)
250 		SET(capmask, SDHC_8BIT_MODE_SUPP);
251 #if 0
252 	if (bus_width < 4)
253 		...
254 #endif
255 
256 	freq = clock_get_frequency(faa->fa_node, "block");
257 	sdhc->sc_clkbase = freq / 1000;
258 
259 	SET(sdhc->sc_flags, SDHC_F_NOPWR0);
260 	SET(capmask, (uint64_t)SDHC_DDR50_SUPP << 32);
261 
262 	sdhc_host_found(sdhc, sc->sc_iot, sc->sc_ioh, sc->sc_ios, 1,
263 	    capmask, capset);
264 }
265 
266 static void
267 dwmshc_clock_pre(struct sdhc_softc *sdhc, int freq, int timing)
268 {
269 #if 0
270 	struct dwmshc_softc *sc = (struct dwmshc_softc *)sdhc;
271 
272 	/*
273 	 * before switching to hs400es the driver needs to enable
274 	 * enhanced strobe. i think this is the right place to do
275 	 * that.
276 	 */
277 	if (timing == hs400es) {
278 		dwmshc_wr4(sc, EMMC_DLL_STRBIN, EMMC_DLL_STRBIN_DELAY_ENA |
279 		    EMMC_DLL_STRBIN_DELAY_NUM_SEL |
280 		    (EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT <<
281 		     EMMC_DLL_STRBIN_DELAY_NUM_SHIFT));
282 	}
283 #endif
284 }
285 
286 static int
287 dwmshc_dll_wait(struct dwmshc_softc *sc)
288 {
289 	uint32_t status0;
290 	int i;
291 
292 	for (i = 0; i < 500 * 1000; i++) {
293 		delay(1);
294 
295 		status0 = dwmshc_rd4(sc, EMMC_DLL_STATUS0);
296 		if (ISSET(status0, EMMC_DLL_STATUS0_DLL_LOCK)) {
297 			if (ISSET(status0, EMMC_DLL_STATUS0_DLL_LOCK_TIMEOUT)) {
298 				printf("%s: lock timeout\n",
299 				    DEVNAME(&sc->sc_sdhc));
300 				return (EIO);
301 			}
302 			return (0);
303 		}
304 	}
305 
306 	printf("%s: poll timeout\n", DEVNAME(&sc->sc_sdhc));
307 	return (ETIMEDOUT);
308 }
309 
310 static void
311 dwmshc_clock_post(struct sdhc_softc *sdhc, int freq, int timing)
312 {
313 	struct dwmshc_softc *sc = (struct dwmshc_softc *)sdhc;
314 	uint32_t txclk_tapnum = EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT;
315 
316 	clock_set_frequency(sc->sc_node, 0, freq * 1000);
317 
318 	if (timing == SDMMC_TIMING_LEGACY) { /* disable dll */
319 		/*
320                  * the bypass and start bits need to be set if dll
321 		 * is not locked.
322 		 */
323 		dwmshc_wr4(sc, EMMC_DLL_CTRL,
324 		    EMMC_DLL_CTRL_DLL_START | EMMC_DLL_CTRL_DLL_BYPASS_MODE);
325 		dwmshc_wr4(sc, EMMC_DLL_RXCLK, 0);
326 		dwmshc_wr4(sc, EMMC_DLL_TXCLK, 0);
327 		dwmshc_wr4(sc, EMMC_DLL_STRBIN, 0);
328 		return;
329 	}
330 
331 	dwmshc_wr4(sc, EMMC_DLL_CTRL, EMMC_DLL_CTRL_DLL_SRST);
332 	delay(1);
333 	dwmshc_wr4(sc, EMMC_DLL_CTRL, 0);
334 
335 	dwmshc_wr4(sc, EMMC_DLL_RXCLK, EMMC_DLL_RXCLK_RX_CLK_OUT_SEL |
336 	    /* rk3568 */ EMMC_DLL_RXCLK_RX_CLK_SRC_SEL);
337 	dwmshc_wr4(sc, EMMC_DLL_CTRL, EMMC_DLL_CTRL_DLL_START |
338 	    0x5 << EMMC_DLL_CTRL_DLL_START_POINT_SHIFT |
339 	    0x2 << EMMC_DLL_CTRL_DLL_INCREMENT_SHIFT);
340 
341 	if (dwmshc_dll_wait(sc) != 0)
342 		return;
343 
344 	dwmshc_wr4(sc, EMMC_AT_CTRL, EMMC_AT_CTRL_TUNE_CLK_STOP_EN |
345 	    EMMC_AT_CTRL_PRE_CHANGE_DLY_LT4 |
346 	    EMMC_AT_CTRL_POST_CHANGE_DLY_LT4);
347 
348 	if (timing >= SDMMC_TIMING_MMC_HS200) {
349 		txclk_tapnum = OF_getpropint(sc->sc_node,
350 		    "rockchip,txclk-tapnum", txclk_tapnum);
351 
352 		/* XXX rk3588 hs400 */
353 	}
354 
355 	dwmshc_wr4(sc, EMMC_DLL_TXCLK, EMMC_DLL_TXCLK_TX_CLK_OUT_SEL |
356 	    EMMC_DLL_TXCLK_TX_TAP_NUM_SEL |
357 	    txclk_tapnum << EMMC_DLL_TXCLK_TX_TAP_NUM_SHIFT);
358 	dwmshc_wr4(sc, EMMC_DLL_STRBIN, EMMC_DLL_STRBIN_DELAY_ENA |
359 	    EMMC_DLL_STRBIN_TAP_NUM_SEL |
360 	    (EMMC_DLL_STRBIN_TAP_NUM_DEFAULT <<
361 	     EMMC_DLL_STRBIN_TAP_NUM_SHIFT));
362 }
363 
364 static int
365 dwmshc_non_removable(struct sdhc_softc *sdhc)
366 {
367 	return (1);
368 }
369 
370 static inline void
371 dwmshc_wr1(struct dwmshc_softc *sc, bus_size_t off, uint8_t v)
372 {
373 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, v);
374 }
375 
376 #if 0
377 static inline void
378 dwmshc_wr2(struct dwmshc_softc *sc, bus_size_t off, uint16_t v)
379 {
380 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, off, v);
381 }
382 
383 static inline uint16_t
384 dwmshc_rd2(struct dwmshc_softc *sc, bus_size_t off)
385 {
386 	return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, off));
387 }
388 #endif
389 
390 static inline void
391 dwmshc_wr4(struct dwmshc_softc *sc, bus_size_t off, uint32_t v)
392 {
393 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, v);
394 }
395 
396 static inline uint32_t
397 dwmshc_rd4(struct dwmshc_softc *sc, bus_size_t off)
398 {
399 	return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off));
400 }
401