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