xref: /netbsd-src/sys/arch/arm/amlogic/meson_sdhc.c (revision c34066c2c9d269307d53ba85708f1aca977c2286)
1*c34066c2Sjmcneill /* $NetBSD: meson_sdhc.c,v 1.6 2021/11/07 17:11:58 jmcneill Exp $ */
2fb172c8aSjmcneill 
3fb172c8aSjmcneill /*-
4fb172c8aSjmcneill  * Copyright (c) 2015-2019 Jared McNeill <jmcneill@invisible.ca>
5fb172c8aSjmcneill  * All rights reserved.
6fb172c8aSjmcneill  *
7fb172c8aSjmcneill  * Redistribution and use in source and binary forms, with or without
8fb172c8aSjmcneill  * modification, are permitted provided that the following conditions
9fb172c8aSjmcneill  * are met:
10fb172c8aSjmcneill  * 1. Redistributions of source code must retain the above copyright
11fb172c8aSjmcneill  *    notice, this list of conditions and the following disclaimer.
12fb172c8aSjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
13fb172c8aSjmcneill  *    notice, this list of conditions and the following disclaimer in the
14fb172c8aSjmcneill  *    documentation and/or other materials provided with the distribution.
15fb172c8aSjmcneill  *
16fb172c8aSjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17fb172c8aSjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18fb172c8aSjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19fb172c8aSjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20fb172c8aSjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21fb172c8aSjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22fb172c8aSjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23fb172c8aSjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24fb172c8aSjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25fb172c8aSjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26fb172c8aSjmcneill  * SUCH DAMAGE.
27fb172c8aSjmcneill  */
28fb172c8aSjmcneill 
29fb172c8aSjmcneill #include <sys/cdefs.h>
30*c34066c2Sjmcneill __KERNEL_RCSID(0, "$NetBSD: meson_sdhc.c,v 1.6 2021/11/07 17:11:58 jmcneill Exp $");
31fb172c8aSjmcneill 
32fb172c8aSjmcneill #include <sys/param.h>
33fb172c8aSjmcneill #include <sys/bus.h>
34fb172c8aSjmcneill #include <sys/device.h>
35fb172c8aSjmcneill #include <sys/intr.h>
36fb172c8aSjmcneill #include <sys/systm.h>
37fb172c8aSjmcneill #include <sys/kernel.h>
38fb172c8aSjmcneill #include <sys/gpio.h>
39fb172c8aSjmcneill 
40fb172c8aSjmcneill #include <dev/sdmmc/sdmmcvar.h>
41fb172c8aSjmcneill #include <dev/sdmmc/sdmmcchip.h>
42fb172c8aSjmcneill #include <dev/sdmmc/sdmmc_ioreg.h>
43fb172c8aSjmcneill 
44fb172c8aSjmcneill #include <dev/fdt/fdtvar.h>
45fb172c8aSjmcneill 
46fb172c8aSjmcneill #include <arm/amlogic/meson_sdhcreg.h>
47fb172c8aSjmcneill 
48fb172c8aSjmcneill enum {
49fb172c8aSjmcneill 	SDHC_PORT_A = 0,
50fb172c8aSjmcneill 	SDHC_PORT_B = 1,
51fb172c8aSjmcneill 	SDHC_PORT_C = 2
52fb172c8aSjmcneill };
53fb172c8aSjmcneill 
54fb172c8aSjmcneill static int	meson_sdhc_match(device_t, cfdata_t, void *);
55fb172c8aSjmcneill static void	meson_sdhc_attach(device_t, device_t, void *);
56fb172c8aSjmcneill static void	meson_sdhc_attach_i(device_t);
57fb172c8aSjmcneill 
58fb172c8aSjmcneill static int	meson_sdhc_intr(void *);
59fb172c8aSjmcneill 
60fb172c8aSjmcneill struct meson_sdhc_softc {
61fb172c8aSjmcneill 	device_t		sc_dev;
62fb172c8aSjmcneill 	bus_space_tag_t		sc_bst;
63fb172c8aSjmcneill 	bus_space_handle_t	sc_bsh;
64fb172c8aSjmcneill 	bus_dma_tag_t		sc_dmat;
65fb172c8aSjmcneill 	void			*sc_ih;
66fb172c8aSjmcneill 
67fb172c8aSjmcneill 	device_t		sc_sdmmc_dev;
68fb172c8aSjmcneill 	kmutex_t		sc_intr_lock;
69fb172c8aSjmcneill 	kcondvar_t		sc_intr_cv;
70fb172c8aSjmcneill 
71fb172c8aSjmcneill 	uint32_t		sc_intr_ista;
72fb172c8aSjmcneill 
73fb172c8aSjmcneill 	bus_dmamap_t		sc_dmamap;
74fb172c8aSjmcneill 	bus_dma_segment_t	sc_segs[1];
75fb172c8aSjmcneill 	void			*sc_bbuf;
76fb172c8aSjmcneill 
77fb172c8aSjmcneill 	u_int			sc_bus_freq;
78fb172c8aSjmcneill 
79fb172c8aSjmcneill 	struct fdtbus_gpio_pin	*sc_gpio_cd;
80fb172c8aSjmcneill 	int			sc_gpio_cd_inverted;
81fb172c8aSjmcneill 	struct fdtbus_gpio_pin	*sc_gpio_wp;
82fb172c8aSjmcneill 	int			sc_gpio_wp_inverted;
83fb172c8aSjmcneill 
84fb172c8aSjmcneill 	struct fdtbus_regulator	*sc_reg_vmmc;
85fb172c8aSjmcneill 	struct fdtbus_regulator	*sc_reg_vqmmc;
86fb172c8aSjmcneill 
87fb172c8aSjmcneill 	bool			sc_non_removable;
88fb172c8aSjmcneill 	bool			sc_broken_cd;
89fb172c8aSjmcneill 
90fb172c8aSjmcneill 	int			sc_port;
91fb172c8aSjmcneill 	int			sc_slot_phandle;
92fb172c8aSjmcneill 	int			sc_signal_voltage;
93fb172c8aSjmcneill };
94fb172c8aSjmcneill 
95fb172c8aSjmcneill CFATTACH_DECL_NEW(meson_sdhc, sizeof(struct meson_sdhc_softc),
96fb172c8aSjmcneill 	meson_sdhc_match, meson_sdhc_attach, NULL, NULL);
97fb172c8aSjmcneill 
98fb172c8aSjmcneill static int	meson_sdhc_host_reset(sdmmc_chipset_handle_t);
99fb172c8aSjmcneill static uint32_t	meson_sdhc_host_ocr(sdmmc_chipset_handle_t);
100fb172c8aSjmcneill static int	meson_sdhc_host_maxblklen(sdmmc_chipset_handle_t);
101fb172c8aSjmcneill static int	meson_sdhc_card_detect(sdmmc_chipset_handle_t);
102fb172c8aSjmcneill static int	meson_sdhc_write_protect(sdmmc_chipset_handle_t);
103fb172c8aSjmcneill static int	meson_sdhc_bus_power(sdmmc_chipset_handle_t, uint32_t);
104fb172c8aSjmcneill static int	meson_sdhc_bus_clock(sdmmc_chipset_handle_t, int);
105fb172c8aSjmcneill static int	meson_sdhc_bus_width(sdmmc_chipset_handle_t, int);
106fb172c8aSjmcneill static int	meson_sdhc_bus_rod(sdmmc_chipset_handle_t, int);
107fb172c8aSjmcneill static void	meson_sdhc_exec_command(sdmmc_chipset_handle_t,
108fb172c8aSjmcneill 				     struct sdmmc_command *);
109fb172c8aSjmcneill static void	meson_sdhc_card_enable_intr(sdmmc_chipset_handle_t, int);
110fb172c8aSjmcneill static void	meson_sdhc_card_intr_ack(sdmmc_chipset_handle_t);
111fb172c8aSjmcneill static int	meson_sdhc_signal_voltage(sdmmc_chipset_handle_t, int);
112fb172c8aSjmcneill static int	meson_sdhc_execute_tuning(sdmmc_chipset_handle_t, int);
113fb172c8aSjmcneill 
114fb172c8aSjmcneill static int	meson_sdhc_default_rx_phase(struct meson_sdhc_softc *);
115fb172c8aSjmcneill static int	meson_sdhc_set_clock(struct meson_sdhc_softc *, u_int);
116fb172c8aSjmcneill static int	meson_sdhc_wait_idle(struct meson_sdhc_softc *);
117fb172c8aSjmcneill static int	meson_sdhc_wait_ista(struct meson_sdhc_softc *, uint32_t, int);
118fb172c8aSjmcneill 
119fb172c8aSjmcneill static void	meson_sdhc_dmainit(struct meson_sdhc_softc *);
120fb172c8aSjmcneill 
121fb172c8aSjmcneill static struct sdmmc_chip_functions meson_sdhc_chip_functions = {
122fb172c8aSjmcneill 	.host_reset = meson_sdhc_host_reset,
123fb172c8aSjmcneill 	.host_ocr = meson_sdhc_host_ocr,
124fb172c8aSjmcneill 	.host_maxblklen = meson_sdhc_host_maxblklen,
125fb172c8aSjmcneill 	.card_detect = meson_sdhc_card_detect,
126fb172c8aSjmcneill 	.write_protect = meson_sdhc_write_protect,
127fb172c8aSjmcneill 	.bus_power = meson_sdhc_bus_power,
128fb172c8aSjmcneill 	.bus_clock = meson_sdhc_bus_clock,
129fb172c8aSjmcneill 	.bus_width = meson_sdhc_bus_width,
130fb172c8aSjmcneill 	.bus_rod = meson_sdhc_bus_rod,
131fb172c8aSjmcneill 	.exec_command = meson_sdhc_exec_command,
132fb172c8aSjmcneill 	.card_enable_intr = meson_sdhc_card_enable_intr,
133fb172c8aSjmcneill 	.card_intr_ack = meson_sdhc_card_intr_ack,
134fb172c8aSjmcneill 	.signal_voltage = meson_sdhc_signal_voltage,
135fb172c8aSjmcneill 	.execute_tuning = meson_sdhc_execute_tuning,
136fb172c8aSjmcneill };
137fb172c8aSjmcneill 
138fb172c8aSjmcneill #define SDHC_WRITE(sc, reg, val) \
139fb172c8aSjmcneill 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
140fb172c8aSjmcneill #define SDHC_READ(sc, reg) \
141fb172c8aSjmcneill 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
142fb172c8aSjmcneill #define	SDHC_SET_CLEAR meson_sdhc_set_clear
143fb172c8aSjmcneill 
144fb172c8aSjmcneill static inline void
meson_sdhc_set_clear(struct meson_sdhc_softc * sc,bus_addr_t reg,uint32_t set,uint32_t clr)145fb172c8aSjmcneill meson_sdhc_set_clear(struct meson_sdhc_softc *sc, bus_addr_t reg, uint32_t set, uint32_t clr)
146fb172c8aSjmcneill {
147fb172c8aSjmcneill 	const uint32_t old = SDHC_READ(sc, reg);
148fb172c8aSjmcneill 	const uint32_t new = set | (old & ~clr);
149fb172c8aSjmcneill 	if (old != new)
150fb172c8aSjmcneill 		SDHC_WRITE(sc, reg, new);
151fb172c8aSjmcneill }
152fb172c8aSjmcneill 
1536e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
154*c34066c2Sjmcneill 	{ .compat = "amlogic,meson8-sdhc" },
155*c34066c2Sjmcneill 	{ .compat = "amlogic,meson8b-sdhc" },	/* DTCOMPAT */
1566e54367aSthorpej 	DEVICE_COMPAT_EOL
157fb172c8aSjmcneill };
158fb172c8aSjmcneill 
1596e54367aSthorpej static const struct device_compatible_entry slot_compat_data[] = {
1606e54367aSthorpej 	{ .compat = "mmc-slot" },
1616e54367aSthorpej 	DEVICE_COMPAT_EOL
162fb172c8aSjmcneill };
163fb172c8aSjmcneill 
164fb172c8aSjmcneill static int
meson_sdhc_match(device_t parent,cfdata_t cf,void * aux)165fb172c8aSjmcneill meson_sdhc_match(device_t parent, cfdata_t cf, void *aux)
166fb172c8aSjmcneill {
167fb172c8aSjmcneill 	struct fdt_attach_args * const faa = aux;
168fb172c8aSjmcneill 
1696e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
170fb172c8aSjmcneill }
171fb172c8aSjmcneill 
172fb172c8aSjmcneill static void
meson_sdhc_attach(device_t parent,device_t self,void * aux)173fb172c8aSjmcneill meson_sdhc_attach(device_t parent, device_t self, void *aux)
174fb172c8aSjmcneill {
175fb172c8aSjmcneill 	struct meson_sdhc_softc * const sc = device_private(self);
176fb172c8aSjmcneill 	struct fdt_attach_args * const faa = aux;
177fb172c8aSjmcneill 	const int phandle = faa->faa_phandle;
178fb172c8aSjmcneill 	char intrstr[128];
179fb172c8aSjmcneill 	struct clk *clk_clkin, *clk_core;
180fb172c8aSjmcneill 	bus_addr_t addr, port;
181fb172c8aSjmcneill 	bus_size_t size;
182fb172c8aSjmcneill 	int child;
183fb172c8aSjmcneill 
184fb172c8aSjmcneill 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
185fb172c8aSjmcneill 		aprint_error(": couldn't get registers\n");
186fb172c8aSjmcneill 		return;
187fb172c8aSjmcneill 	}
188fb172c8aSjmcneill 
189fb172c8aSjmcneill 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
190fb172c8aSjmcneill 		aprint_error(": failed to decode interrupt\n");
191fb172c8aSjmcneill 		return;
192fb172c8aSjmcneill 	}
193fb172c8aSjmcneill 
194fb172c8aSjmcneill 	clk_core = fdtbus_clock_get(phandle, "core");
195*c34066c2Sjmcneill 	if (clk_core == NULL) {
196*c34066c2Sjmcneill 		clk_core = fdtbus_clock_get(phandle, "pclk");
197*c34066c2Sjmcneill 	}
198fb172c8aSjmcneill 	if (clk_core == NULL || clk_enable(clk_core) != 0) {
199*c34066c2Sjmcneill 		aprint_error(": failed to enable core/pclk clock\n");
200fb172c8aSjmcneill 		return;
201fb172c8aSjmcneill 	}
202fb172c8aSjmcneill 
203fb172c8aSjmcneill 	clk_clkin = fdtbus_clock_get(phandle, "clkin");
204*c34066c2Sjmcneill 	if (clk_clkin == NULL) {
205*c34066c2Sjmcneill 		clk_clkin = fdtbus_clock_get(phandle, "clkin2");
206*c34066c2Sjmcneill 	}
207fb172c8aSjmcneill 	if (clk_clkin == NULL || clk_enable(clk_clkin) != 0) {
208*c34066c2Sjmcneill 		aprint_error(": failed to get clkin/clkin2 clock\n");
209fb172c8aSjmcneill 		return;
210fb172c8aSjmcneill 	}
211fb172c8aSjmcneill 
212fb172c8aSjmcneill 	sc->sc_dev = self;
213fb172c8aSjmcneill 	sc->sc_bst = faa->faa_bst;
214fb172c8aSjmcneill 	sc->sc_dmat = faa->faa_dmat;
215fb172c8aSjmcneill 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
216fb172c8aSjmcneill 		aprint_error(": failed to map registers\n");
217fb172c8aSjmcneill 		return;
218fb172c8aSjmcneill 	}
219fb172c8aSjmcneill 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO);
220fb172c8aSjmcneill 	cv_init(&sc->sc_intr_cv, "sdhcintr");
221fb172c8aSjmcneill 	sc->sc_signal_voltage = SDMMC_SIGNAL_VOLTAGE_330;
222fb172c8aSjmcneill 
223fb172c8aSjmcneill 	sc->sc_port = -1;
224fb172c8aSjmcneill 	for (child = OF_child(phandle); child; child = OF_peer(child))
2256e54367aSthorpej 		if (of_compatible_match(child, slot_compat_data)) {
226fb172c8aSjmcneill 			if (fdtbus_get_reg(child, 0, &port, NULL) == 0) {
227fb172c8aSjmcneill 				sc->sc_slot_phandle = child;
228fb172c8aSjmcneill 				sc->sc_port = port;
229fb172c8aSjmcneill 			}
230fb172c8aSjmcneill 			break;
231fb172c8aSjmcneill 		}
232fb172c8aSjmcneill 	if (sc->sc_port == -1) {
233fb172c8aSjmcneill 		aprint_error(": couldn't get mmc slot\n");
234fb172c8aSjmcneill 		return;
235fb172c8aSjmcneill 	}
236fb172c8aSjmcneill 
237fb172c8aSjmcneill 	aprint_naive("\n");
238fb172c8aSjmcneill 	aprint_normal(": SDHC controller (port %c)\n", sc->sc_port + 'A');
239fb172c8aSjmcneill 
240fb172c8aSjmcneill 	sc->sc_reg_vmmc = fdtbus_regulator_acquire(sc->sc_slot_phandle, "vmmc-supply");
241fb172c8aSjmcneill 	sc->sc_reg_vqmmc = fdtbus_regulator_acquire(sc->sc_slot_phandle, "vqmmc-supply");
242fb172c8aSjmcneill 
243fb172c8aSjmcneill 	sc->sc_gpio_cd = fdtbus_gpio_acquire(sc->sc_slot_phandle, "cd-gpios",
244fb172c8aSjmcneill 	    GPIO_PIN_INPUT);
245fb172c8aSjmcneill 	sc->sc_gpio_wp = fdtbus_gpio_acquire(sc->sc_slot_phandle, "wp-gpios",
246fb172c8aSjmcneill 	    GPIO_PIN_INPUT);
247fb172c8aSjmcneill 
248fb172c8aSjmcneill 	sc->sc_gpio_cd_inverted = of_hasprop(sc->sc_slot_phandle, "cd-inverted");
249fb172c8aSjmcneill 	sc->sc_gpio_wp_inverted = of_hasprop(sc->sc_slot_phandle, "wp-inverted");
250fb172c8aSjmcneill 
251fb172c8aSjmcneill 	sc->sc_non_removable = of_hasprop(sc->sc_slot_phandle, "non-removable");
252fb172c8aSjmcneill 	sc->sc_broken_cd = of_hasprop(sc->sc_slot_phandle, "broken-cd");
253fb172c8aSjmcneill 
25464e248edSryo 	sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_BIO, 0,
25564e248edSryo 	    meson_sdhc_intr, sc, device_xname(self));
256fb172c8aSjmcneill 	if (sc->sc_ih == NULL) {
257fb172c8aSjmcneill 		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
258fb172c8aSjmcneill 		    intrstr);
259fb172c8aSjmcneill 		return;
260fb172c8aSjmcneill 	}
261fb172c8aSjmcneill 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
262fb172c8aSjmcneill 
263fb172c8aSjmcneill 	sc->sc_bus_freq = clk_get_rate(clk_clkin);
264fb172c8aSjmcneill 
265fb172c8aSjmcneill 	aprint_normal_dev(self, "core %u Hz, clkin %u Hz\n", clk_get_rate(clk_core), clk_get_rate(clk_clkin));
266fb172c8aSjmcneill 
267fb172c8aSjmcneill 	meson_sdhc_dmainit(sc);
268fb172c8aSjmcneill 
269fb172c8aSjmcneill 	config_interrupts(self, meson_sdhc_attach_i);
270fb172c8aSjmcneill }
271fb172c8aSjmcneill 
272fb172c8aSjmcneill static void
meson_sdhc_attach_i(device_t self)273fb172c8aSjmcneill meson_sdhc_attach_i(device_t self)
274fb172c8aSjmcneill {
275fb172c8aSjmcneill 	struct meson_sdhc_softc *sc = device_private(self);
276fb172c8aSjmcneill 	struct sdmmcbus_attach_args saa;
277fb172c8aSjmcneill 	u_int pll_freq;
278fb172c8aSjmcneill 
279fb172c8aSjmcneill 	pll_freq = sc->sc_bus_freq / 1000;
280fb172c8aSjmcneill 
281fb172c8aSjmcneill 	meson_sdhc_host_reset(sc);
282fb172c8aSjmcneill 	meson_sdhc_bus_width(sc, 1);
283fb172c8aSjmcneill 
284fb172c8aSjmcneill 	memset(&saa, 0, sizeof(saa));
285fb172c8aSjmcneill 	saa.saa_busname = "sdmmc";
286fb172c8aSjmcneill 	saa.saa_sct = &meson_sdhc_chip_functions;
287fb172c8aSjmcneill 	saa.saa_dmat = sc->sc_dmat;
288fb172c8aSjmcneill 	saa.saa_sch = sc;
289fb172c8aSjmcneill 	saa.saa_clkmin = 400;
290fb172c8aSjmcneill 	saa.saa_clkmax = pll_freq;
291fb172c8aSjmcneill 	/* Do not advertise DMA capabilities, we handle DMA ourselves */
292fb172c8aSjmcneill 	saa.saa_caps = SMC_CAPS_4BIT_MODE|
293fb172c8aSjmcneill 		       SMC_CAPS_SD_HIGHSPEED|
294fb172c8aSjmcneill 		       SMC_CAPS_MMC_HIGHSPEED|
295fb172c8aSjmcneill 		       SMC_CAPS_UHS_SDR50|
296fb172c8aSjmcneill 		       SMC_CAPS_UHS_SDR104|
297fb172c8aSjmcneill 		       SMC_CAPS_AUTO_STOP;
298fb172c8aSjmcneill 
299fb172c8aSjmcneill 	if (sc->sc_port == SDHC_PORT_C) {
300fb172c8aSjmcneill 		saa.saa_caps |= SMC_CAPS_MMC_HS200;
301fb172c8aSjmcneill 		saa.saa_caps |= SMC_CAPS_8BIT_MODE;
302fb172c8aSjmcneill 	}
303fb172c8aSjmcneill 
304c7fb772bSthorpej 	sc->sc_sdmmc_dev = config_found(self, &saa, NULL, CFARGS_NONE);
305fb172c8aSjmcneill }
306fb172c8aSjmcneill 
307fb172c8aSjmcneill static int
meson_sdhc_intr(void * priv)308fb172c8aSjmcneill meson_sdhc_intr(void *priv)
309fb172c8aSjmcneill {
310fb172c8aSjmcneill 	struct meson_sdhc_softc *sc = priv;
311fb172c8aSjmcneill 	uint32_t ista;
312fb172c8aSjmcneill 
313fb172c8aSjmcneill 	mutex_enter(&sc->sc_intr_lock);
314fb172c8aSjmcneill 	ista = SDHC_READ(sc, SD_ISTA_REG);
315fb172c8aSjmcneill 
316fb172c8aSjmcneill 	if (!ista) {
317fb172c8aSjmcneill 		mutex_exit(&sc->sc_intr_lock);
318fb172c8aSjmcneill 		return 0;
319fb172c8aSjmcneill 	}
320fb172c8aSjmcneill 
321fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_ISTA_REG, ista);
322fb172c8aSjmcneill 
323fb172c8aSjmcneill 	sc->sc_intr_ista |= ista;
324fb172c8aSjmcneill 	cv_broadcast(&sc->sc_intr_cv);
325fb172c8aSjmcneill 
326fb172c8aSjmcneill 	mutex_exit(&sc->sc_intr_lock);
327fb172c8aSjmcneill 
328fb172c8aSjmcneill 	return 1;
329fb172c8aSjmcneill }
330fb172c8aSjmcneill 
331fb172c8aSjmcneill static void
meson_sdhc_dmainit(struct meson_sdhc_softc * sc)332fb172c8aSjmcneill meson_sdhc_dmainit(struct meson_sdhc_softc *sc)
333fb172c8aSjmcneill {
334fb172c8aSjmcneill 	int error, rseg;
335fb172c8aSjmcneill 
336fb172c8aSjmcneill 	error = bus_dmamem_alloc(sc->sc_dmat, MAXPHYS, PAGE_SIZE, MAXPHYS,
337fb172c8aSjmcneill 	    sc->sc_segs, 1, &rseg, BUS_DMA_WAITOK);
338fb172c8aSjmcneill 	if (error) {
339fb172c8aSjmcneill 		device_printf(sc->sc_dev, "bus_dmamem_alloc failed: %d\n", error);
340fb172c8aSjmcneill 		return;
341fb172c8aSjmcneill 	}
342fb172c8aSjmcneill 	KASSERT(rseg == 1);
343fb172c8aSjmcneill 
344fb172c8aSjmcneill 	error = bus_dmamem_map(sc->sc_dmat, sc->sc_segs, rseg, MAXPHYS,
345fb172c8aSjmcneill 	    &sc->sc_bbuf, BUS_DMA_WAITOK);
346fb172c8aSjmcneill 	if (error) {
347fb172c8aSjmcneill 		device_printf(sc->sc_dev, "bus_dmamem_map failed\n");
348fb172c8aSjmcneill 		return;
349fb172c8aSjmcneill 	}
350fb172c8aSjmcneill 
351fb172c8aSjmcneill 	error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, 1, MAXPHYS, 0,
352fb172c8aSjmcneill 	    BUS_DMA_WAITOK, &sc->sc_dmamap);
353fb172c8aSjmcneill 	if (error) {
354fb172c8aSjmcneill 		device_printf(sc->sc_dev, "bus_dmamap_create failed\n");
355fb172c8aSjmcneill 		return;
356fb172c8aSjmcneill 	}
357fb172c8aSjmcneill 
358fb172c8aSjmcneill }
359fb172c8aSjmcneill 
360fb172c8aSjmcneill static int
meson_sdhc_default_rx_phase(struct meson_sdhc_softc * sc)361fb172c8aSjmcneill meson_sdhc_default_rx_phase(struct meson_sdhc_softc *sc)
362fb172c8aSjmcneill {
363fb172c8aSjmcneill 	const u_int pll_freq = sc->sc_bus_freq / 1000;
364fb172c8aSjmcneill 	const u_int clkc = SDHC_READ(sc, SD_CLKC_REG);
365fb172c8aSjmcneill 	const u_int clk_div = __SHIFTOUT(clkc, SD_CLKC_CLK_DIV);
366fb172c8aSjmcneill 	const u_int act_freq = pll_freq / clk_div;
367fb172c8aSjmcneill 
368fb172c8aSjmcneill 	if (act_freq > 90000) {
369fb172c8aSjmcneill 		return 1;
370fb172c8aSjmcneill 	} else if (act_freq > 45000) {
371fb172c8aSjmcneill 		if (sc->sc_signal_voltage == SDMMC_SIGNAL_VOLTAGE_330) {
372fb172c8aSjmcneill 			return 15;
373fb172c8aSjmcneill 		} else {
374fb172c8aSjmcneill 			return 11;
375fb172c8aSjmcneill 		}
376fb172c8aSjmcneill 	} else if (act_freq >= 25000) {
377fb172c8aSjmcneill 		return 15;
378fb172c8aSjmcneill 	} else if (act_freq > 5000) {
379fb172c8aSjmcneill 		return 23;
380fb172c8aSjmcneill 	} else if (act_freq > 1000) {
381fb172c8aSjmcneill 		return 55;
382fb172c8aSjmcneill 	} else {
383fb172c8aSjmcneill 		return 1061;
384fb172c8aSjmcneill 	}
385fb172c8aSjmcneill }
386fb172c8aSjmcneill 
387fb172c8aSjmcneill static int
meson_sdhc_set_clock(struct meson_sdhc_softc * sc,u_int freq)388fb172c8aSjmcneill meson_sdhc_set_clock(struct meson_sdhc_softc *sc, u_int freq)
389fb172c8aSjmcneill {
390fb172c8aSjmcneill 	uint32_t clkc;
391fb172c8aSjmcneill 	uint32_t clk2;
392fb172c8aSjmcneill 	u_int pll_freq, clk_div;
393fb172c8aSjmcneill 
394fb172c8aSjmcneill 	clkc = SDHC_READ(sc, SD_CLKC_REG);
395fb172c8aSjmcneill 	clkc &= ~SD_CLKC_TX_CLK_ENABLE;
396fb172c8aSjmcneill 	clkc &= ~SD_CLKC_RX_CLK_ENABLE;
397fb172c8aSjmcneill 	clkc &= ~SD_CLKC_SD_CLK_ENABLE;
398fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_CLKC_REG, clkc);
399fb172c8aSjmcneill 	clkc &= ~SD_CLKC_MOD_CLK_ENABLE;
400fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_CLKC_REG, clkc);
401fb172c8aSjmcneill 
402fb172c8aSjmcneill 	if (freq == 0)
403fb172c8aSjmcneill 		return 0;
404fb172c8aSjmcneill 
405fb172c8aSjmcneill 	clkc &= ~SD_CLKC_CLK_DIV;
406fb172c8aSjmcneill 	clkc &= ~SD_CLKC_CLK_IN_SEL;
407fb172c8aSjmcneill 
408fb172c8aSjmcneill 	clkc |= __SHIFTIN(SD_CLKC_CLK_IN_SEL_FCLK_DIV3,
409fb172c8aSjmcneill 			  SD_CLKC_CLK_IN_SEL);
410fb172c8aSjmcneill 
411fb172c8aSjmcneill 	pll_freq = sc->sc_bus_freq / 1000;	/* 2.55GHz */
412fb172c8aSjmcneill 	clk_div = howmany(pll_freq, freq);
413fb172c8aSjmcneill 
414fb172c8aSjmcneill 	clkc |= __SHIFTIN(clk_div - 1, SD_CLKC_CLK_DIV);
415fb172c8aSjmcneill 
416fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_CLKC_REG, clkc);
417fb172c8aSjmcneill 
418fb172c8aSjmcneill 	clkc |= SD_CLKC_MOD_CLK_ENABLE;
419fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_CLKC_REG, clkc);
420fb172c8aSjmcneill 
421fb172c8aSjmcneill 	clkc |= SD_CLKC_TX_CLK_ENABLE;
422fb172c8aSjmcneill 	clkc |= SD_CLKC_RX_CLK_ENABLE;
423fb172c8aSjmcneill 	clkc |= SD_CLKC_SD_CLK_ENABLE;
424fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_CLKC_REG, clkc);
425fb172c8aSjmcneill 
426fb172c8aSjmcneill 	clk2 = SDHC_READ(sc, SD_CLK2_REG);
427fb172c8aSjmcneill 	clk2 &= ~SD_CLK2_SD_CLK_PHASE;
428fb172c8aSjmcneill 	clk2 |= __SHIFTIN(1, SD_CLK2_SD_CLK_PHASE);
429fb172c8aSjmcneill 	clk2 &= ~SD_CLK2_RX_CLK_PHASE;
430fb172c8aSjmcneill 	clk2 |= __SHIFTIN(meson_sdhc_default_rx_phase(sc),
431fb172c8aSjmcneill 			  SD_CLK2_RX_CLK_PHASE);
432fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_CLK2_REG, clk2);
433fb172c8aSjmcneill 
434fb172c8aSjmcneill 	return 0;
435fb172c8aSjmcneill }
436fb172c8aSjmcneill 
437fb172c8aSjmcneill static int
meson_sdhc_wait_idle(struct meson_sdhc_softc * sc)438fb172c8aSjmcneill meson_sdhc_wait_idle(struct meson_sdhc_softc *sc)
439fb172c8aSjmcneill {
440fb172c8aSjmcneill 	int i;
441fb172c8aSjmcneill 
442fb172c8aSjmcneill 	for (i = 0; i < 1000000; i++) {
443fb172c8aSjmcneill 		const uint32_t stat = SDHC_READ(sc, SD_STAT_REG);
444fb172c8aSjmcneill 		const uint32_t esta = SDHC_READ(sc, SD_ESTA_REG);
445fb172c8aSjmcneill 		if ((stat & SD_STAT_BUSY) == 0 &&
446fb172c8aSjmcneill 		    (esta & SD_ESTA_BUSY) == 0)
447fb172c8aSjmcneill 			return 0;
448fb172c8aSjmcneill 		delay(1);
449fb172c8aSjmcneill 	}
450fb172c8aSjmcneill 
451fb172c8aSjmcneill 	return EBUSY;
452fb172c8aSjmcneill }
453fb172c8aSjmcneill 
454fb172c8aSjmcneill static int
meson_sdhc_wait_ista(struct meson_sdhc_softc * sc,uint32_t mask,int timeout)455fb172c8aSjmcneill meson_sdhc_wait_ista(struct meson_sdhc_softc *sc, uint32_t mask, int timeout)
456fb172c8aSjmcneill {
457fb172c8aSjmcneill 	int retry, error;
458fb172c8aSjmcneill 
459fb172c8aSjmcneill 	KASSERT(mutex_owned(&sc->sc_intr_lock));
460fb172c8aSjmcneill 
461fb172c8aSjmcneill 	if (sc->sc_intr_ista & mask)
462fb172c8aSjmcneill 		return 0;
463fb172c8aSjmcneill 
464fb172c8aSjmcneill 	retry = timeout / hz;
465fb172c8aSjmcneill 
466fb172c8aSjmcneill 	while (retry > 0) {
467fb172c8aSjmcneill 		error = cv_timedwait(&sc->sc_intr_cv, &sc->sc_intr_lock, hz);
468fb172c8aSjmcneill 		if (error && error != EWOULDBLOCK)
469fb172c8aSjmcneill 			return error;
470fb172c8aSjmcneill 		if (sc->sc_intr_ista & mask)
471fb172c8aSjmcneill 			return 0;
472fb172c8aSjmcneill 		--retry;
473fb172c8aSjmcneill 	}
474fb172c8aSjmcneill 
475fb172c8aSjmcneill 	return ETIMEDOUT;
476fb172c8aSjmcneill }
477fb172c8aSjmcneill 
478fb172c8aSjmcneill static int
meson_sdhc_host_reset(sdmmc_chipset_handle_t sch)479fb172c8aSjmcneill meson_sdhc_host_reset(sdmmc_chipset_handle_t sch)
480fb172c8aSjmcneill {
481fb172c8aSjmcneill 	struct meson_sdhc_softc *sc = sch;
482fb172c8aSjmcneill 	uint32_t enhc;
483fb172c8aSjmcneill 
484fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_SRST_REG,
485fb172c8aSjmcneill 	    SD_SRST_MAIN_CTRL | SD_SRST_TX_FIFO | SD_SRST_RX_FIFO |
486fb172c8aSjmcneill 	    SD_SRST_DPHY_TX | SD_SRST_DPHY_RX | SD_SRST_DMA_IF);
487fb172c8aSjmcneill 
488fb172c8aSjmcneill 	delay(50);
489fb172c8aSjmcneill 
490fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_SRST_REG, 0);
491fb172c8aSjmcneill 
492fb172c8aSjmcneill 	delay(10);
493fb172c8aSjmcneill 
494fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_CNTL_REG,
495fb172c8aSjmcneill 	    __SHIFTIN(0x7, SD_CNTL_TX_ENDIAN_CTRL) |
496fb172c8aSjmcneill 	    __SHIFTIN(0x7, SD_CNTL_RX_ENDIAN_CTRL) |
497fb172c8aSjmcneill 	    __SHIFTIN(0xf, SD_CNTL_RX_PERIOD) |
498fb172c8aSjmcneill 	    __SHIFTIN(0x7f, SD_CNTL_RX_TIMEOUT));
499fb172c8aSjmcneill 
500fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_CLKC_REG,
501fb172c8aSjmcneill 	    SDHC_READ(sc, SD_CLKC_REG) & ~SD_CLKC_MEM_PWR);
502fb172c8aSjmcneill 
503fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_PDMA_REG,
504fb172c8aSjmcneill 	    __SHIFTIN(7, SD_PDMA_TX_BURST_LEN) |
505fb172c8aSjmcneill 	    __SHIFTIN(49, SD_PDMA_TXFIFO_THRESHOLD) |
506fb172c8aSjmcneill 	    __SHIFTIN(15, SD_PDMA_RX_BURST_LEN) |
507fb172c8aSjmcneill 	    __SHIFTIN(7, SD_PDMA_RXFIFO_THRESHOLD) |
508fb172c8aSjmcneill 	    SD_PDMA_DMA_URGENT);
509fb172c8aSjmcneill 
510fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_MISC_REG,
511fb172c8aSjmcneill 	    __SHIFTIN(7, SD_MISC_TXSTART_THRESHOLD) |
512fb172c8aSjmcneill 	    __SHIFTIN(5, SD_MISC_WCRC_ERR_PATTERN) |
513fb172c8aSjmcneill 	    __SHIFTIN(2, SD_MISC_WCRC_OK_PATTERN));
514fb172c8aSjmcneill 
515fb172c8aSjmcneill 	enhc = SDHC_READ(sc, SD_ENHC_REG);
516fb172c8aSjmcneill 	enhc &= ~SD_ENHC_RXFIFO_THRESHOLD;
517fb172c8aSjmcneill 	enhc |= __SHIFTIN(63, SD_ENHC_RXFIFO_THRESHOLD);
518fb172c8aSjmcneill 	enhc &= ~SD_ENHC_DMA_RX_RESP;
519fb172c8aSjmcneill 	enhc |= SD_ENHC_DMA_TX_RESP;
520fb172c8aSjmcneill 	enhc &= ~SD_ENHC_SDIO_IRQ_PERIOD;
521fb172c8aSjmcneill 	enhc |= __SHIFTIN(12, SD_ENHC_SDIO_IRQ_PERIOD);
522fb172c8aSjmcneill 	enhc &= ~SD_ENHC_RX_TIMEOUT;
523fb172c8aSjmcneill 	enhc |= __SHIFTIN(0xff, SD_ENHC_RX_TIMEOUT);
524fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_ENHC_REG, enhc);
525fb172c8aSjmcneill 
526fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_ICTL_REG, 0);
527fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_ISTA_REG, SD_INT_CLEAR);
528fb172c8aSjmcneill 
529fb172c8aSjmcneill 	return 0;
530fb172c8aSjmcneill }
531fb172c8aSjmcneill 
532fb172c8aSjmcneill static uint32_t
meson_sdhc_host_ocr(sdmmc_chipset_handle_t sch)533fb172c8aSjmcneill meson_sdhc_host_ocr(sdmmc_chipset_handle_t sch)
534fb172c8aSjmcneill {
535fb172c8aSjmcneill 	return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V |
536fb172c8aSjmcneill 	       MMC_OCR_HCS | MMC_OCR_S18A;
537fb172c8aSjmcneill }
538fb172c8aSjmcneill 
539fb172c8aSjmcneill static int
meson_sdhc_host_maxblklen(sdmmc_chipset_handle_t sch)540fb172c8aSjmcneill meson_sdhc_host_maxblklen(sdmmc_chipset_handle_t sch)
541fb172c8aSjmcneill {
542fb172c8aSjmcneill 	return 512;
543fb172c8aSjmcneill }
544fb172c8aSjmcneill 
545fb172c8aSjmcneill static int
meson_sdhc_card_detect(sdmmc_chipset_handle_t sch)546fb172c8aSjmcneill meson_sdhc_card_detect(sdmmc_chipset_handle_t sch)
547fb172c8aSjmcneill {
548fb172c8aSjmcneill 	struct meson_sdhc_softc *sc = sch;
549fb172c8aSjmcneill 	int val;
550fb172c8aSjmcneill 
551fb172c8aSjmcneill 	if (sc->sc_non_removable || sc->sc_broken_cd) {
552fb172c8aSjmcneill 		return 1;
553fb172c8aSjmcneill 	} else if (sc->sc_gpio_cd != NULL) {
554fb172c8aSjmcneill 		val = fdtbus_gpio_read(sc->sc_gpio_cd);
555fb172c8aSjmcneill 		if (sc->sc_gpio_cd_inverted)
556fb172c8aSjmcneill 			val = !val;
557fb172c8aSjmcneill 		return val;
558fb172c8aSjmcneill 	} else {
559fb172c8aSjmcneill 		return 1;
560fb172c8aSjmcneill 	}
561fb172c8aSjmcneill }
562fb172c8aSjmcneill 
563fb172c8aSjmcneill static int
meson_sdhc_write_protect(sdmmc_chipset_handle_t sch)564fb172c8aSjmcneill meson_sdhc_write_protect(sdmmc_chipset_handle_t sch)
565fb172c8aSjmcneill {
566fb172c8aSjmcneill 	struct meson_sdhc_softc *sc = sch;
567fb172c8aSjmcneill 	int val;
568fb172c8aSjmcneill 
569fb172c8aSjmcneill 	if (sc->sc_gpio_wp != NULL) {
570fb172c8aSjmcneill 		val = fdtbus_gpio_read(sc->sc_gpio_wp);
571fb172c8aSjmcneill 		if (sc->sc_gpio_wp_inverted)
572fb172c8aSjmcneill 			val = !val;
573fb172c8aSjmcneill 		return val;
574fb172c8aSjmcneill 	}
575fb172c8aSjmcneill 
576fb172c8aSjmcneill 	return 0;
577fb172c8aSjmcneill }
578fb172c8aSjmcneill 
579fb172c8aSjmcneill static int
meson_sdhc_bus_power(sdmmc_chipset_handle_t sch,uint32_t ocr)580fb172c8aSjmcneill meson_sdhc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
581fb172c8aSjmcneill {
582fb172c8aSjmcneill 	return 0;
583fb172c8aSjmcneill }
584fb172c8aSjmcneill 
585fb172c8aSjmcneill static int
meson_sdhc_bus_clock(sdmmc_chipset_handle_t sch,int freq)586fb172c8aSjmcneill meson_sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
587fb172c8aSjmcneill {
588fb172c8aSjmcneill 	struct meson_sdhc_softc *sc = sch;
589fb172c8aSjmcneill 
590fb172c8aSjmcneill 	return meson_sdhc_set_clock(sc, freq);
591fb172c8aSjmcneill }
592fb172c8aSjmcneill 
593fb172c8aSjmcneill static int
meson_sdhc_bus_width(sdmmc_chipset_handle_t sch,int width)594fb172c8aSjmcneill meson_sdhc_bus_width(sdmmc_chipset_handle_t sch, int width)
595fb172c8aSjmcneill {
596fb172c8aSjmcneill 	struct meson_sdhc_softc *sc = sch;
597fb172c8aSjmcneill 	uint32_t cntl;
598fb172c8aSjmcneill 
599fb172c8aSjmcneill 	cntl = SDHC_READ(sc, SD_CNTL_REG);
600fb172c8aSjmcneill 	cntl &= ~SD_CNTL_DAT_TYPE;
601fb172c8aSjmcneill 	switch (width) {
602fb172c8aSjmcneill 	case 1:
603fb172c8aSjmcneill 		cntl |= __SHIFTIN(0, SD_CNTL_DAT_TYPE);
604fb172c8aSjmcneill 		break;
605fb172c8aSjmcneill 	case 4:
606fb172c8aSjmcneill 		cntl |= __SHIFTIN(1, SD_CNTL_DAT_TYPE);
607fb172c8aSjmcneill 		break;
608fb172c8aSjmcneill 	case 8:
609fb172c8aSjmcneill 		cntl |= __SHIFTIN(2, SD_CNTL_DAT_TYPE);
610fb172c8aSjmcneill 		break;
611fb172c8aSjmcneill 	default:
612fb172c8aSjmcneill 		return EINVAL;
613fb172c8aSjmcneill 	}
614fb172c8aSjmcneill 
615fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_CNTL_REG, cntl);
616fb172c8aSjmcneill 
617fb172c8aSjmcneill 	return 0;
618fb172c8aSjmcneill }
619fb172c8aSjmcneill 
620fb172c8aSjmcneill static int
meson_sdhc_bus_rod(sdmmc_chipset_handle_t sch,int on)621fb172c8aSjmcneill meson_sdhc_bus_rod(sdmmc_chipset_handle_t sch, int on)
622fb172c8aSjmcneill {
623fb172c8aSjmcneill 	return ENOTSUP;
624fb172c8aSjmcneill }
625fb172c8aSjmcneill 
626fb172c8aSjmcneill static void
meson_sdhc_exec_command(sdmmc_chipset_handle_t sch,struct sdmmc_command * cmd)627fb172c8aSjmcneill meson_sdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
628fb172c8aSjmcneill {
629fb172c8aSjmcneill 	struct meson_sdhc_softc *sc = sch;
630fb172c8aSjmcneill 	uint32_t cmdval = 0, cntl, srst, pdma, ictl;
631fb172c8aSjmcneill 	bool use_bbuf = false;
632fb172c8aSjmcneill 	int i;
633fb172c8aSjmcneill 
634fb172c8aSjmcneill 	KASSERT(cmd->c_blklen <= 512);
635fb172c8aSjmcneill 
636fb172c8aSjmcneill 	mutex_enter(&sc->sc_intr_lock);
637fb172c8aSjmcneill 
638fb172c8aSjmcneill 	/* Filter SDIO commands */
639fb172c8aSjmcneill 	switch (cmd->c_opcode) {
640fb172c8aSjmcneill 	case SD_IO_SEND_OP_COND:
641fb172c8aSjmcneill 	case SD_IO_RW_DIRECT:
642fb172c8aSjmcneill 	case SD_IO_RW_EXTENDED:
643fb172c8aSjmcneill 		cmd->c_error = EINVAL;
644fb172c8aSjmcneill 		goto done;
645fb172c8aSjmcneill 	}
646fb172c8aSjmcneill 
647fb172c8aSjmcneill 	if (cmd->c_opcode == MMC_STOP_TRANSMISSION)
648fb172c8aSjmcneill 		cmdval |= SD_SEND_DATA_STOP;
649fb172c8aSjmcneill 	if (cmd->c_flags & SCF_RSP_PRESENT)
650fb172c8aSjmcneill 		cmdval |= SD_SEND_COMMAND_HAS_RESP;
651fb172c8aSjmcneill 	if (cmd->c_flags & SCF_RSP_136) {
652fb172c8aSjmcneill 		cmdval |= SD_SEND_RESPONSE_LENGTH;
653fb172c8aSjmcneill 		cmdval |= SD_SEND_RESPONSE_NO_CRC;
654fb172c8aSjmcneill 	}
655fb172c8aSjmcneill 	if ((cmd->c_flags & SCF_RSP_CRC) == 0)
656fb172c8aSjmcneill 		cmdval |= SD_SEND_RESPONSE_NO_CRC;
657fb172c8aSjmcneill 
658fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_ICTL_REG, 0);
659fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_ISTA_REG, SD_INT_CLEAR);
660fb172c8aSjmcneill 	sc->sc_intr_ista = 0;
661fb172c8aSjmcneill 
662fb172c8aSjmcneill 	ictl = SD_INT_ERROR;
663fb172c8aSjmcneill 
664fb172c8aSjmcneill 	cntl = SDHC_READ(sc, SD_CNTL_REG);
665fb172c8aSjmcneill 	cntl &= ~SD_CNTL_PACK_LEN;
666fb172c8aSjmcneill 	if (cmd->c_datalen > 0) {
667fb172c8aSjmcneill 		unsigned int nblks;
668fb172c8aSjmcneill 
669fb172c8aSjmcneill 		cmdval |= SD_SEND_COMMAND_HAS_DATA;
670fb172c8aSjmcneill 		if (!ISSET(cmd->c_flags, SCF_CMD_READ)) {
671fb172c8aSjmcneill 			cmdval |= SD_SEND_DATA_DIRECTION;
672fb172c8aSjmcneill 		}
673fb172c8aSjmcneill 
674fb172c8aSjmcneill 		nblks = cmd->c_datalen / cmd->c_blklen;
675fb172c8aSjmcneill 		if (nblks == 0 || (cmd->c_datalen % cmd->c_blklen) != 0)
676fb172c8aSjmcneill 			++nblks;
677fb172c8aSjmcneill 
678fb172c8aSjmcneill 		cntl |= __SHIFTIN(cmd->c_blklen & 0x1ff, SD_CNTL_PACK_LEN);
679fb172c8aSjmcneill 
680fb172c8aSjmcneill 		cmdval |= __SHIFTIN(nblks - 1, SD_SEND_TOTAL_PACK);
681fb172c8aSjmcneill 
682fb172c8aSjmcneill 		if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
683fb172c8aSjmcneill 			ictl |= SD_INT_DATA_COMPLETE;
684fb172c8aSjmcneill 		} else {
685fb172c8aSjmcneill 			ictl |= SD_INT_DMA_DONE;
686fb172c8aSjmcneill 		}
687fb172c8aSjmcneill 	} else {
688fb172c8aSjmcneill 		ictl |= SD_INT_RESP_COMPLETE;
689fb172c8aSjmcneill 	}
690fb172c8aSjmcneill 
691fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_ICTL_REG, ictl);
692fb172c8aSjmcneill 
693fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_CNTL_REG, cntl);
694fb172c8aSjmcneill 
695fb172c8aSjmcneill 	pdma = SDHC_READ(sc, SD_PDMA_REG);
696fb172c8aSjmcneill 	if (cmd->c_datalen > 0) {
697fb172c8aSjmcneill 		pdma |= SD_PDMA_DMA_MODE;
698fb172c8aSjmcneill 	} else {
699fb172c8aSjmcneill 		pdma &= ~SD_PDMA_DMA_MODE;
700fb172c8aSjmcneill 	}
701fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_PDMA_REG, pdma);
702fb172c8aSjmcneill 
703fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_ARGU_REG, cmd->c_arg);
704fb172c8aSjmcneill 
705fb172c8aSjmcneill 	cmd->c_error = meson_sdhc_wait_idle(sc);
706fb172c8aSjmcneill 	if (cmd->c_error) {
707fb172c8aSjmcneill 		goto done;
708fb172c8aSjmcneill 	}
709fb172c8aSjmcneill 
710fb172c8aSjmcneill 	if (cmd->c_datalen > 0) {
711fb172c8aSjmcneill 		cmd->c_error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap,
712fb172c8aSjmcneill 		    sc->sc_bbuf, MAXPHYS, NULL, BUS_DMA_WAITOK);
713fb172c8aSjmcneill 		if (cmd->c_error) {
714fb172c8aSjmcneill 			device_printf(sc->sc_dev, "bus_dmamap_load failed\n");
715fb172c8aSjmcneill 			goto done;
716fb172c8aSjmcneill 		}
717fb172c8aSjmcneill 		if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
718fb172c8aSjmcneill 			bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
719fb172c8aSjmcneill 			    MAXPHYS, BUS_DMASYNC_PREREAD);
720fb172c8aSjmcneill 		} else {
721fb172c8aSjmcneill 			memcpy(sc->sc_bbuf, cmd->c_data, cmd->c_datalen);
722fb172c8aSjmcneill 			bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
723fb172c8aSjmcneill 			    MAXPHYS, BUS_DMASYNC_PREWRITE);
724fb172c8aSjmcneill 		}
725fb172c8aSjmcneill 		SDHC_WRITE(sc, SD_ADDR_REG, sc->sc_dmamap->dm_segs[0].ds_addr);
726fb172c8aSjmcneill 		use_bbuf = true;
727fb172c8aSjmcneill 	}
728fb172c8aSjmcneill 
729fb172c8aSjmcneill 	cmd->c_resid = cmd->c_datalen;
730fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_SEND_REG, cmdval | cmd->c_opcode);
731fb172c8aSjmcneill 
732fb172c8aSjmcneill 	if (cmd->c_datalen > 0) {
733fb172c8aSjmcneill 		uint32_t wbit = ISSET(cmd->c_flags, SCF_CMD_READ) ?
734fb172c8aSjmcneill 		    SD_INT_DATA_COMPLETE : SD_INT_DMA_DONE;
735fb172c8aSjmcneill 		cmd->c_error = meson_sdhc_wait_ista(sc,
736fb172c8aSjmcneill 		    SD_INT_ERROR | wbit, hz * 10);
737fb172c8aSjmcneill 		if (cmd->c_error == 0 &&
738fb172c8aSjmcneill 		    (sc->sc_intr_ista & SD_INT_ERROR)) {
739fb172c8aSjmcneill 			cmd->c_error = ETIMEDOUT;
740fb172c8aSjmcneill 		}
741fb172c8aSjmcneill 		if (cmd->c_error) {
742fb172c8aSjmcneill 			goto done;
743fb172c8aSjmcneill 		}
744fb172c8aSjmcneill 	} else {
745fb172c8aSjmcneill 		cmd->c_error = meson_sdhc_wait_ista(sc,
746fb172c8aSjmcneill 		    SD_INT_ERROR | SD_INT_RESP_COMPLETE, hz * 10);
747fb172c8aSjmcneill 		if (cmd->c_error == 0 && (sc->sc_intr_ista & SD_INT_ERROR)) {
748fb172c8aSjmcneill 			if (sc->sc_intr_ista & SD_INT_TIMEOUT) {
749fb172c8aSjmcneill 				cmd->c_error = ETIMEDOUT;
750fb172c8aSjmcneill 			} else {
751fb172c8aSjmcneill 				cmd->c_error = EIO;
752fb172c8aSjmcneill 			}
753fb172c8aSjmcneill 		}
754fb172c8aSjmcneill 		if (cmd->c_error) {
755fb172c8aSjmcneill 			goto done;
756fb172c8aSjmcneill 		}
757fb172c8aSjmcneill 	}
758fb172c8aSjmcneill 
759fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_ISTA_REG, sc->sc_intr_ista);
760fb172c8aSjmcneill 
761fb172c8aSjmcneill 	if (cmd->c_flags & SCF_RSP_PRESENT) {
762fb172c8aSjmcneill 		pdma = SDHC_READ(sc, SD_PDMA_REG);
763fb172c8aSjmcneill 		pdma &= ~SD_PDMA_DMA_MODE;
764fb172c8aSjmcneill 		if (cmd->c_flags & SCF_RSP_136) {
765fb172c8aSjmcneill 			for (i = 4; i >= 1; i--) {
766fb172c8aSjmcneill 				pdma &= ~SD_PDMA_PIO_RDRESP;
767fb172c8aSjmcneill 				pdma |= __SHIFTIN(i, SD_PDMA_PIO_RDRESP);
768fb172c8aSjmcneill 				SDHC_WRITE(sc, SD_PDMA_REG, pdma);
769fb172c8aSjmcneill 				cmd->c_resp[i - 1] = SDHC_READ(sc, SD_ARGU_REG);
770fb172c8aSjmcneill 
771fb172c8aSjmcneill 			}
772fb172c8aSjmcneill 			if (cmd->c_flags & SCF_RSP_CRC) {
773fb172c8aSjmcneill 				cmd->c_resp[0] = (cmd->c_resp[0] >> 8) |
774fb172c8aSjmcneill 				    (cmd->c_resp[1] << 24);
775fb172c8aSjmcneill 				cmd->c_resp[1] = (cmd->c_resp[1] >> 8) |
776fb172c8aSjmcneill 				    (cmd->c_resp[2] << 24);
777fb172c8aSjmcneill 				cmd->c_resp[2] = (cmd->c_resp[2] >> 8) |
778fb172c8aSjmcneill 				    (cmd->c_resp[3] << 24);
779fb172c8aSjmcneill 				cmd->c_resp[3] = (cmd->c_resp[3] >> 8);
780fb172c8aSjmcneill 			}
781fb172c8aSjmcneill 		} else {
782fb172c8aSjmcneill 			pdma &= ~SD_PDMA_PIO_RDRESP;
783fb172c8aSjmcneill 			pdma |= __SHIFTIN(0, SD_PDMA_PIO_RDRESP);
784fb172c8aSjmcneill 			SDHC_WRITE(sc, SD_PDMA_REG, pdma);
785fb172c8aSjmcneill 			cmd->c_resp[0] = SDHC_READ(sc, SD_ARGU_REG);
786fb172c8aSjmcneill 		}
787fb172c8aSjmcneill 	}
788fb172c8aSjmcneill 
789fb172c8aSjmcneill done:
790fb172c8aSjmcneill 	if (use_bbuf) {
791fb172c8aSjmcneill 		if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
792fb172c8aSjmcneill 			bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
793fb172c8aSjmcneill 			    MAXPHYS, BUS_DMASYNC_POSTREAD);
794fb172c8aSjmcneill 		} else {
795fb172c8aSjmcneill 			bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
796fb172c8aSjmcneill 			    MAXPHYS, BUS_DMASYNC_POSTWRITE);
797fb172c8aSjmcneill 		}
798fb172c8aSjmcneill 		bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap);
799fb172c8aSjmcneill 		if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
800fb172c8aSjmcneill 			memcpy(cmd->c_data, sc->sc_bbuf, cmd->c_datalen);
801fb172c8aSjmcneill 		}
802fb172c8aSjmcneill 	}
803fb172c8aSjmcneill 
804fb172c8aSjmcneill 	cmd->c_flags |= SCF_ITSDONE;
805fb172c8aSjmcneill 
806fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_ISTA_REG, SD_INT_CLEAR);
807fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_ICTL_REG, 0);
808fb172c8aSjmcneill 
809fb172c8aSjmcneill 	srst = SDHC_READ(sc, SD_SRST_REG);
810fb172c8aSjmcneill 	srst |= (SD_SRST_TX_FIFO | SD_SRST_RX_FIFO);
811fb172c8aSjmcneill 	SDHC_WRITE(sc, SD_SRST_REG, srst);
812fb172c8aSjmcneill 
813fb172c8aSjmcneill 	mutex_exit(&sc->sc_intr_lock);
814fb172c8aSjmcneill }
815fb172c8aSjmcneill 
816fb172c8aSjmcneill static void
meson_sdhc_card_enable_intr(sdmmc_chipset_handle_t sch,int enable)817fb172c8aSjmcneill meson_sdhc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable)
818fb172c8aSjmcneill {
819fb172c8aSjmcneill }
820fb172c8aSjmcneill 
821fb172c8aSjmcneill static void
meson_sdhc_card_intr_ack(sdmmc_chipset_handle_t sch)822fb172c8aSjmcneill meson_sdhc_card_intr_ack(sdmmc_chipset_handle_t sch)
823fb172c8aSjmcneill {
824fb172c8aSjmcneill }
825fb172c8aSjmcneill 
826fb172c8aSjmcneill static int
meson_sdhc_signal_voltage(sdmmc_chipset_handle_t sch,int signal_voltage)827fb172c8aSjmcneill meson_sdhc_signal_voltage(sdmmc_chipset_handle_t sch, int signal_voltage)
828fb172c8aSjmcneill {
829fb172c8aSjmcneill 	struct meson_sdhc_softc *sc = sch;
830fb172c8aSjmcneill 	u_int uvol;
831fb172c8aSjmcneill 	int error;
832fb172c8aSjmcneill 
833fb172c8aSjmcneill 	if (sc->sc_reg_vqmmc == NULL)
834fb172c8aSjmcneill 		return 0;
835fb172c8aSjmcneill 
836fb172c8aSjmcneill 	switch (signal_voltage) {
837fb172c8aSjmcneill 	case SDMMC_SIGNAL_VOLTAGE_330:
838fb172c8aSjmcneill 		uvol = 3300000;
839fb172c8aSjmcneill 		break;
840fb172c8aSjmcneill 	case SDMMC_SIGNAL_VOLTAGE_180:
841fb172c8aSjmcneill 		uvol = 1800000;
842fb172c8aSjmcneill 		break;
843fb172c8aSjmcneill 	default:
844fb172c8aSjmcneill 		return EINVAL;
845fb172c8aSjmcneill 	}
846fb172c8aSjmcneill 
847fb172c8aSjmcneill 	error = fdtbus_regulator_supports_voltage(sc->sc_reg_vqmmc, uvol, uvol);
848fb172c8aSjmcneill 	if (error != 0)
849fb172c8aSjmcneill 		return 0;
850fb172c8aSjmcneill 
851fb172c8aSjmcneill 	error = fdtbus_regulator_set_voltage(sc->sc_reg_vqmmc, uvol, uvol);
852fb172c8aSjmcneill 	if (error != 0)
853fb172c8aSjmcneill 		return error;
854fb172c8aSjmcneill 
855fb172c8aSjmcneill 	error = fdtbus_regulator_enable(sc->sc_reg_vqmmc);
856fb172c8aSjmcneill 	if (error != 0)
857fb172c8aSjmcneill 		return error;
858fb172c8aSjmcneill 
859fb172c8aSjmcneill 	sc->sc_signal_voltage = signal_voltage;
860fb172c8aSjmcneill 	return 0;
861fb172c8aSjmcneill }
862fb172c8aSjmcneill 
863fb172c8aSjmcneill static int
meson_sdhc_execute_tuning(sdmmc_chipset_handle_t sch,int timing)864fb172c8aSjmcneill meson_sdhc_execute_tuning(sdmmc_chipset_handle_t sch, int timing)
865fb172c8aSjmcneill {
866fb172c8aSjmcneill 	static const uint8_t tuning_blk_8bit[] = {
867fb172c8aSjmcneill 		0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
868fb172c8aSjmcneill 		0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
869fb172c8aSjmcneill 		0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
870fb172c8aSjmcneill 		0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
871fb172c8aSjmcneill 		0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
872fb172c8aSjmcneill 		0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
873fb172c8aSjmcneill 		0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
874fb172c8aSjmcneill 		0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
875fb172c8aSjmcneill 		0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
876fb172c8aSjmcneill 		0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
877fb172c8aSjmcneill 		0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
878fb172c8aSjmcneill 		0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
879fb172c8aSjmcneill 		0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
880fb172c8aSjmcneill 		0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
881fb172c8aSjmcneill 		0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
882fb172c8aSjmcneill 		0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
883fb172c8aSjmcneill 	};
884fb172c8aSjmcneill 	static const uint8_t tuning_blk_4bit[] = {
885fb172c8aSjmcneill 		0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
886fb172c8aSjmcneill 		0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
887fb172c8aSjmcneill 		0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
888fb172c8aSjmcneill 		0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
889fb172c8aSjmcneill 		0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
890fb172c8aSjmcneill 		0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
891fb172c8aSjmcneill 		0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
892fb172c8aSjmcneill 		0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
893fb172c8aSjmcneill 	};
894fb172c8aSjmcneill 
895fb172c8aSjmcneill 	struct meson_sdhc_softc *sc = sch;
896fb172c8aSjmcneill 	struct sdmmc_command cmd;
897fb172c8aSjmcneill 	uint8_t data[sizeof(tuning_blk_8bit)];
898fb172c8aSjmcneill 	const uint8_t *tblk;
899fb172c8aSjmcneill 	size_t tsize;
900fb172c8aSjmcneill 	struct window_s {
901fb172c8aSjmcneill 		int start;
902fb172c8aSjmcneill 		u_int size;
903fb172c8aSjmcneill 	} best = { .start = -1, .size = 0 },
904fb172c8aSjmcneill 	  curr = { .start = -1, .size = 0 },
905fb172c8aSjmcneill 	  wrap = { .start =  0, .size = 0 };
906fb172c8aSjmcneill 	u_int ph, rx_phase, clk_div;
907fb172c8aSjmcneill 	int opcode;
908fb172c8aSjmcneill 
909fb172c8aSjmcneill 	switch (timing) {
910fb172c8aSjmcneill 	case SDMMC_TIMING_MMC_HS200:
911fb172c8aSjmcneill 		tblk = tuning_blk_8bit;
912fb172c8aSjmcneill 		tsize = sizeof(tuning_blk_8bit);
913fb172c8aSjmcneill 		opcode = MMC_SEND_TUNING_BLOCK_HS200;
914fb172c8aSjmcneill 		break;
915fb172c8aSjmcneill 	case SDMMC_TIMING_UHS_SDR50:
916fb172c8aSjmcneill 	case SDMMC_TIMING_UHS_SDR104:
917fb172c8aSjmcneill 		tblk = tuning_blk_4bit;
918fb172c8aSjmcneill 		tsize = sizeof(tuning_blk_4bit);
919fb172c8aSjmcneill 		opcode = MMC_SEND_TUNING_BLOCK;
920fb172c8aSjmcneill 		break;
921fb172c8aSjmcneill 	default:
922fb172c8aSjmcneill 		return EINVAL;
923fb172c8aSjmcneill 	}
924fb172c8aSjmcneill 
925fb172c8aSjmcneill 	const uint32_t clkc = SDHC_READ(sc, SD_CLKC_REG);
926fb172c8aSjmcneill 	clk_div = __SHIFTOUT(clkc, SD_CLKC_CLK_DIV);
927fb172c8aSjmcneill 
928fb172c8aSjmcneill 	for (ph = 0; ph <= clk_div; ph++) {
929fb172c8aSjmcneill 		SDHC_SET_CLEAR(sc, SD_CLK2_REG,
930fb172c8aSjmcneill 		    __SHIFTIN(ph, SD_CLK2_RX_CLK_PHASE), SD_CLK2_RX_CLK_PHASE);
931fb172c8aSjmcneill 		delay(10);
932fb172c8aSjmcneill 
933fb172c8aSjmcneill 		u_int nmatch = 0;
934fb172c8aSjmcneill #define NUMTRIES 10
935fb172c8aSjmcneill 		for (u_int i = 0; i < NUMTRIES; i++) {
936fb172c8aSjmcneill 			memset(data, 0, tsize);
937fb172c8aSjmcneill 			memset(&cmd, 0, sizeof(cmd));
938fb172c8aSjmcneill 			cmd.c_data = data;
939fb172c8aSjmcneill 			cmd.c_datalen = cmd.c_blklen = tsize;
940fb172c8aSjmcneill 			cmd.c_opcode = opcode;
941fb172c8aSjmcneill 			cmd.c_arg = 0;
942fb172c8aSjmcneill 			cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1;
943fb172c8aSjmcneill 			meson_sdhc_exec_command(sc, &cmd);
944fb172c8aSjmcneill 			if (cmd.c_error == 0 && memcmp(data, tblk, tsize) == 0)
945fb172c8aSjmcneill 				nmatch++;
946fb172c8aSjmcneill 		}
947fb172c8aSjmcneill 		if (nmatch == NUMTRIES) {	/* good phase value */
948fb172c8aSjmcneill 			if (wrap.start == 0)
949fb172c8aSjmcneill 				wrap.size++;
950fb172c8aSjmcneill 			if (curr.start == -1)
951fb172c8aSjmcneill 				curr.start = ph;
952fb172c8aSjmcneill 			curr.size++;
953fb172c8aSjmcneill 		} else {
954fb172c8aSjmcneill 			wrap.start = -1;
955fb172c8aSjmcneill 			if (curr.start != -1) {	/* end of current window */
956fb172c8aSjmcneill 				if (best.start == -1 || best.size < curr.size)
957fb172c8aSjmcneill 					best = curr;
958fb172c8aSjmcneill 				curr = (struct window_s)
959fb172c8aSjmcneill 				    { .start = -1, .size = 0 };
960fb172c8aSjmcneill 			}
961fb172c8aSjmcneill 		}
962fb172c8aSjmcneill #undef NUMTRIES
963fb172c8aSjmcneill 	}
964fb172c8aSjmcneill 
965fb172c8aSjmcneill 	if (curr.start != -1) {	/* the current window wraps around */
966fb172c8aSjmcneill 		curr.size += wrap.size;
967fb172c8aSjmcneill 		if (curr.size > ph)
968fb172c8aSjmcneill 			curr.size = ph;
969fb172c8aSjmcneill 		if (best.start == -1 || best.size < curr.size)
970fb172c8aSjmcneill 			best = curr;
971fb172c8aSjmcneill 	}
972fb172c8aSjmcneill 
973fb172c8aSjmcneill 	if (best.start == -1) {	/* no window - use default rx_phase */
974fb172c8aSjmcneill 		rx_phase = meson_sdhc_default_rx_phase(sc);
975fb172c8aSjmcneill 	} else {
976fb172c8aSjmcneill 		rx_phase = best.start + best.size / 2;
977fb172c8aSjmcneill 		if (rx_phase >= ph)
978fb172c8aSjmcneill 			rx_phase -= ph;
979fb172c8aSjmcneill 	}
980fb172c8aSjmcneill 
981fb172c8aSjmcneill 	SDHC_SET_CLEAR(sc, SD_CLK2_REG,
982fb172c8aSjmcneill 	    __SHIFTIN(rx_phase, SD_CLK2_RX_CLK_PHASE), SD_CLK2_RX_CLK_PHASE);
983fb172c8aSjmcneill 
984fb172c8aSjmcneill 	return 0;
985fb172c8aSjmcneill }
986