xref: /openbsd/sys/dev/fdt/sdhc_fdt.c (revision 73471bf0)
1 /*	$OpenBSD: sdhc_fdt.c,v 1.18 2021/10/24 17:52:27 mpi 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 const 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 		sc->sc.sc_flags |= SDHC_F_NO_HS_BIT;
253 	}
254 
255 	if (OF_is_compatible(faa->fa_node, "marvell,armada-3700-sdhci") ||
256 	    OF_is_compatible(faa->fa_node, "marvell,armada-ap806-sdhci") ||
257 	    OF_is_compatible(faa->fa_node, "marvell,armada-cp110-sdhci")) {
258 		if (OF_is_compatible(faa->fa_node,
259 		    "marvell,armada-3700-sdhci")) {
260 			KASSERT(faa->fa_nreg > 1);
261 			if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
262 			    faa->fa_reg[1].size, 0, &sc->sc_pad_ioh)) {
263 				printf("%s: can't map registers\n",
264 				    sc->sc.sc_dev.dv_xname);
265 				return;
266 			}
267 			OF_getprop(faa->fa_node, "marvell,pad-type",
268 			    pad_type, sizeof(pad_type));
269 			if (!strcmp(pad_type, "fixed-1-8v")) {
270 				bus_space_write_4(sc->sc_iot, sc->sc_pad_ioh,
271 				    ARMADA_3700_SOC_PAD_CTL,
272 				    ARMADA_3700_SOC_PAD_CTL_1_8V);
273 			} else {
274 				bus_space_write_4(sc->sc_iot, sc->sc_pad_ioh,
275 				    ARMADA_3700_SOC_PAD_CTL,
276 				    ARMADA_3700_SOC_PAD_CTL_3_3V);
277 				regulator_set_voltage(sc->sc_vqmmc, 3300000);
278 			}
279 		}
280 
281 		cap = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
282 		    SDHC_CAPABILITIES);
283 		if (OF_getpropint(faa->fa_node, "bus-width", 1) != 8)
284 			cap &= ~SDHC_8BIT_MODE_SUPP;
285 		if (OF_getproplen(faa->fa_node, "no-1-8-v") == 0) {
286 			cap &= ~SDHC_VOLTAGE_SUPP_1_8V;
287 			sc->sc.sc_flags |= SDHC_F_NODDR50;
288 		}
289 		if (OF_getproplen(faa->fa_node,
290 		    "marvell,xenon-phy-slow-mode") == 0)
291 			sc->sc_slow_mode = 1;
292 
293 		sc->sc_znr = OF_getpropint(faa->fa_node,
294 		    "marvell,xenon-phy-znr", 0xf);
295 		sc->sc_znr &= XENON_EMMC_PHY_PAD_CONTROL2_ZNR_MASK;
296 		sc->sc_zpr = OF_getpropint(faa->fa_node,
297 		    "marvell,xenon-phy-zpr", 0xf);
298 		sc->sc_zpr &= XENON_EMMC_PHY_PAD_CONTROL2_ZPR_MASK;
299 		sc->sc_sdhc_id = OF_getpropint(faa->fa_node,
300 		    "marvell,xenon-sdhc-id", 0);
301 
302 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
303 		    XENON_SYS_OP_CTRL);
304 		reg |= XENON_SYS_OP_CTRL_SLOT_ENABLE(sc->sc_sdhc_id);
305 		reg &= ~XENON_SYS_OP_CTRL_SDCLK_IDLEOFF_ENABLE(sc->sc_sdhc_id);
306 		reg &= ~XENON_SYS_OP_CTRL_AUTO_CLKGATE_DISABLE;
307 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
308 		    XENON_SYS_OP_CTRL, reg);
309 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
310 		    XENON_SYS_EXT_OP_CTRL);
311 		reg |= XENON_SYS_EXT_OP_CTRL_PARALLEL_TRAN(sc->sc_sdhc_id);
312 		reg |= XENON_SYS_EXT_OP_CTRL_MASK_CMD_CONFLICT_ERR;
313 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
314 		    XENON_SYS_EXT_OP_CTRL, reg);
315 
316 		freq = clock_get_frequency(faa->fa_node, NULL);
317 		sc->sc.sc_clkbase = freq / 1000;
318 		sc->sc.sc_bus_clock_post = sdhc_fdt_xenon_bus_clock_post;
319 	}
320 
321 	sdhc_host_found(&sc->sc, sc->sc_iot, sc->sc_ioh, sc->sc_size, 1, cap);
322 	return;
323 
324 unmap:
325 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
326 }
327 
328 int
329 sdhc_fdt_card_detect(struct sdhc_softc *ssc)
330 {
331 	struct sdhc_fdt_softc *sc = (struct sdhc_fdt_softc *)ssc;
332 
333 	if (OF_getproplen(sc->sc_node, "non-removable") == 0)
334 		return 1;
335 
336 	return gpio_controller_get_pin(sc->sc_gpio);
337 }
338 
339 int
340 sdhc_fdt_signal_voltage(struct sdhc_softc *sc, int signal_voltage)
341 {
342 	switch (signal_voltage) {
343 	case SDMMC_SIGNAL_VOLTAGE_180:
344 		return 0;
345 	default:
346 		return EINVAL;
347 	}
348 }
349 
350 uint32_t
351 sdhc_fdt_get_frequency(void *cookie, uint32_t *cells)
352 {
353 	struct sdhc_fdt_softc *sc = cookie;
354 	return clock_get_frequency(sc->sc_cd.cd_node, "clk_xin");
355 }
356 
357 /* Marvell Xenon */
358 void
359 sdhc_fdt_xenon_bus_clock_post(struct sdhc_softc *ssc, int freq, int timing)
360 {
361 	struct sdhc_fdt_softc *sc = (struct sdhc_fdt_softc *)ssc;
362 	uint32_t reg;
363 	int i;
364 
365 	if (freq == 0)
366 		return;
367 
368 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
369 	    XENON_EMMC_PHY_PAD_CONTROL);
370 	reg |= (XENON_EMMC_PHY_PAD_CONTROL_FC_DQ_RECEN |
371 		XENON_EMMC_PHY_PAD_CONTROL_FC_CMD_RECEN |
372 		XENON_EMMC_PHY_PAD_CONTROL_FC_QSP_RECEN |
373 		XENON_EMMC_PHY_PAD_CONTROL_FC_QSN_RECEN |
374 		XENON_EMMC_PHY_PAD_CONTROL_FC_ALL_CMOS_RECVR);
375 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
376 	    XENON_EMMC_PHY_PAD_CONTROL, reg);
377 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
378 	    XENON_EMMC_PHY_PAD_CONTROL1);
379 	reg &= ~(XENON_EMMC_PHY_PAD_CONTROL1_FC_CMD_PD |
380 		XENON_EMMC_PHY_PAD_CONTROL1_FC_DQ_PD);
381 	reg |= (XENON_EMMC_PHY_PAD_CONTROL1_FC_CMD_PU |
382 		XENON_EMMC_PHY_PAD_CONTROL1_FC_DQ_PU);
383 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
384 	    XENON_EMMC_PHY_PAD_CONTROL1, reg);
385 
386 	if (timing == SDMMC_TIMING_LEGACY)
387 		goto phy_init;
388 
389 	/* TODO: check for SMF_IO_MODE and set flag */
390 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
391 	    XENON_EMMC_PHY_TIMING_ADJUST);
392 	reg &= ~XENON_EMMC_PHY_TIMING_ADJUST_SDIO_MODE;
393 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
394 	    XENON_EMMC_PHY_TIMING_ADJUST, reg);
395 
396 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
397 	    XENON_EMMC_PHY_PAD_CONTROL2);
398 	reg &= ~(XENON_EMMC_PHY_PAD_CONTROL2_ZPR_MASK <<
399 	    XENON_EMMC_PHY_PAD_CONTROL2_ZPR_SHIFT |
400 	    XENON_EMMC_PHY_PAD_CONTROL2_ZNR_MASK <<
401 	    XENON_EMMC_PHY_PAD_CONTROL2_ZNR_SHIFT);
402 	reg |= sc->sc_zpr << XENON_EMMC_PHY_PAD_CONTROL2_ZPR_SHIFT |
403 	     sc->sc_znr << XENON_EMMC_PHY_PAD_CONTROL2_ZNR_SHIFT;
404 
405 	reg = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL);
406 	reg &= ~SDHC_SDCLK_ENABLE;
407 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL, reg);
408 
409 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
410 	    XENON_EMMC_PHY_FUNC_CONTROL);
411 	reg &= ~(XENON_EMMC_PHY_FUNC_CONTROL_DQ_DDR_MODE |
412 	     XENON_EMMC_PHY_FUNC_CONTROL_CMD_DDR_MODE);
413 	reg |= XENON_EMMC_PHY_FUNC_CONTROL_DQ_ASYNC_MODE;
414 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
415 	    XENON_EMMC_PHY_FUNC_CONTROL, reg);
416 
417 	reg = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL);
418 	reg |= SDHC_SDCLK_ENABLE;
419 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL, reg);
420 
421 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
422 	    XENON_SLOT_EMMC_CTRL);
423 	reg &= ~(XENON_SLOT_EMMC_CTRL_ENABLE_DATA_STROBE |
424 	    XENON_SLOT_EMMC_CTRL_ENABLE_RESP_STROBE);
425 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
426 	    XENON_SLOT_EMMC_CTRL, reg);
427 
428 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
429 	    XENON_EMMC_PHY_PAD_CONTROL1);
430 	reg &= ~(XENON_EMMC_PHY_PAD_CONTROL1_FC_QSP_PD |
431 		XENON_EMMC_PHY_PAD_CONTROL1_FC_QSP_PU);
432 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
433 	    XENON_EMMC_PHY_PAD_CONTROL1, reg);
434 
435 phy_init:
436 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
437 	    XENON_EMMC_PHY_TIMING_ADJUST);
438 	reg |= XENON_EMMC_PHY_TIMING_ADJUST_SAMPL_INV_QSP_PHASE_SELECT;
439 	reg &= ~XENON_EMMC_PHY_TIMING_ADJUST_SLOW_MODE;
440 	if (timing == SDMMC_TIMING_LEGACY ||
441 	    timing == SDMMC_TIMING_HIGHSPEED || sc->sc_slow_mode)
442 		reg |= XENON_EMMC_PHY_TIMING_ADJUST_SLOW_MODE;
443 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
444 	    XENON_EMMC_PHY_TIMING_ADJUST, reg);
445 
446 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
447 	    XENON_EMMC_PHY_TIMING_ADJUST);
448 	reg |= XENON_EMMC_PHY_TIMING_ADJUST_INIT;
449 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
450 	    XENON_EMMC_PHY_TIMING_ADJUST, reg);
451 
452 	for (i = 1000; i > 0; i--) {
453 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
454 		    XENON_EMMC_PHY_TIMING_ADJUST);
455 		if (!(reg & XENON_EMMC_PHY_TIMING_ADJUST_INIT))
456 			break;
457 		delay(10);
458 	}
459 	if (i == 0)
460 		printf("%s: phy initialization timeout\n",
461 		    sc->sc.sc_dev.dv_xname);
462 
463 	if (freq > SDMMC_SDCLK_400KHZ) {
464 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
465 		    XENON_SYS_OP_CTRL);
466 		reg |= XENON_SYS_OP_CTRL_SDCLK_IDLEOFF_ENABLE(sc->sc_sdhc_id);
467 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
468 		    XENON_SYS_OP_CTRL, reg);
469 	}
470 }
471