xref: /openbsd-src/sys/dev/fdt/sdhc_fdt.c (revision f1dd7b858388b4a23f4f67a4957ec5ff656ebbe8)
1 /*	$OpenBSD: sdhc_fdt.c,v 1.16 2021/05/03 13:11:40 visa Exp $	*/
2 /*
3  * Copyright (c) 2017 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/malloc.h>
20 #include <sys/systm.h>
21 
22 #include <machine/bus.h>
23 #include <machine/fdt.h>
24 #include <machine/intr.h>
25 
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_clock.h>
28 #include <dev/ofw/ofw_gpio.h>
29 #include <dev/ofw/ofw_misc.h>
30 #include <dev/ofw/ofw_pinctrl.h>
31 #include <dev/ofw/ofw_regulator.h>
32 #include <dev/ofw/fdt.h>
33 
34 #include <dev/sdmmc/sdhcreg.h>
35 #include <dev/sdmmc/sdhcvar.h>
36 #include <dev/sdmmc/sdmmcvar.h>
37 
38 /* RK3399 */
39 #define GRF_EMMCCORE_CON0_BASECLOCK		0xf000
40 #define  GRF_EMMCCORE_CON0_BASECLOCK_CLR		(0xff << 24)
41 #define  GRF_EMMCCORE_CON0_BASECLOCK_VAL(x)		(((x) & 0xff) << 8)
42 #define GRF_EMMCCORE_CON11			0xf02c
43 #define  GRF_EMMCCORE_CON11_CLOCKMULT_CLR		(0xff << 16)
44 #define  GRF_EMMCCORE_CON11_CLOCKMULT_VAL(x)		(((x) & 0xff) << 0)
45 
46 /* Marvell Xenon */
47 #define XENON_SYS_OP_CTRL			0x108
48 #define  XENON_SYS_OP_CTRL_SLOT_ENABLE(x)		(1 << (x))
49 #define  XENON_SYS_OP_CTRL_SDCLK_IDLEOFF_ENABLE(x)	(1 << ((x) + 8))
50 #define  XENON_SYS_OP_CTRL_AUTO_CLKGATE_DISABLE		(1 << 20)
51 #define XENON_SYS_EXT_OP_CTRL			0x10c
52 #define  XENON_SYS_EXT_OP_CTRL_PARALLEL_TRAN(x)		(1 << (x))
53 #define  XENON_SYS_EXT_OP_CTRL_MASK_CMD_CONFLICT_ERR	(1 << 8)
54 #define XENON_SLOT_EMMC_CTRL			0x130
55 #define  XENON_SLOT_EMMC_CTRL_ENABLE_DATA_STROBE	(1 << 24)
56 #define  XENON_SLOT_EMMC_CTRL_ENABLE_RESP_STROBE	(1 << 25)
57 #define XENON_EMMC_PHY_TIMING_ADJUST		0x170
58 #define  XENON_EMMC_PHY_TIMING_ADJUST_SAMPL_INV_QSP_PHASE_SELECT (1 << 18)
59 #define  XENON_EMMC_PHY_TIMING_ADJUST_SDIO_MODE		(1 << 28)
60 #define  XENON_EMMC_PHY_TIMING_ADJUST_SLOW_MODE		(1 << 29)
61 #define  XENON_EMMC_PHY_TIMING_ADJUST_INIT		(1U << 31)
62 #define XENON_EMMC_PHY_FUNC_CONTROL		0x174
63 #define  XENON_EMMC_PHY_FUNC_CONTROL_DQ_ASYNC_MODE	(1 << 4)
64 #define  XENON_EMMC_PHY_FUNC_CONTROL_DQ_DDR_MODE	(0xff << 8)
65 #define  XENON_EMMC_PHY_FUNC_CONTROL_CMD_DDR_MODE	(1 << 16)
66 #define XENON_EMMC_PHY_PAD_CONTROL		0x178
67 #define  XENON_EMMC_PHY_PAD_CONTROL_FC_DQ_RECEN		(1 << 24)
68 #define  XENON_EMMC_PHY_PAD_CONTROL_FC_CMD_RECEN	(1 << 25)
69 #define  XENON_EMMC_PHY_PAD_CONTROL_FC_QSP_RECEN	(1 << 26)
70 #define  XENON_EMMC_PHY_PAD_CONTROL_FC_QSN_RECEN	(1 << 27)
71 #define  XENON_EMMC_PHY_PAD_CONTROL_FC_ALL_CMOS_RECVR	0xf000
72 #define XENON_EMMC_PHY_PAD_CONTROL1		0x17c
73 #define  XENON_EMMC_PHY_PAD_CONTROL1_FC_CMD_PD		(1 << 8)
74 #define  XENON_EMMC_PHY_PAD_CONTROL1_FC_QSP_PD		(1 << 9)
75 #define  XENON_EMMC_PHY_PAD_CONTROL1_FC_CMD_PU		(1 << 24)
76 #define  XENON_EMMC_PHY_PAD_CONTROL1_FC_QSP_PU		(1 << 25)
77 #define  XENON_EMMC_PHY_PAD_CONTROL1_FC_DQ_PD		0xff
78 #define  XENON_EMMC_PHY_PAD_CONTROL1_FC_DQ_PU		(0xff << 16)
79 #define XENON_EMMC_PHY_PAD_CONTROL2		0x180
80 #define  XENON_EMMC_PHY_PAD_CONTROL2_ZPR_SHIFT		0
81 #define  XENON_EMMC_PHY_PAD_CONTROL2_ZPR_MASK		0x1f
82 #define  XENON_EMMC_PHY_PAD_CONTROL2_ZNR_SHIFT		8
83 #define  XENON_EMMC_PHY_PAD_CONTROL2_ZNR_MASK		0x1f
84 
85 #define ARMADA_3700_SOC_PAD_CTL			0
86 #define  ARMADA_3700_SOC_PAD_CTL_3_3V			0
87 #define  ARMADA_3700_SOC_PAD_CTL_1_8V			1
88 
89 struct sdhc_fdt_softc {
90 	struct sdhc_softc 	sc;
91 	bus_space_tag_t		sc_iot;
92 	bus_space_handle_t	sc_ioh;
93 	bus_space_handle_t	sc_pad_ioh;
94 	bus_size_t		sc_size;
95 	void			*sc_ih;
96 	int			sc_node;
97 	uint32_t		sc_gpio[3];
98 	uint32_t		sc_vqmmc;
99 
100 	/* Marvell Xenon */
101 	int			sc_sdhc_id;
102 	int			sc_slow_mode;
103 	uint32_t		sc_znr;
104 	uint32_t		sc_zpr;
105 
106 	struct sdhc_host 	*sc_host;
107 	struct clock_device	sc_cd;
108 };
109 
110 int	sdhc_fdt_match(struct device *, void *, void *);
111 void	sdhc_fdt_attach(struct device *, struct device *, void *);
112 
113 struct cfattach sdhc_fdt_ca = {
114 	sizeof(struct sdhc_fdt_softc), sdhc_fdt_match, sdhc_fdt_attach
115 };
116 
117 int	sdhc_fdt_card_detect(struct sdhc_softc *);
118 int	sdhc_fdt_signal_voltage(struct sdhc_softc *, int);
119 uint32_t sdhc_fdt_get_frequency(void *, uint32_t *);
120 
121 void	sdhc_fdt_xenon_bus_clock_post(struct sdhc_softc *, int, int);
122 
123 int
124 sdhc_fdt_match(struct device *parent, void *match, void *aux)
125 {
126 	struct fdt_attach_args *faa = aux;
127 
128 	return (OF_is_compatible(faa->fa_node, "arasan,sdhci-5.1") ||
129 	    OF_is_compatible(faa->fa_node, "arasan,sdhci-8.9a") ||
130 	    OF_is_compatible(faa->fa_node, "brcm,bcm2711-emmc2") ||
131 	    OF_is_compatible(faa->fa_node, "brcm,bcm2835-sdhci") ||
132 	    OF_is_compatible(faa->fa_node, "marvell,armada-3700-sdhci") ||
133 	    OF_is_compatible(faa->fa_node, "marvell,armada-ap806-sdhci") ||
134 	    OF_is_compatible(faa->fa_node, "marvell,armada-cp110-sdhci"));
135 }
136 
137 void
138 sdhc_fdt_attach(struct device *parent, struct device *self, void *aux)
139 {
140 	struct sdhc_fdt_softc *sc = (struct sdhc_fdt_softc *)self;
141 	struct fdt_attach_args *faa = aux;
142 	struct regmap *rm = NULL;
143 	uint32_t reg, phandle, freq, cap = 0;
144 	char pad_type[16] = { 0 };
145 
146 	if (faa->fa_nreg < 1) {
147 		printf(": no registers\n");
148 		return;
149 	}
150 
151 	sc->sc_iot = faa->fa_iot;
152 	sc->sc_size = faa->fa_reg[0].size;
153 	sc->sc_node = faa->fa_node;
154 
155 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
156 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
157 		printf(": can't map registers\n");
158 		return;
159 	}
160 
161 	pinctrl_byname(faa->fa_node, "default");
162 
163 	clock_set_assigned(faa->fa_node);
164 	clock_enable_all(faa->fa_node);
165 	reset_deassert_all(faa->fa_node);
166 
167 	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO,
168 	    sdhc_intr, sc, sc->sc.sc_dev.dv_xname);
169 	if (sc->sc_ih == NULL) {
170 		printf(": can't establish interrupt\n");
171 		goto unmap;
172 	}
173 
174 	if (OF_getproplen(faa->fa_node, "cd-gpios") > 0 ||
175 	    OF_getproplen(faa->fa_node, "non-removable") == 0) {
176 		OF_getpropintarray(faa->fa_node, "cd-gpios", sc->sc_gpio,
177 		    sizeof(sc->sc_gpio));
178 		gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_INPUT);
179 		sc->sc.sc_card_detect = sdhc_fdt_card_detect;
180 	}
181 
182 	sc->sc_vqmmc = OF_getpropint(sc->sc_node, "vqmmc-supply", 0);
183 
184 	printf("\n");
185 
186 	sc->sc.sc_host = &sc->sc_host;
187 	sc->sc.sc_dmat = faa->fa_dmat;
188 
189 	/*
190 	 * Arasan controller always uses 1.8V and doesn't like an
191 	 * explicit switch.
192 	 */
193 	if (OF_is_compatible(faa->fa_node, "arasan,sdhci-5.1"))
194 		sc->sc.sc_signal_voltage = sdhc_fdt_signal_voltage;
195 
196 	/*
197 	 * Rockchip RK3399 PHY doesn't like being powered down at low
198 	 * clock speeds and needs to be powered up explicitly.
199 	 */
200 	if (OF_is_compatible(faa->fa_node, "rockchip,rk3399-sdhci-5.1")) {
201 		/*
202 		 * The eMMC core's clock multiplier is of no use, so we just
203 		 * clear it.  Also make sure to set the base clock frequency.
204 		 */
205 		freq = clock_get_frequency(faa->fa_node, "clk_xin");
206 		freq /= 1000 * 1000; /* in MHz */
207 		phandle = OF_getpropint(faa->fa_node,
208 		    "arasan,soc-ctl-syscon", 0);
209 		if (phandle)
210 			rm = regmap_byphandle(phandle);
211 		if (rm) {
212 			regmap_write_4(rm, GRF_EMMCCORE_CON11,
213 			    GRF_EMMCCORE_CON11_CLOCKMULT_CLR |
214 			    GRF_EMMCCORE_CON11_CLOCKMULT_VAL(0));
215 			regmap_write_4(rm, GRF_EMMCCORE_CON0_BASECLOCK,
216 			    GRF_EMMCCORE_CON0_BASECLOCK_CLR |
217 			    GRF_EMMCCORE_CON0_BASECLOCK_VAL(freq));
218 		}
219 		/* Provide base clock frequency for the PHY driver. */
220 		sc->sc_cd.cd_node = faa->fa_node;
221 		sc->sc_cd.cd_cookie = sc;
222 		sc->sc_cd.cd_get_frequency = sdhc_fdt_get_frequency;
223 		clock_register(&sc->sc_cd);
224 		/*
225 		 * Enable the PHY.  The PHY should be powered on/off in
226 		 * the bus_clock function, but it's good enough to just
227 		 * enable it here right away and to keep it powered on.
228 		 */
229 		phy_enable(faa->fa_node, "phy_arasan");
230 		sc->sc.sc_flags |= SDHC_F_NOPWR0;
231 
232 		/* XXX Doesn't work on Rockchip RK3399. */
233 		sc->sc.sc_flags |= SDHC_F_NODDR50;
234 	}
235 
236 	if (OF_is_compatible(faa->fa_node, "arasan,sdhci-8.9a")) {
237 		freq = clock_get_frequency(faa->fa_node, "clk_xin");
238 		sc->sc.sc_clkbase = freq / 1000;
239 	}
240 
241 	if (OF_is_compatible(faa->fa_node, "brcm,bcm2711-emmc2"))
242 		sc->sc.sc_flags |= SDHC_F_NOPWR0;
243 
244 	if (OF_is_compatible(faa->fa_node, "brcm,bcm2835-sdhci")) {
245 		cap = SDHC_VOLTAGE_SUPP_3_3V | SDHC_HIGH_SPEED_SUPP;
246 		cap |= SDHC_MAX_BLK_LEN_1024 << SDHC_MAX_BLK_LEN_SHIFT;
247 
248 		freq = clock_get_frequency(faa->fa_node, NULL);
249 		sc->sc.sc_clkbase = freq / 1000;
250 
251 		sc->sc.sc_flags |= SDHC_F_32BIT_ACCESS;
252 	}
253 
254 	if (OF_is_compatible(faa->fa_node, "marvell,armada-3700-sdhci") ||
255 	    OF_is_compatible(faa->fa_node, "marvell,armada-ap806-sdhci") ||
256 	    OF_is_compatible(faa->fa_node, "marvell,armada-cp110-sdhci")) {
257 		if (OF_is_compatible(faa->fa_node,
258 		    "marvell,armada-3700-sdhci")) {
259 			KASSERT(faa->fa_nreg > 1);
260 			if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
261 			    faa->fa_reg[1].size, 0, &sc->sc_pad_ioh)) {
262 				printf("%s: can't map registers\n",
263 				    sc->sc.sc_dev.dv_xname);
264 				return;
265 			}
266 			OF_getprop(faa->fa_node, "marvell,pad-type",
267 			    pad_type, sizeof(pad_type));
268 			if (!strcmp(pad_type, "fixed-1-8v")) {
269 				bus_space_write_4(sc->sc_iot, sc->sc_pad_ioh,
270 				    ARMADA_3700_SOC_PAD_CTL,
271 				    ARMADA_3700_SOC_PAD_CTL_1_8V);
272 			} else {
273 				bus_space_write_4(sc->sc_iot, sc->sc_pad_ioh,
274 				    ARMADA_3700_SOC_PAD_CTL,
275 				    ARMADA_3700_SOC_PAD_CTL_3_3V);
276 				regulator_set_voltage(sc->sc_vqmmc, 3300000);
277 			}
278 		}
279 
280 		cap = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
281 		    SDHC_CAPABILITIES);
282 		if (OF_getpropint(faa->fa_node, "bus-width", 1) != 8)
283 			cap &= ~SDHC_8BIT_MODE_SUPP;
284 		if (OF_getproplen(faa->fa_node, "no-1-8-v") == 0) {
285 			cap &= ~SDHC_VOLTAGE_SUPP_1_8V;
286 			sc->sc.sc_flags |= SDHC_F_NODDR50;
287 		}
288 		if (OF_getproplen(faa->fa_node,
289 		    "marvell,xenon-phy-slow-mode") == 0)
290 			sc->sc_slow_mode = 1;
291 
292 		sc->sc_znr = OF_getpropint(faa->fa_node,
293 		    "marvell,xenon-phy-znr", 0xf);
294 		sc->sc_znr &= XENON_EMMC_PHY_PAD_CONTROL2_ZNR_MASK;
295 		sc->sc_zpr = OF_getpropint(faa->fa_node,
296 		    "marvell,xenon-phy-zpr", 0xf);
297 		sc->sc_zpr &= XENON_EMMC_PHY_PAD_CONTROL2_ZPR_MASK;
298 		sc->sc_sdhc_id = OF_getpropint(faa->fa_node,
299 		    "marvell,xenon-sdhc-id", 0);
300 
301 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
302 		    XENON_SYS_OP_CTRL);
303 		reg |= XENON_SYS_OP_CTRL_SLOT_ENABLE(sc->sc_sdhc_id);
304 		reg &= ~XENON_SYS_OP_CTRL_SDCLK_IDLEOFF_ENABLE(sc->sc_sdhc_id);
305 		reg &= ~XENON_SYS_OP_CTRL_AUTO_CLKGATE_DISABLE;
306 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
307 		    XENON_SYS_OP_CTRL, reg);
308 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
309 		    XENON_SYS_EXT_OP_CTRL);
310 		reg |= XENON_SYS_EXT_OP_CTRL_PARALLEL_TRAN(sc->sc_sdhc_id);
311 		reg |= XENON_SYS_EXT_OP_CTRL_MASK_CMD_CONFLICT_ERR;
312 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
313 		    XENON_SYS_EXT_OP_CTRL, reg);
314 
315 		freq = clock_get_frequency(faa->fa_node, NULL);
316 		sc->sc.sc_clkbase = freq / 1000;
317 		sc->sc.sc_bus_clock_post = sdhc_fdt_xenon_bus_clock_post;
318 	}
319 
320 	sdhc_host_found(&sc->sc, sc->sc_iot, sc->sc_ioh, sc->sc_size, 1, cap);
321 	return;
322 
323 unmap:
324 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
325 }
326 
327 int
328 sdhc_fdt_card_detect(struct sdhc_softc *ssc)
329 {
330 	struct sdhc_fdt_softc *sc = (struct sdhc_fdt_softc *)ssc;
331 
332 	if (OF_getproplen(sc->sc_node, "non-removable") == 0)
333 		return 1;
334 
335 	return gpio_controller_get_pin(sc->sc_gpio);
336 }
337 
338 int
339 sdhc_fdt_signal_voltage(struct sdhc_softc *sc, int signal_voltage)
340 {
341 	switch (signal_voltage) {
342 	case SDMMC_SIGNAL_VOLTAGE_180:
343 		return 0;
344 	default:
345 		return EINVAL;
346 	}
347 }
348 
349 uint32_t
350 sdhc_fdt_get_frequency(void *cookie, uint32_t *cells)
351 {
352 	struct sdhc_fdt_softc *sc = cookie;
353 	return clock_get_frequency(sc->sc_cd.cd_node, "clk_xin");
354 }
355 
356 /* Marvell Xenon */
357 void
358 sdhc_fdt_xenon_bus_clock_post(struct sdhc_softc *ssc, int freq, int timing)
359 {
360 	struct sdhc_fdt_softc *sc = (struct sdhc_fdt_softc *)ssc;
361 	uint32_t reg;
362 	int i;
363 
364 	if (freq == 0)
365 		return;
366 
367 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
368 	    XENON_EMMC_PHY_PAD_CONTROL);
369 	reg |= (XENON_EMMC_PHY_PAD_CONTROL_FC_DQ_RECEN |
370 		XENON_EMMC_PHY_PAD_CONTROL_FC_CMD_RECEN |
371 		XENON_EMMC_PHY_PAD_CONTROL_FC_QSP_RECEN |
372 		XENON_EMMC_PHY_PAD_CONTROL_FC_QSN_RECEN |
373 		XENON_EMMC_PHY_PAD_CONTROL_FC_ALL_CMOS_RECVR);
374 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
375 	    XENON_EMMC_PHY_PAD_CONTROL, reg);
376 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
377 	    XENON_EMMC_PHY_PAD_CONTROL1);
378 	reg &= ~(XENON_EMMC_PHY_PAD_CONTROL1_FC_CMD_PD |
379 		XENON_EMMC_PHY_PAD_CONTROL1_FC_DQ_PD);
380 	reg |= (XENON_EMMC_PHY_PAD_CONTROL1_FC_CMD_PU |
381 		XENON_EMMC_PHY_PAD_CONTROL1_FC_DQ_PU);
382 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
383 	    XENON_EMMC_PHY_PAD_CONTROL1, reg);
384 
385 	if (timing == SDMMC_TIMING_LEGACY)
386 		goto phy_init;
387 
388 	/* TODO: check for SMF_IO_MODE and set flag */
389 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
390 	    XENON_EMMC_PHY_TIMING_ADJUST);
391 	reg &= ~XENON_EMMC_PHY_TIMING_ADJUST_SDIO_MODE;
392 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
393 	    XENON_EMMC_PHY_TIMING_ADJUST, reg);
394 
395 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
396 	    XENON_EMMC_PHY_PAD_CONTROL2);
397 	reg &= ~(XENON_EMMC_PHY_PAD_CONTROL2_ZPR_MASK <<
398 	    XENON_EMMC_PHY_PAD_CONTROL2_ZPR_SHIFT |
399 	    XENON_EMMC_PHY_PAD_CONTROL2_ZNR_MASK <<
400 	    XENON_EMMC_PHY_PAD_CONTROL2_ZNR_SHIFT);
401 	reg |= sc->sc_zpr << XENON_EMMC_PHY_PAD_CONTROL2_ZPR_SHIFT |
402 	     sc->sc_znr << XENON_EMMC_PHY_PAD_CONTROL2_ZNR_SHIFT;
403 
404 	reg = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL);
405 	reg &= ~SDHC_SDCLK_ENABLE;
406 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL, reg);
407 
408 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
409 	    XENON_EMMC_PHY_FUNC_CONTROL);
410 	reg &= ~(XENON_EMMC_PHY_FUNC_CONTROL_DQ_DDR_MODE |
411 	     XENON_EMMC_PHY_FUNC_CONTROL_CMD_DDR_MODE);
412 	reg |= XENON_EMMC_PHY_FUNC_CONTROL_DQ_ASYNC_MODE;
413 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
414 	    XENON_EMMC_PHY_FUNC_CONTROL, reg);
415 
416 	reg = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL);
417 	reg |= SDHC_SDCLK_ENABLE;
418 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL, reg);
419 
420 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
421 	    XENON_SLOT_EMMC_CTRL);
422 	reg &= ~(XENON_SLOT_EMMC_CTRL_ENABLE_DATA_STROBE |
423 	    XENON_SLOT_EMMC_CTRL_ENABLE_RESP_STROBE);
424 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
425 	    XENON_SLOT_EMMC_CTRL, reg);
426 
427 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
428 	    XENON_EMMC_PHY_PAD_CONTROL1);
429 	reg &= ~(XENON_EMMC_PHY_PAD_CONTROL1_FC_QSP_PD |
430 		XENON_EMMC_PHY_PAD_CONTROL1_FC_QSP_PU);
431 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
432 	    XENON_EMMC_PHY_PAD_CONTROL1, reg);
433 
434 phy_init:
435 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
436 	    XENON_EMMC_PHY_TIMING_ADJUST);
437 	reg |= XENON_EMMC_PHY_TIMING_ADJUST_SAMPL_INV_QSP_PHASE_SELECT;
438 	reg &= ~XENON_EMMC_PHY_TIMING_ADJUST_SLOW_MODE;
439 	if (timing == SDMMC_TIMING_LEGACY ||
440 	    timing == SDMMC_TIMING_HIGHSPEED || sc->sc_slow_mode)
441 		reg |= XENON_EMMC_PHY_TIMING_ADJUST_SLOW_MODE;
442 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
443 	    XENON_EMMC_PHY_TIMING_ADJUST, reg);
444 
445 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
446 	    XENON_EMMC_PHY_TIMING_ADJUST);
447 	reg |= XENON_EMMC_PHY_TIMING_ADJUST_INIT;
448 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
449 	    XENON_EMMC_PHY_TIMING_ADJUST, reg);
450 
451 	for (i = 1000; i > 0; i--) {
452 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
453 		    XENON_EMMC_PHY_TIMING_ADJUST);
454 		if (!(reg & XENON_EMMC_PHY_TIMING_ADJUST_INIT))
455 			break;
456 		delay(10);
457 	}
458 	if (i == 0)
459 		printf("%s: phy initialization timeout\n",
460 		    sc->sc.sc_dev.dv_xname);
461 
462 	if (freq > SDMMC_SDCLK_400KHZ) {
463 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
464 		    XENON_SYS_OP_CTRL);
465 		reg |= XENON_SYS_OP_CTRL_SDCLK_IDLEOFF_ENABLE(sc->sc_sdhc_id);
466 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
467 		    XENON_SYS_OP_CTRL, reg);
468 	}
469 }
470