xref: /openbsd/sys/dev/fdt/sdhc_fdt.c (revision 3a3d566b)
1 /*	$OpenBSD: sdhc_fdt.c,v 1.21 2024/10/09 00:38:26 jsg 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 	NULL, sdhc_activate
116 };
117 
118 int	sdhc_fdt_card_detect(struct sdhc_softc *);
119 int	sdhc_fdt_signal_voltage(struct sdhc_softc *, int);
120 uint32_t sdhc_fdt_get_frequency(void *, uint32_t *);
121 
122 void	sdhc_fdt_xenon_bus_clock_post(struct sdhc_softc *, int, int);
123 
124 int
sdhc_fdt_match(struct device * parent,void * match,void * aux)125 sdhc_fdt_match(struct device *parent, void *match, void *aux)
126 {
127 	struct fdt_attach_args *faa = aux;
128 
129 	return (OF_is_compatible(faa->fa_node, "arasan,sdhci-5.1") ||
130 	    OF_is_compatible(faa->fa_node, "arasan,sdhci-8.9a") ||
131 	    OF_is_compatible(faa->fa_node, "brcm,bcm2711-emmc2") ||
132 	    OF_is_compatible(faa->fa_node, "brcm,bcm2835-sdhci") ||
133 	    OF_is_compatible(faa->fa_node, "marvell,armada-3700-sdhci") ||
134 	    OF_is_compatible(faa->fa_node, "marvell,armada-ap806-sdhci") ||
135 	    OF_is_compatible(faa->fa_node, "marvell,armada-cp110-sdhci"));
136 }
137 
138 void
sdhc_fdt_attach(struct device * parent,struct device * self,void * aux)139 sdhc_fdt_attach(struct device *parent, struct device *self, void *aux)
140 {
141 	struct sdhc_fdt_softc *sc = (struct sdhc_fdt_softc *)self;
142 	struct fdt_attach_args *faa = aux;
143 	struct regmap *rm = NULL;
144 	uint64_t capmask = 0, capset = 0;
145 	uint32_t reg, phandle, freq;
146 	char pad_type[16] = { 0 };
147 
148 	if (faa->fa_nreg < 1) {
149 		printf(": no registers\n");
150 		return;
151 	}
152 
153 	sc->sc_iot = faa->fa_iot;
154 	sc->sc_size = faa->fa_reg[0].size;
155 	sc->sc_node = faa->fa_node;
156 
157 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
158 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
159 		printf(": can't map registers\n");
160 		return;
161 	}
162 
163 	pinctrl_byname(faa->fa_node, "default");
164 
165 	clock_set_assigned(faa->fa_node);
166 	clock_enable_all(faa->fa_node);
167 	reset_deassert_all(faa->fa_node);
168 
169 	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO,
170 	    sdhc_intr, sc, sc->sc.sc_dev.dv_xname);
171 	if (sc->sc_ih == NULL) {
172 		printf(": can't establish interrupt\n");
173 		goto unmap;
174 	}
175 
176 	if (OF_getproplen(faa->fa_node, "cd-gpios") > 0 ||
177 	    OF_getproplen(faa->fa_node, "non-removable") == 0) {
178 		OF_getpropintarray(faa->fa_node, "cd-gpios", sc->sc_gpio,
179 		    sizeof(sc->sc_gpio));
180 		gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_INPUT);
181 		sc->sc.sc_card_detect = sdhc_fdt_card_detect;
182 	}
183 
184 	sc->sc_vqmmc = OF_getpropint(sc->sc_node, "vqmmc-supply", 0);
185 
186 	printf("\n");
187 
188 	sc->sc.sc_host = &sc->sc_host;
189 	sc->sc.sc_dmat = faa->fa_dmat;
190 
191 	/*
192 	 * Arasan controller always uses 1.8V and doesn't like an
193 	 * explicit switch.
194 	 */
195 	if (OF_is_compatible(faa->fa_node, "arasan,sdhci-5.1"))
196 		sc->sc.sc_signal_voltage = sdhc_fdt_signal_voltage;
197 
198 	/*
199 	 * Rockchip RK3399 PHY doesn't like being powered down at low
200 	 * clock speeds and needs to be powered up explicitly.
201 	 */
202 	if (OF_is_compatible(faa->fa_node, "rockchip,rk3399-sdhci-5.1")) {
203 		/*
204 		 * The eMMC core's clock multiplier is of no use, so we just
205 		 * clear it.  Also make sure to set the base clock frequency.
206 		 */
207 		freq = clock_get_frequency(faa->fa_node, "clk_xin");
208 		freq /= 1000 * 1000; /* in MHz */
209 		phandle = OF_getpropint(faa->fa_node,
210 		    "arasan,soc-ctl-syscon", 0);
211 		if (phandle)
212 			rm = regmap_byphandle(phandle);
213 		if (rm) {
214 			regmap_write_4(rm, GRF_EMMCCORE_CON11,
215 			    GRF_EMMCCORE_CON11_CLOCKMULT_CLR |
216 			    GRF_EMMCCORE_CON11_CLOCKMULT_VAL(0));
217 			regmap_write_4(rm, GRF_EMMCCORE_CON0_BASECLOCK,
218 			    GRF_EMMCCORE_CON0_BASECLOCK_CLR |
219 			    GRF_EMMCCORE_CON0_BASECLOCK_VAL(freq));
220 		}
221 		/* Provide base clock frequency for the PHY driver. */
222 		sc->sc_cd.cd_node = faa->fa_node;
223 		sc->sc_cd.cd_cookie = sc;
224 		sc->sc_cd.cd_get_frequency = sdhc_fdt_get_frequency;
225 		clock_register(&sc->sc_cd);
226 		/*
227 		 * Enable the PHY.  The PHY should be powered on/off in
228 		 * the bus_clock function, but it's good enough to just
229 		 * enable it here right away and to keep it powered on.
230 		 */
231 		phy_enable(faa->fa_node, "phy_arasan");
232 		sc->sc.sc_flags |= SDHC_F_NOPWR0;
233 
234 		/* XXX Doesn't work on Rockchip RK3399. */
235 		capmask |= (uint64_t)SDHC_DDR50_SUPP << 32;
236 	}
237 
238 	if (OF_is_compatible(faa->fa_node, "arasan,sdhci-8.9a")) {
239 		freq = clock_get_frequency(faa->fa_node, "clk_xin");
240 		sc->sc.sc_clkbase = freq / 1000;
241 	}
242 
243 	if (OF_is_compatible(faa->fa_node, "brcm,bcm2711-emmc2"))
244 		sc->sc.sc_flags |= SDHC_F_NOPWR0;
245 
246 	if (OF_is_compatible(faa->fa_node, "brcm,bcm2835-sdhci")) {
247 		capmask = 0xffffffff;
248 		capset = SDHC_VOLTAGE_SUPP_3_3V | SDHC_HIGH_SPEED_SUPP;
249 		capset |= SDHC_MAX_BLK_LEN_1024 << SDHC_MAX_BLK_LEN_SHIFT;
250 
251 		freq = clock_get_frequency(faa->fa_node, NULL);
252 		sc->sc.sc_clkbase = freq / 1000;
253 
254 		sc->sc.sc_flags |= SDHC_F_32BIT_ACCESS;
255 		sc->sc.sc_flags |= SDHC_F_NO_HS_BIT;
256 	}
257 
258 	if (OF_is_compatible(faa->fa_node, "marvell,armada-3700-sdhci") ||
259 	    OF_is_compatible(faa->fa_node, "marvell,armada-ap806-sdhci") ||
260 	    OF_is_compatible(faa->fa_node, "marvell,armada-cp110-sdhci")) {
261 		if (OF_is_compatible(faa->fa_node,
262 		    "marvell,armada-3700-sdhci")) {
263 			KASSERT(faa->fa_nreg > 1);
264 			if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
265 			    faa->fa_reg[1].size, 0, &sc->sc_pad_ioh)) {
266 				printf("%s: can't map registers\n",
267 				    sc->sc.sc_dev.dv_xname);
268 				return;
269 			}
270 			OF_getprop(faa->fa_node, "marvell,pad-type",
271 			    pad_type, sizeof(pad_type));
272 			if (!strcmp(pad_type, "fixed-1-8v")) {
273 				bus_space_write_4(sc->sc_iot, sc->sc_pad_ioh,
274 				    ARMADA_3700_SOC_PAD_CTL,
275 				    ARMADA_3700_SOC_PAD_CTL_1_8V);
276 			} else {
277 				bus_space_write_4(sc->sc_iot, sc->sc_pad_ioh,
278 				    ARMADA_3700_SOC_PAD_CTL,
279 				    ARMADA_3700_SOC_PAD_CTL_3_3V);
280 				regulator_set_voltage(sc->sc_vqmmc, 3300000);
281 			}
282 		}
283 
284 		if (OF_getpropint(faa->fa_node, "bus-width", 1) != 8)
285 			capmask |= SDHC_8BIT_MODE_SUPP;
286 		if (OF_getproplen(faa->fa_node, "no-1-8-v") == 0) {
287 			capmask |= SDHC_VOLTAGE_SUPP_1_8V;
288 			capmask |= (uint64_t)SDHC_DDR50_SUPP << 32;
289 		}
290 		if (OF_getproplen(faa->fa_node,
291 		    "marvell,xenon-phy-slow-mode") == 0)
292 			sc->sc_slow_mode = 1;
293 
294 		sc->sc_znr = OF_getpropint(faa->fa_node,
295 		    "marvell,xenon-phy-znr", 0xf);
296 		sc->sc_znr &= XENON_EMMC_PHY_PAD_CONTROL2_ZNR_MASK;
297 		sc->sc_zpr = OF_getpropint(faa->fa_node,
298 		    "marvell,xenon-phy-zpr", 0xf);
299 		sc->sc_zpr &= XENON_EMMC_PHY_PAD_CONTROL2_ZPR_MASK;
300 		sc->sc_sdhc_id = OF_getpropint(faa->fa_node,
301 		    "marvell,xenon-sdhc-id", 0);
302 
303 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
304 		    XENON_SYS_OP_CTRL);
305 		reg |= XENON_SYS_OP_CTRL_SLOT_ENABLE(sc->sc_sdhc_id);
306 		reg &= ~XENON_SYS_OP_CTRL_SDCLK_IDLEOFF_ENABLE(sc->sc_sdhc_id);
307 		reg &= ~XENON_SYS_OP_CTRL_AUTO_CLKGATE_DISABLE;
308 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
309 		    XENON_SYS_OP_CTRL, reg);
310 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
311 		    XENON_SYS_EXT_OP_CTRL);
312 		reg |= XENON_SYS_EXT_OP_CTRL_PARALLEL_TRAN(sc->sc_sdhc_id);
313 		reg |= XENON_SYS_EXT_OP_CTRL_MASK_CMD_CONFLICT_ERR;
314 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
315 		    XENON_SYS_EXT_OP_CTRL, reg);
316 
317 		freq = clock_get_frequency(faa->fa_node, NULL);
318 		sc->sc.sc_clkbase = freq / 1000;
319 		sc->sc.sc_bus_clock_post = sdhc_fdt_xenon_bus_clock_post;
320 	}
321 
322 	sdhc_host_found(&sc->sc, sc->sc_iot, sc->sc_ioh, sc->sc_size, 1,
323 	    capmask, capset);
324 	return;
325 
326 unmap:
327 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
328 }
329 
330 int
sdhc_fdt_card_detect(struct sdhc_softc * ssc)331 sdhc_fdt_card_detect(struct sdhc_softc *ssc)
332 {
333 	struct sdhc_fdt_softc *sc = (struct sdhc_fdt_softc *)ssc;
334 
335 	if (OF_getproplen(sc->sc_node, "non-removable") == 0)
336 		return 1;
337 
338 	return gpio_controller_get_pin(sc->sc_gpio);
339 }
340 
341 int
sdhc_fdt_signal_voltage(struct sdhc_softc * sc,int signal_voltage)342 sdhc_fdt_signal_voltage(struct sdhc_softc *sc, int signal_voltage)
343 {
344 	switch (signal_voltage) {
345 	case SDMMC_SIGNAL_VOLTAGE_180:
346 		return 0;
347 	default:
348 		return EINVAL;
349 	}
350 }
351 
352 uint32_t
sdhc_fdt_get_frequency(void * cookie,uint32_t * cells)353 sdhc_fdt_get_frequency(void *cookie, uint32_t *cells)
354 {
355 	struct sdhc_fdt_softc *sc = cookie;
356 	return clock_get_frequency(sc->sc_cd.cd_node, "clk_xin");
357 }
358 
359 /* Marvell Xenon */
360 void
sdhc_fdt_xenon_bus_clock_post(struct sdhc_softc * ssc,int freq,int timing)361 sdhc_fdt_xenon_bus_clock_post(struct sdhc_softc *ssc, int freq, int timing)
362 {
363 	struct sdhc_fdt_softc *sc = (struct sdhc_fdt_softc *)ssc;
364 	uint32_t reg;
365 	int i;
366 
367 	if (freq == 0)
368 		return;
369 
370 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
371 	    XENON_EMMC_PHY_PAD_CONTROL);
372 	reg |= (XENON_EMMC_PHY_PAD_CONTROL_FC_DQ_RECEN |
373 		XENON_EMMC_PHY_PAD_CONTROL_FC_CMD_RECEN |
374 		XENON_EMMC_PHY_PAD_CONTROL_FC_QSP_RECEN |
375 		XENON_EMMC_PHY_PAD_CONTROL_FC_QSN_RECEN |
376 		XENON_EMMC_PHY_PAD_CONTROL_FC_ALL_CMOS_RECVR);
377 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
378 	    XENON_EMMC_PHY_PAD_CONTROL, reg);
379 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
380 	    XENON_EMMC_PHY_PAD_CONTROL1);
381 	reg &= ~(XENON_EMMC_PHY_PAD_CONTROL1_FC_CMD_PD |
382 		XENON_EMMC_PHY_PAD_CONTROL1_FC_DQ_PD);
383 	reg |= (XENON_EMMC_PHY_PAD_CONTROL1_FC_CMD_PU |
384 		XENON_EMMC_PHY_PAD_CONTROL1_FC_DQ_PU);
385 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
386 	    XENON_EMMC_PHY_PAD_CONTROL1, reg);
387 
388 	if (timing == SDMMC_TIMING_LEGACY)
389 		goto phy_init;
390 
391 	/* TODO: check for SMF_IO_MODE and set flag */
392 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
393 	    XENON_EMMC_PHY_TIMING_ADJUST);
394 	reg &= ~XENON_EMMC_PHY_TIMING_ADJUST_SDIO_MODE;
395 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
396 	    XENON_EMMC_PHY_TIMING_ADJUST, reg);
397 
398 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
399 	    XENON_EMMC_PHY_PAD_CONTROL2);
400 	reg &= ~(XENON_EMMC_PHY_PAD_CONTROL2_ZPR_MASK <<
401 	    XENON_EMMC_PHY_PAD_CONTROL2_ZPR_SHIFT |
402 	    XENON_EMMC_PHY_PAD_CONTROL2_ZNR_MASK <<
403 	    XENON_EMMC_PHY_PAD_CONTROL2_ZNR_SHIFT);
404 	reg |= sc->sc_zpr << XENON_EMMC_PHY_PAD_CONTROL2_ZPR_SHIFT |
405 	     sc->sc_znr << XENON_EMMC_PHY_PAD_CONTROL2_ZNR_SHIFT;
406 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
407 	    XENON_EMMC_PHY_PAD_CONTROL2, reg);
408 
409 	reg = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL);
410 	reg &= ~SDHC_SDCLK_ENABLE;
411 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL, reg);
412 
413 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
414 	    XENON_EMMC_PHY_FUNC_CONTROL);
415 	reg &= ~(XENON_EMMC_PHY_FUNC_CONTROL_DQ_DDR_MODE |
416 	     XENON_EMMC_PHY_FUNC_CONTROL_CMD_DDR_MODE);
417 	reg |= XENON_EMMC_PHY_FUNC_CONTROL_DQ_ASYNC_MODE;
418 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
419 	    XENON_EMMC_PHY_FUNC_CONTROL, reg);
420 
421 	reg = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL);
422 	reg |= SDHC_SDCLK_ENABLE;
423 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SDHC_CLOCK_CTL, reg);
424 
425 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
426 	    XENON_SLOT_EMMC_CTRL);
427 	reg &= ~(XENON_SLOT_EMMC_CTRL_ENABLE_DATA_STROBE |
428 	    XENON_SLOT_EMMC_CTRL_ENABLE_RESP_STROBE);
429 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
430 	    XENON_SLOT_EMMC_CTRL, reg);
431 
432 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
433 	    XENON_EMMC_PHY_PAD_CONTROL1);
434 	reg &= ~(XENON_EMMC_PHY_PAD_CONTROL1_FC_QSP_PD |
435 		XENON_EMMC_PHY_PAD_CONTROL1_FC_QSP_PU);
436 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
437 	    XENON_EMMC_PHY_PAD_CONTROL1, reg);
438 
439 phy_init:
440 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
441 	    XENON_EMMC_PHY_TIMING_ADJUST);
442 	reg |= XENON_EMMC_PHY_TIMING_ADJUST_SAMPL_INV_QSP_PHASE_SELECT;
443 	reg &= ~XENON_EMMC_PHY_TIMING_ADJUST_SLOW_MODE;
444 	if (timing == SDMMC_TIMING_LEGACY ||
445 	    timing == SDMMC_TIMING_HIGHSPEED || sc->sc_slow_mode)
446 		reg |= XENON_EMMC_PHY_TIMING_ADJUST_SLOW_MODE;
447 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
448 	    XENON_EMMC_PHY_TIMING_ADJUST, reg);
449 
450 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
451 	    XENON_EMMC_PHY_TIMING_ADJUST);
452 	reg |= XENON_EMMC_PHY_TIMING_ADJUST_INIT;
453 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
454 	    XENON_EMMC_PHY_TIMING_ADJUST, reg);
455 
456 	for (i = 1000; i > 0; i--) {
457 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
458 		    XENON_EMMC_PHY_TIMING_ADJUST);
459 		if (!(reg & XENON_EMMC_PHY_TIMING_ADJUST_INIT))
460 			break;
461 		delay(10);
462 	}
463 	if (i == 0)
464 		printf("%s: phy initialization timeout\n",
465 		    sc->sc.sc_dev.dv_xname);
466 
467 	if (freq > SDMMC_SDCLK_400KHZ) {
468 		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
469 		    XENON_SYS_OP_CTRL);
470 		reg |= XENON_SYS_OP_CTRL_SDCLK_IDLEOFF_ENABLE(sc->sc_sdhc_id);
471 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
472 		    XENON_SYS_OP_CTRL, reg);
473 	}
474 }
475