1*cc534ef5Smlelstv /* $NetBSD: sdmmc_io.c,v 1.21 2020/10/17 09:36:45 mlelstv Exp $ */
2e0297d1eSnonaka /* $OpenBSD: sdmmc_io.c,v 1.10 2007/09/17 01:33:33 krw Exp $ */
3e0297d1eSnonaka
4e0297d1eSnonaka /*
5e0297d1eSnonaka * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
6e0297d1eSnonaka *
7e0297d1eSnonaka * Permission to use, copy, modify, and distribute this software for any
8e0297d1eSnonaka * purpose with or without fee is hereby granted, provided that the above
9e0297d1eSnonaka * copyright notice and this permission notice appear in all copies.
10e0297d1eSnonaka *
11e0297d1eSnonaka * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12e0297d1eSnonaka * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13e0297d1eSnonaka * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14e0297d1eSnonaka * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15e0297d1eSnonaka * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16e0297d1eSnonaka * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17e0297d1eSnonaka * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18e0297d1eSnonaka */
19e0297d1eSnonaka
20e0297d1eSnonaka /* Routines for SD I/O cards. */
21e0297d1eSnonaka
22e0297d1eSnonaka #include <sys/cdefs.h>
23*cc534ef5Smlelstv __KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.21 2020/10/17 09:36:45 mlelstv Exp $");
245e2f4552Smatt
255e2f4552Smatt #ifdef _KERNEL_OPT
265e2f4552Smatt #include "opt_sdmmc.h"
275e2f4552Smatt #endif
28e0297d1eSnonaka
29e0297d1eSnonaka #include <sys/param.h>
30e0297d1eSnonaka #include <sys/kernel.h>
31e0297d1eSnonaka #include <sys/malloc.h>
32e0297d1eSnonaka #include <sys/proc.h>
33e0297d1eSnonaka #include <sys/systm.h>
34e0297d1eSnonaka
35e0297d1eSnonaka #include <dev/sdmmc/sdmmc_ioreg.h>
36e0297d1eSnonaka #include <dev/sdmmc/sdmmcchip.h>
37e0297d1eSnonaka #include <dev/sdmmc/sdmmcreg.h>
38e0297d1eSnonaka #include <dev/sdmmc/sdmmcvar.h>
39e0297d1eSnonaka
40e0297d1eSnonaka #ifdef SDMMC_DEBUG
41e0297d1eSnonaka #define DPRINTF(s) do { printf s; } while (0)
42e0297d1eSnonaka #else
43e0297d1eSnonaka #define DPRINTF(s) do {} while (0)
44e0297d1eSnonaka #endif
45e0297d1eSnonaka
46e0297d1eSnonaka struct sdmmc_intr_handler {
47e0297d1eSnonaka struct sdmmc_softc *ih_softc;
48e0297d1eSnonaka char *ih_name;
49e0297d1eSnonaka int (*ih_fun)(void *);
50e0297d1eSnonaka void *ih_arg;
51e0297d1eSnonaka TAILQ_ENTRY(sdmmc_intr_handler) entry;
52e0297d1eSnonaka };
53e0297d1eSnonaka
54e0297d1eSnonaka static int sdmmc_io_rw_direct(struct sdmmc_softc *,
55e34bd768Smlelstv struct sdmmc_function *, int, u_char *, int, bool);
56e0297d1eSnonaka static int sdmmc_io_rw_extended(struct sdmmc_softc *,
57e0297d1eSnonaka struct sdmmc_function *, int, u_char *, int, int);
58e0297d1eSnonaka #if 0
59e0297d1eSnonaka static int sdmmc_io_xchg(struct sdmmc_softc *, struct sdmmc_function *,
60e0297d1eSnonaka int, u_char *);
61e0297d1eSnonaka #endif
62e0297d1eSnonaka static void sdmmc_io_reset(struct sdmmc_softc *);
63e0297d1eSnonaka static int sdmmc_io_send_op_cond(struct sdmmc_softc *, uint32_t,
64e0297d1eSnonaka uint32_t *);
65e0297d1eSnonaka
66e0297d1eSnonaka /*
67e0297d1eSnonaka * Initialize SD I/O card functions (before memory cards). The host
68e0297d1eSnonaka * system and controller must support card interrupts in order to use
69e0297d1eSnonaka * I/O functions.
70e0297d1eSnonaka */
71e0297d1eSnonaka int
sdmmc_io_enable(struct sdmmc_softc * sc)72e0297d1eSnonaka sdmmc_io_enable(struct sdmmc_softc *sc)
73e0297d1eSnonaka {
74e0297d1eSnonaka uint32_t host_ocr;
75e0297d1eSnonaka uint32_t card_ocr;
76e0297d1eSnonaka int error;
77e0297d1eSnonaka
78e0297d1eSnonaka SDMMC_LOCK(sc);
79e0297d1eSnonaka
80e0297d1eSnonaka /* Set host mode to SD "combo" card. */
81e0297d1eSnonaka SET(sc->sc_flags, SMF_SD_MODE|SMF_IO_MODE|SMF_MEM_MODE);
82e0297d1eSnonaka
83e0297d1eSnonaka /* Reset I/O functions. */
84e0297d1eSnonaka sdmmc_io_reset(sc);
85e0297d1eSnonaka
86e0297d1eSnonaka /*
87e0297d1eSnonaka * Read the I/O OCR value, determine the number of I/O
88e0297d1eSnonaka * functions and whether memory is also present (a "combo
89e0297d1eSnonaka * card") by issuing CMD5. SD memory-only and MMC cards
90e0297d1eSnonaka * do not respond to CMD5.
91e0297d1eSnonaka */
92e0297d1eSnonaka error = sdmmc_io_send_op_cond(sc, 0, &card_ocr);
93e0297d1eSnonaka if (error) {
94e0297d1eSnonaka /* No SDIO card; switch to SD memory-only mode. */
95e0297d1eSnonaka CLR(sc->sc_flags, SMF_IO_MODE);
96e0297d1eSnonaka error = 0;
97e0297d1eSnonaka goto out;
98e0297d1eSnonaka }
99e0297d1eSnonaka
100e0297d1eSnonaka /* Parse the additional bits in the I/O OCR value. */
101e0297d1eSnonaka if (!ISSET(card_ocr, SD_IO_OCR_MEM_PRESENT)) {
102e0297d1eSnonaka /* SDIO card without memory (not a "combo card"). */
103e0297d1eSnonaka DPRINTF(("%s: no memory present\n", SDMMCDEVNAME(sc)));
104e0297d1eSnonaka CLR(sc->sc_flags, SMF_MEM_MODE);
105e0297d1eSnonaka }
106e0297d1eSnonaka sc->sc_function_count = SD_IO_OCR_NUM_FUNCTIONS(card_ocr);
107e0297d1eSnonaka if (sc->sc_function_count == 0) {
108e0297d1eSnonaka /* Useless SDIO card without any I/O functions. */
109e0297d1eSnonaka DPRINTF(("%s: no I/O functions\n", SDMMCDEVNAME(sc)));
110e0297d1eSnonaka CLR(sc->sc_flags, SMF_IO_MODE);
111e0297d1eSnonaka error = 0;
112e0297d1eSnonaka goto out;
113e0297d1eSnonaka }
114e0297d1eSnonaka card_ocr &= SD_IO_OCR_MASK;
115e0297d1eSnonaka
116e0297d1eSnonaka /* Set the lowest voltage supported by the card and host. */
117e0297d1eSnonaka host_ocr = sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch);
118e0297d1eSnonaka error = sdmmc_set_bus_power(sc, host_ocr, card_ocr);
119e0297d1eSnonaka if (error) {
120e0297d1eSnonaka aprint_error_dev(sc->sc_dev,
121e0297d1eSnonaka "couldn't supply voltage requested by card\n");
122e0297d1eSnonaka goto out;
123e0297d1eSnonaka }
124e0297d1eSnonaka
125e0297d1eSnonaka /* Send the new OCR value until all cards are ready. */
126e0297d1eSnonaka error = sdmmc_io_send_op_cond(sc, host_ocr, NULL);
127e0297d1eSnonaka if (error) {
128e0297d1eSnonaka aprint_error_dev(sc->sc_dev, "couldn't send I/O OCR\n");
129e0297d1eSnonaka goto out;
130e0297d1eSnonaka }
131e0297d1eSnonaka
132e0297d1eSnonaka out:
133e0297d1eSnonaka SDMMC_UNLOCK(sc);
134e0297d1eSnonaka
135e0297d1eSnonaka return error;
136e0297d1eSnonaka }
137e0297d1eSnonaka
138e0297d1eSnonaka /*
139e0297d1eSnonaka * Allocate sdmmc_function structures for SD card I/O function
140e0297d1eSnonaka * (including function 0).
141e0297d1eSnonaka */
142e0297d1eSnonaka void
sdmmc_io_scan(struct sdmmc_softc * sc)143e0297d1eSnonaka sdmmc_io_scan(struct sdmmc_softc *sc)
144e0297d1eSnonaka {
145e0297d1eSnonaka struct sdmmc_function *sf0, *sf;
146e0297d1eSnonaka int error;
147e0297d1eSnonaka int i;
148e0297d1eSnonaka
149e0297d1eSnonaka SDMMC_LOCK(sc);
150e0297d1eSnonaka
151e0297d1eSnonaka sf0 = sdmmc_function_alloc(sc);
152e0297d1eSnonaka sf0->number = 0;
153e0297d1eSnonaka error = sdmmc_set_relative_addr(sc, sf0);
154e0297d1eSnonaka if (error) {
155e0297d1eSnonaka aprint_error_dev(sc->sc_dev, "couldn't set I/O RCA\n");
156e0297d1eSnonaka SET(sf0->flags, SFF_ERROR);
157e0297d1eSnonaka goto out;
158e0297d1eSnonaka }
159e0297d1eSnonaka sc->sc_fn0 = sf0;
160e0297d1eSnonaka SIMPLEQ_INSERT_TAIL(&sc->sf_head, sf0, sf_list);
161e0297d1eSnonaka
16262d43deeSkiyohara /* Go to Data Transfer Mode, if possible. */
16362d43deeSkiyohara sdmmc_chip_bus_rod(sc->sc_sct, sc->sc_sch, 0);
16462d43deeSkiyohara
165e0297d1eSnonaka /* Verify that the RCA has been set by selecting the card. */
166e0297d1eSnonaka error = sdmmc_select_card(sc, sf0);
167e0297d1eSnonaka if (error) {
168e0297d1eSnonaka aprint_error_dev(sc->sc_dev, "couldn't select I/O RCA %d\n",
169e0297d1eSnonaka sf0->rca);
170e0297d1eSnonaka SET(sf0->flags, SFF_ERROR);
171e0297d1eSnonaka goto out;
172e0297d1eSnonaka }
173e0297d1eSnonaka
174e0297d1eSnonaka for (i = 1; i <= sc->sc_function_count; i++) {
175e0297d1eSnonaka sf = sdmmc_function_alloc(sc);
176e0297d1eSnonaka sf->number = i;
177e0297d1eSnonaka sf->rca = sf0->rca;
178e0297d1eSnonaka SIMPLEQ_INSERT_TAIL(&sc->sf_head, sf, sf_list);
179e0297d1eSnonaka }
180e0297d1eSnonaka
181e0297d1eSnonaka out:
182e0297d1eSnonaka SDMMC_UNLOCK(sc);
183e0297d1eSnonaka }
184e0297d1eSnonaka
185e0297d1eSnonaka /*
186e0297d1eSnonaka * Initialize SDIO card functions.
187e0297d1eSnonaka */
188e0297d1eSnonaka int
sdmmc_io_init(struct sdmmc_softc * sc,struct sdmmc_function * sf)189e0297d1eSnonaka sdmmc_io_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
190e0297d1eSnonaka {
191b5a696dfSkiyohara struct sdmmc_function *sf0 = sc->sc_fn0;
192e0297d1eSnonaka int error = 0;
193b5a696dfSkiyohara uint8_t reg;
194e0297d1eSnonaka
195e0297d1eSnonaka SDMMC_LOCK(sc);
196e0297d1eSnonaka
1975ab3b2b2Smlelstv sf->blklen = sdmmc_chip_host_maxblklen(sc->sc_sct, sc->sc_sch);
1985ab3b2b2Smlelstv
199e0297d1eSnonaka if (sf->number == 0) {
200b5a696dfSkiyohara reg = sdmmc_io_read_1(sf, SD_IO_CCCR_CAPABILITY);
201b5a696dfSkiyohara if (!(reg & CCCR_CAPS_LSC) || (reg & CCCR_CAPS_4BLS)) {
202b5a696dfSkiyohara sdmmc_io_write_1(sf, SD_IO_CCCR_BUS_WIDTH,
203b5a696dfSkiyohara CCCR_BUS_WIDTH_4);
204b5a696dfSkiyohara sf->width = 4;
20591a0a070Sjmcneill error = sdmmc_chip_bus_width(sc->sc_sct, sc->sc_sch,
20691a0a070Sjmcneill sf->width);
20791a0a070Sjmcneill if (error)
20891a0a070Sjmcneill aprint_error_dev(sc->sc_dev,
20991a0a070Sjmcneill "can't change bus width\n");
210b5a696dfSkiyohara }
211e0297d1eSnonaka
212e0297d1eSnonaka error = sdmmc_read_cis(sf, &sf->cis);
213e0297d1eSnonaka if (error) {
214e0297d1eSnonaka aprint_error_dev(sc->sc_dev, "couldn't read CIS\n");
215e0297d1eSnonaka SET(sf->flags, SFF_ERROR);
216e0297d1eSnonaka goto out;
217e0297d1eSnonaka }
218e0297d1eSnonaka
219e0297d1eSnonaka sdmmc_check_cis_quirks(sf);
220e0297d1eSnonaka
221e0297d1eSnonaka #ifdef SDMMC_DEBUG
222e0297d1eSnonaka if (sdmmcdebug)
223e0297d1eSnonaka sdmmc_print_cis(sf);
224e0297d1eSnonaka #endif
22562d43deeSkiyohara
226b5a696dfSkiyohara reg = sdmmc_io_read_1(sf, SD_IO_CCCR_HIGH_SPEED);
227b5a696dfSkiyohara if (reg & CCCR_HIGH_SPEED_SHS) {
228b5a696dfSkiyohara reg |= CCCR_HIGH_SPEED_EHS;
229b5a696dfSkiyohara sdmmc_io_write_1(sf, SD_IO_CCCR_HIGH_SPEED, reg);
230b5a696dfSkiyohara sf->csd.tran_speed = 50000; /* 50MHz */
231b5a696dfSkiyohara
232b5a696dfSkiyohara /* Wait 400KHz x 8 clock */
233c301b5e4Smlelstv sdmmc_delay(20);
234b5a696dfSkiyohara }
23562d43deeSkiyohara if (sc->sc_busclk > sf->csd.tran_speed)
23662d43deeSkiyohara sc->sc_busclk = sf->csd.tran_speed;
23762d43deeSkiyohara error =
2389350eba5Sjmcneill sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk,
2399350eba5Sjmcneill false);
24062d43deeSkiyohara if (error)
24162d43deeSkiyohara aprint_error_dev(sc->sc_dev,
24262d43deeSkiyohara "can't change bus clock\n");
243c301b5e4Smlelstv
244c301b5e4Smlelstv aprint_normal_dev(sc->sc_dev, "%u-bit width,", sf->width);
245c301b5e4Smlelstv if ((sc->sc_busclk / 1000) != 0)
246c301b5e4Smlelstv aprint_normal(" %u.%03u MHz\n",
247c301b5e4Smlelstv sc->sc_busclk / 1000, sc->sc_busclk % 1000);
248c301b5e4Smlelstv else
249c301b5e4Smlelstv aprint_normal(" %u KHz\n", sc->sc_busclk % 1000);
250c301b5e4Smlelstv
251c301b5e4Smlelstv
252b5a696dfSkiyohara } else {
253b5a696dfSkiyohara reg = sdmmc_io_read_1(sf0, SD_IO_FBR(sf->number) + 0x000);
254b5a696dfSkiyohara sf->interface = FBR_STD_FUNC_IF_CODE(reg);
255b5a696dfSkiyohara if (sf->interface == 0x0f)
256b5a696dfSkiyohara sf->interface =
257b5a696dfSkiyohara sdmmc_io_read_1(sf0, SD_IO_FBR(sf->number) + 0x001);
258b5a696dfSkiyohara error = sdmmc_read_cis(sf, &sf->cis);
259b5a696dfSkiyohara if (error) {
260b5a696dfSkiyohara aprint_error_dev(sc->sc_dev, "couldn't read CIS\n");
261b5a696dfSkiyohara SET(sf->flags, SFF_ERROR);
262b5a696dfSkiyohara goto out;
263b5a696dfSkiyohara }
264b5a696dfSkiyohara
265b5a696dfSkiyohara sdmmc_check_cis_quirks(sf);
266b5a696dfSkiyohara
267b5a696dfSkiyohara #ifdef SDMMC_DEBUG
268b5a696dfSkiyohara if (sdmmcdebug)
269b5a696dfSkiyohara sdmmc_print_cis(sf);
270b5a696dfSkiyohara #endif
271e0297d1eSnonaka }
272e0297d1eSnonaka
273e0297d1eSnonaka out:
274e0297d1eSnonaka SDMMC_UNLOCK(sc);
275e0297d1eSnonaka
276e0297d1eSnonaka return error;
277e0297d1eSnonaka }
278e0297d1eSnonaka
279e0297d1eSnonaka /*
280e0297d1eSnonaka * Indicate whether the function is ready to operate.
281e0297d1eSnonaka */
282e0297d1eSnonaka static int
sdmmc_io_function_ready(struct sdmmc_function * sf)283e0297d1eSnonaka sdmmc_io_function_ready(struct sdmmc_function *sf)
284e0297d1eSnonaka {
285e0297d1eSnonaka struct sdmmc_softc *sc = sf->sc;
286e0297d1eSnonaka struct sdmmc_function *sf0 = sc->sc_fn0;
287e0297d1eSnonaka uint8_t reg;
288e0297d1eSnonaka
289e0297d1eSnonaka if (sf->number == 0)
290e0297d1eSnonaka return 1; /* FN0 is always ready */
291e0297d1eSnonaka
292e0297d1eSnonaka SDMMC_LOCK(sc);
293e0297d1eSnonaka reg = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_IOREADY);
294e0297d1eSnonaka SDMMC_UNLOCK(sc);
295e0297d1eSnonaka return (reg & (1 << sf->number)) != 0;
296e0297d1eSnonaka }
297e0297d1eSnonaka
298e0297d1eSnonaka int
sdmmc_io_function_enable(struct sdmmc_function * sf)299e0297d1eSnonaka sdmmc_io_function_enable(struct sdmmc_function *sf)
300e0297d1eSnonaka {
301e0297d1eSnonaka struct sdmmc_softc *sc = sf->sc;
302e0297d1eSnonaka struct sdmmc_function *sf0 = sc->sc_fn0;
303e0297d1eSnonaka uint8_t reg;
304e0297d1eSnonaka int retry;
305e0297d1eSnonaka
306e0297d1eSnonaka if (sf->number == 0)
307e0297d1eSnonaka return 0; /* FN0 is always enabled */
308e0297d1eSnonaka
309e0297d1eSnonaka SDMMC_LOCK(sc);
310e0297d1eSnonaka reg = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_ENABLE);
311e0297d1eSnonaka SET(reg, (1U << sf->number));
312e0297d1eSnonaka sdmmc_io_write_1(sf0, SD_IO_CCCR_FN_ENABLE, reg);
313e0297d1eSnonaka SDMMC_UNLOCK(sc);
314e0297d1eSnonaka
315e0297d1eSnonaka retry = 5;
316e0297d1eSnonaka while (!sdmmc_io_function_ready(sf) && retry-- > 0)
317faa8e1b3Spooka kpause("pause", false, hz, NULL);
318e0297d1eSnonaka return (retry >= 0) ? 0 : ETIMEDOUT;
319e0297d1eSnonaka }
320e0297d1eSnonaka
321e0297d1eSnonaka /*
322e0297d1eSnonaka * Disable the I/O function. Return zero if the function was
323e0297d1eSnonaka * disabled successfully.
324e0297d1eSnonaka */
325e0297d1eSnonaka void
sdmmc_io_function_disable(struct sdmmc_function * sf)326e0297d1eSnonaka sdmmc_io_function_disable(struct sdmmc_function *sf)
327e0297d1eSnonaka {
328e0297d1eSnonaka struct sdmmc_softc *sc = sf->sc;
329e0297d1eSnonaka struct sdmmc_function *sf0 = sc->sc_fn0;
330e0297d1eSnonaka uint8_t reg;
331e0297d1eSnonaka
332e0297d1eSnonaka if (sf->number == 0)
333e0297d1eSnonaka return; /* FN0 is always enabled */
334e0297d1eSnonaka
335e0297d1eSnonaka SDMMC_LOCK(sc);
336e0297d1eSnonaka reg = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_ENABLE);
337e0297d1eSnonaka CLR(reg, (1U << sf->number));
338e0297d1eSnonaka sdmmc_io_write_1(sf0, SD_IO_CCCR_FN_ENABLE, reg);
339e0297d1eSnonaka SDMMC_UNLOCK(sc);
340e0297d1eSnonaka }
341e0297d1eSnonaka
342e0297d1eSnonaka static int
sdmmc_io_rw_direct(struct sdmmc_softc * sc,struct sdmmc_function * sf,int reg,u_char * datap,int arg,bool toutok)343e0297d1eSnonaka sdmmc_io_rw_direct(struct sdmmc_softc *sc, struct sdmmc_function *sf,
344e34bd768Smlelstv int reg, u_char *datap, int arg, bool toutok)
345e0297d1eSnonaka {
346e0297d1eSnonaka struct sdmmc_command cmd;
347e0297d1eSnonaka int error;
348e0297d1eSnonaka
349e0297d1eSnonaka /* Don't lock */
350e0297d1eSnonaka
351e0297d1eSnonaka /* Make sure the card is selected. */
352e0297d1eSnonaka error = sdmmc_select_card(sc, sf);
353e0297d1eSnonaka if (error)
354e0297d1eSnonaka return error;
355e0297d1eSnonaka
356e0297d1eSnonaka arg |= ((sf == NULL ? 0 : sf->number) & SD_ARG_CMD52_FUNC_MASK) <<
357e0297d1eSnonaka SD_ARG_CMD52_FUNC_SHIFT;
358e0297d1eSnonaka arg |= (reg & SD_ARG_CMD52_REG_MASK) <<
359e0297d1eSnonaka SD_ARG_CMD52_REG_SHIFT;
360e0297d1eSnonaka arg |= (*datap & SD_ARG_CMD52_DATA_MASK) <<
361e0297d1eSnonaka SD_ARG_CMD52_DATA_SHIFT;
362e0297d1eSnonaka
363e0297d1eSnonaka memset(&cmd, 0, sizeof cmd);
364e0297d1eSnonaka cmd.c_opcode = SD_IO_RW_DIRECT;
365e0297d1eSnonaka cmd.c_arg = arg;
366e0297d1eSnonaka cmd.c_flags = SCF_CMD_AC | SCF_RSP_R5;
367e34bd768Smlelstv if (toutok)
368e34bd768Smlelstv cmd.c_flags |= SCF_TOUT_OK;
369e0297d1eSnonaka
370e0297d1eSnonaka error = sdmmc_mmc_command(sc, &cmd);
371c301b5e4Smlelstv if (error == 0)
372e0297d1eSnonaka *datap = SD_R5_DATA(cmd.c_resp);
373e0297d1eSnonaka
374e34bd768Smlelstv if (error && error != ETIMEDOUT) {
375c301b5e4Smlelstv device_printf(sc->sc_dev,
376c301b5e4Smlelstv "direct I/O error %d, r=%d p=%p %s\n",
377c301b5e4Smlelstv error, reg, datap,
378*cc534ef5Smlelstv ISSET(arg, SD_ARG_CMD52_WRITE) ? "write" : "read");
379c301b5e4Smlelstv }
380c301b5e4Smlelstv
381e0297d1eSnonaka return error;
382e0297d1eSnonaka }
383e0297d1eSnonaka
384e0297d1eSnonaka /*
385e0297d1eSnonaka * Useful values of `arg' to pass in are either SD_ARG_CMD53_READ or
386e0297d1eSnonaka * SD_ARG_CMD53_WRITE. SD_ARG_CMD53_INCREMENT may be ORed into `arg'
387e0297d1eSnonaka * to access successive register locations instead of accessing the
388e0297d1eSnonaka * same register many times.
389e0297d1eSnonaka */
390e0297d1eSnonaka static int
sdmmc_io_rw_extended(struct sdmmc_softc * sc,struct sdmmc_function * sf,int reg,u_char * datap,int datalen,int arg)391e0297d1eSnonaka sdmmc_io_rw_extended(struct sdmmc_softc *sc, struct sdmmc_function *sf,
392e0297d1eSnonaka int reg, u_char *datap, int datalen, int arg)
393e0297d1eSnonaka {
394e0297d1eSnonaka struct sdmmc_command cmd;
395e0297d1eSnonaka int error;
396e0297d1eSnonaka
397e0297d1eSnonaka /* Don't lock */
398e0297d1eSnonaka
399e0297d1eSnonaka #if 0
400e0297d1eSnonaka /* Make sure the card is selected. */
401e0297d1eSnonaka error = sdmmc_select_card(sc, sf);
402e0297d1eSnonaka if (error)
403e0297d1eSnonaka return error;
404e0297d1eSnonaka #endif
405e0297d1eSnonaka
406e0297d1eSnonaka arg |= (((sf == NULL) ? 0 : sf->number) & SD_ARG_CMD53_FUNC_MASK) <<
407e0297d1eSnonaka SD_ARG_CMD53_FUNC_SHIFT;
408e0297d1eSnonaka arg |= (reg & SD_ARG_CMD53_REG_MASK) <<
409e0297d1eSnonaka SD_ARG_CMD53_REG_SHIFT;
410e0297d1eSnonaka arg |= (datalen & SD_ARG_CMD53_LENGTH_MASK) <<
411e0297d1eSnonaka SD_ARG_CMD53_LENGTH_SHIFT;
412e0297d1eSnonaka
413e0297d1eSnonaka memset(&cmd, 0, sizeof cmd);
414e0297d1eSnonaka cmd.c_opcode = SD_IO_RW_EXTENDED;
415e0297d1eSnonaka cmd.c_arg = arg;
416116cf3ddSjmcneill cmd.c_flags = SCF_CMD_ADTC | SCF_RSP_R5;
417e0297d1eSnonaka cmd.c_data = datap;
418e0297d1eSnonaka cmd.c_datalen = datalen;
4195ab3b2b2Smlelstv cmd.c_blklen = MIN(datalen, sf->blklen);
4205ab3b2b2Smlelstv
421e0297d1eSnonaka if (!ISSET(arg, SD_ARG_CMD53_WRITE))
422e0297d1eSnonaka cmd.c_flags |= SCF_CMD_READ;
423e0297d1eSnonaka
424e0297d1eSnonaka error = sdmmc_mmc_command(sc, &cmd);
425e0297d1eSnonaka
426c301b5e4Smlelstv if (error) {
427c301b5e4Smlelstv device_printf(sc->sc_dev,
428c301b5e4Smlelstv "extended I/O error %d, r=%d p=%p l=%d %s\n",
429c301b5e4Smlelstv error, reg, datap, datalen,
430c301b5e4Smlelstv ISSET(arg, SD_ARG_CMD53_WRITE) ? "write" : "read");
431c301b5e4Smlelstv }
432c301b5e4Smlelstv
433e0297d1eSnonaka return error;
434e0297d1eSnonaka }
435e0297d1eSnonaka
436e0297d1eSnonaka uint8_t
sdmmc_io_read_1(struct sdmmc_function * sf,int reg)437e0297d1eSnonaka sdmmc_io_read_1(struct sdmmc_function *sf, int reg)
438e0297d1eSnonaka {
439e0297d1eSnonaka uint8_t data = 0;
440e0297d1eSnonaka
441e0297d1eSnonaka /* Don't lock */
442e0297d1eSnonaka
443e0297d1eSnonaka (void)sdmmc_io_rw_direct(sf->sc, sf, reg, (u_char *)&data,
444e34bd768Smlelstv SD_ARG_CMD52_READ, false);
445e0297d1eSnonaka return data;
446e0297d1eSnonaka }
447e0297d1eSnonaka
448e0297d1eSnonaka void
sdmmc_io_write_1(struct sdmmc_function * sf,int reg,uint8_t data)449e0297d1eSnonaka sdmmc_io_write_1(struct sdmmc_function *sf, int reg, uint8_t data)
450e0297d1eSnonaka {
451e0297d1eSnonaka
452e0297d1eSnonaka /* Don't lock */
453e0297d1eSnonaka
454e0297d1eSnonaka (void)sdmmc_io_rw_direct(sf->sc, sf, reg, (u_char *)&data,
455e34bd768Smlelstv SD_ARG_CMD52_WRITE, false);
456e0297d1eSnonaka }
457e0297d1eSnonaka
458e0297d1eSnonaka uint16_t
sdmmc_io_read_2(struct sdmmc_function * sf,int reg)459e0297d1eSnonaka sdmmc_io_read_2(struct sdmmc_function *sf, int reg)
460e0297d1eSnonaka {
461e0297d1eSnonaka uint16_t data = 0;
462e0297d1eSnonaka
463e0297d1eSnonaka /* Don't lock */
464e0297d1eSnonaka
465e0297d1eSnonaka (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 2,
466e0297d1eSnonaka SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT);
467e0297d1eSnonaka return data;
468e0297d1eSnonaka }
469e0297d1eSnonaka
470e0297d1eSnonaka void
sdmmc_io_write_2(struct sdmmc_function * sf,int reg,uint16_t data)471e0297d1eSnonaka sdmmc_io_write_2(struct sdmmc_function *sf, int reg, uint16_t data)
472e0297d1eSnonaka {
473e0297d1eSnonaka
474e0297d1eSnonaka /* Don't lock */
475e0297d1eSnonaka
476e0297d1eSnonaka (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 2,
477e0297d1eSnonaka SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT);
478e0297d1eSnonaka }
479e0297d1eSnonaka
480e0297d1eSnonaka uint32_t
sdmmc_io_read_4(struct sdmmc_function * sf,int reg)481e0297d1eSnonaka sdmmc_io_read_4(struct sdmmc_function *sf, int reg)
482e0297d1eSnonaka {
483e0297d1eSnonaka uint32_t data = 0;
484e0297d1eSnonaka
485e0297d1eSnonaka /* Don't lock */
486e0297d1eSnonaka
487e0297d1eSnonaka (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 4,
488e0297d1eSnonaka SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT);
489e0297d1eSnonaka return data;
490e0297d1eSnonaka }
491e0297d1eSnonaka
492e0297d1eSnonaka void
sdmmc_io_write_4(struct sdmmc_function * sf,int reg,uint32_t data)493e0297d1eSnonaka sdmmc_io_write_4(struct sdmmc_function *sf, int reg, uint32_t data)
494e0297d1eSnonaka {
495e0297d1eSnonaka
496e0297d1eSnonaka /* Don't lock */
497e0297d1eSnonaka
498e0297d1eSnonaka (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 4,
499e0297d1eSnonaka SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT);
500e0297d1eSnonaka }
501e0297d1eSnonaka
502e0297d1eSnonaka
503e0297d1eSnonaka int
sdmmc_io_read_multi_1(struct sdmmc_function * sf,int reg,u_char * data,int datalen)504e0297d1eSnonaka sdmmc_io_read_multi_1(struct sdmmc_function *sf, int reg, u_char *data,
505e0297d1eSnonaka int datalen)
506e0297d1eSnonaka {
5075ab3b2b2Smlelstv int blocks, bytes, error = 0;
508e0297d1eSnonaka
509e0297d1eSnonaka /* Don't lock */
510e0297d1eSnonaka
5115ab3b2b2Smlelstv while (datalen >= sf->blklen) {
5125ab3b2b2Smlelstv //blocks = imin(datalen / sf->blklen,
5135ab3b2b2Smlelstv // SD_ARG_CMD53_LENGTH_MAX);
5145ab3b2b2Smlelstv blocks = 1;
5155ab3b2b2Smlelstv bytes = blocks * sf->blklen;
516e0297d1eSnonaka error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
5175ab3b2b2Smlelstv bytes, SD_ARG_CMD53_READ);
518e0297d1eSnonaka if (error)
519e0297d1eSnonaka goto error;
5205ab3b2b2Smlelstv data += bytes;
5215ab3b2b2Smlelstv datalen -= bytes;
522e0297d1eSnonaka }
523e0297d1eSnonaka
5245ab3b2b2Smlelstv if (datalen)
525e0297d1eSnonaka error = sdmmc_io_rw_extended(sf->sc, sf, reg, data, datalen,
526e0297d1eSnonaka SD_ARG_CMD53_READ);
527e0297d1eSnonaka error:
528e0297d1eSnonaka return error;
529e0297d1eSnonaka }
530e0297d1eSnonaka
531e0297d1eSnonaka int
sdmmc_io_write_multi_1(struct sdmmc_function * sf,int reg,u_char * data,int datalen)532e0297d1eSnonaka sdmmc_io_write_multi_1(struct sdmmc_function *sf, int reg, u_char *data,
533e0297d1eSnonaka int datalen)
534e0297d1eSnonaka {
5355ab3b2b2Smlelstv int blocks, bytes, error = 0;
536e0297d1eSnonaka
537e0297d1eSnonaka /* Don't lock */
538e0297d1eSnonaka
5395ab3b2b2Smlelstv while (datalen >= sf->blklen) {
5405ab3b2b2Smlelstv //blocks = imin(datalen / sf->blklen,
5415ab3b2b2Smlelstv // SD_ARG_CMD53_LENGTH_MAX);
5425ab3b2b2Smlelstv blocks = 1;
5435ab3b2b2Smlelstv bytes = blocks * sf->blklen;
544e0297d1eSnonaka error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
5455ab3b2b2Smlelstv bytes, SD_ARG_CMD53_WRITE);
546e0297d1eSnonaka if (error)
547e0297d1eSnonaka goto error;
5485ab3b2b2Smlelstv data += bytes;
5495ab3b2b2Smlelstv datalen -= bytes;
550e0297d1eSnonaka }
551e0297d1eSnonaka
5525ab3b2b2Smlelstv if (datalen)
553e0297d1eSnonaka error = sdmmc_io_rw_extended(sf->sc, sf, reg, data, datalen,
554e0297d1eSnonaka SD_ARG_CMD53_WRITE);
555e0297d1eSnonaka error:
556e0297d1eSnonaka return error;
557e0297d1eSnonaka }
558e0297d1eSnonaka
5595ab3b2b2Smlelstv
5605ab3b2b2Smlelstv int
sdmmc_io_read_region_1(struct sdmmc_function * sf,int reg,u_char * data,int datalen)5615ab3b2b2Smlelstv sdmmc_io_read_region_1(struct sdmmc_function *sf, int reg, u_char *data,
5625ab3b2b2Smlelstv int datalen)
5635ab3b2b2Smlelstv {
5645ab3b2b2Smlelstv int blocks, bytes, error = 0;
5655ab3b2b2Smlelstv
5665ab3b2b2Smlelstv /* Don't lock */
5675ab3b2b2Smlelstv
5685ab3b2b2Smlelstv while (datalen >= sf->blklen) {
5695ab3b2b2Smlelstv //blocks = imin(datalen / sf->blklen,
5705ab3b2b2Smlelstv // SD_ARG_CMD53_LENGTH_MAX);
5715ab3b2b2Smlelstv blocks = 1;
5725ab3b2b2Smlelstv bytes = blocks * sf->blklen;
5735ab3b2b2Smlelstv error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
5745ab3b2b2Smlelstv bytes, SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT);
5755ab3b2b2Smlelstv if (error)
5765ab3b2b2Smlelstv goto error;
5775ab3b2b2Smlelstv reg += bytes;
5785ab3b2b2Smlelstv data += bytes;
5795ab3b2b2Smlelstv datalen -= bytes;
5805ab3b2b2Smlelstv }
5815ab3b2b2Smlelstv
5825ab3b2b2Smlelstv if (datalen)
5835ab3b2b2Smlelstv error = sdmmc_io_rw_extended(sf->sc, sf, reg, data, datalen,
5845ab3b2b2Smlelstv SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT);
5855ab3b2b2Smlelstv error:
5865ab3b2b2Smlelstv return error;
5875ab3b2b2Smlelstv }
5885ab3b2b2Smlelstv
5895ab3b2b2Smlelstv int
sdmmc_io_write_region_1(struct sdmmc_function * sf,int reg,u_char * data,int datalen)5905ab3b2b2Smlelstv sdmmc_io_write_region_1(struct sdmmc_function *sf, int reg, u_char *data,
5915ab3b2b2Smlelstv int datalen)
5925ab3b2b2Smlelstv {
5935ab3b2b2Smlelstv int blocks, bytes, error = 0;
5945ab3b2b2Smlelstv
5955ab3b2b2Smlelstv /* Don't lock */
5965ab3b2b2Smlelstv
5975ab3b2b2Smlelstv while (datalen >= sf->blklen) {
5985ab3b2b2Smlelstv //blocks = imin(datalen / sf->blklen,
5995ab3b2b2Smlelstv // SD_ARG_CMD53_LENGTH_MAX);
6005ab3b2b2Smlelstv blocks = 1;
6015ab3b2b2Smlelstv bytes = blocks * sf->blklen;
6025ab3b2b2Smlelstv error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
6035ab3b2b2Smlelstv bytes, SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT);
6045ab3b2b2Smlelstv if (error)
6055ab3b2b2Smlelstv goto error;
6065ab3b2b2Smlelstv reg += bytes;
6075ab3b2b2Smlelstv data += bytes;
6085ab3b2b2Smlelstv datalen -= bytes;
6095ab3b2b2Smlelstv }
6105ab3b2b2Smlelstv
6115ab3b2b2Smlelstv if (datalen)
6125ab3b2b2Smlelstv error = sdmmc_io_rw_extended(sf->sc, sf, reg, data, datalen,
6135ab3b2b2Smlelstv SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT);
6145ab3b2b2Smlelstv error:
6155ab3b2b2Smlelstv return error;
6165ab3b2b2Smlelstv }
6175ab3b2b2Smlelstv
618e0297d1eSnonaka #if 0
619e0297d1eSnonaka static int
620e0297d1eSnonaka sdmmc_io_xchg(struct sdmmc_softc *sc, struct sdmmc_function *sf,
621e0297d1eSnonaka int reg, u_char *datap)
622e0297d1eSnonaka {
623e0297d1eSnonaka
624e0297d1eSnonaka /* Don't lock */
625e0297d1eSnonaka
626e0297d1eSnonaka return sdmmc_io_rw_direct(sc, sf, reg, datap,
627e34bd768Smlelstv SD_ARG_CMD52_WRITE|SD_ARG_CMD52_EXCHANGE, false);
628e0297d1eSnonaka }
629e0297d1eSnonaka #endif
630e0297d1eSnonaka
631e0297d1eSnonaka /*
632c301b5e4Smlelstv * Abort I/O function of the card
633c301b5e4Smlelstv */
634c301b5e4Smlelstv int
sdmmc_io_function_abort(struct sdmmc_function * sf)635c301b5e4Smlelstv sdmmc_io_function_abort(struct sdmmc_function *sf)
636c301b5e4Smlelstv {
637c301b5e4Smlelstv u_char data = CCCR_CTL_AS(sf->number);
638c301b5e4Smlelstv
639c301b5e4Smlelstv return sdmmc_io_rw_direct(sf->sc, NULL, SD_IO_CCCR_CTL, &data,
640e34bd768Smlelstv SD_ARG_CMD52_WRITE, true);
641c301b5e4Smlelstv }
642c301b5e4Smlelstv
643c301b5e4Smlelstv /*
644e0297d1eSnonaka * Reset the I/O functions of the card.
645e0297d1eSnonaka */
646e0297d1eSnonaka static void
sdmmc_io_reset(struct sdmmc_softc * sc)647e0297d1eSnonaka sdmmc_io_reset(struct sdmmc_softc *sc)
648e0297d1eSnonaka {
64991a0a070Sjmcneill u_char data = CCCR_CTL_RES;
650e0297d1eSnonaka
6515ab3b2b2Smlelstv if (sdmmc_io_rw_direct(sc, NULL, SD_IO_CCCR_CTL, &data,
652e34bd768Smlelstv SD_ARG_CMD52_WRITE, true) == 0)
653c301b5e4Smlelstv sdmmc_pause(100000, NULL); /* XXX SDMMC_LOCK */
654e0297d1eSnonaka }
655e0297d1eSnonaka
656e0297d1eSnonaka /*
657e0297d1eSnonaka * Get or set the card's I/O OCR value (SDIO).
658e0297d1eSnonaka */
659e0297d1eSnonaka static int
sdmmc_io_send_op_cond(struct sdmmc_softc * sc,u_int32_t ocr,u_int32_t * ocrp)660e0297d1eSnonaka sdmmc_io_send_op_cond(struct sdmmc_softc *sc, u_int32_t ocr, u_int32_t *ocrp)
661e0297d1eSnonaka {
662e0297d1eSnonaka struct sdmmc_command cmd;
663e0297d1eSnonaka int error;
664e0297d1eSnonaka int retry;
665e0297d1eSnonaka
666e0297d1eSnonaka DPRINTF(("sdmmc_io_send_op_cond: ocr = %#x\n", ocr));
667e0297d1eSnonaka
668e0297d1eSnonaka /* Don't lock */
669e0297d1eSnonaka
670e0297d1eSnonaka /*
671e0297d1eSnonaka * If we change the OCR value, retry the command until the OCR
672e0297d1eSnonaka * we receive in response has the "CARD BUSY" bit set, meaning
673e0297d1eSnonaka * that all cards are ready for identification.
674e0297d1eSnonaka */
675e0297d1eSnonaka for (retry = 0; retry < 100; retry++) {
676e0297d1eSnonaka memset(&cmd, 0, sizeof cmd);
677e0297d1eSnonaka cmd.c_opcode = SD_IO_SEND_OP_COND;
678e0297d1eSnonaka cmd.c_arg = ocr;
679f30ec675Smlelstv cmd.c_flags = SCF_CMD_BCR | SCF_RSP_R4 | SCF_TOUT_OK;
680e0297d1eSnonaka
681e0297d1eSnonaka error = sdmmc_mmc_command(sc, &cmd);
682e0297d1eSnonaka if (error)
683e0297d1eSnonaka break;
684e0297d1eSnonaka if (ISSET(MMC_R4(cmd.c_resp), SD_IO_OCR_MEM_READY) || ocr == 0)
685e0297d1eSnonaka break;
686e0297d1eSnonaka
687e0297d1eSnonaka error = ETIMEDOUT;
688c301b5e4Smlelstv sdmmc_pause(10000, NULL);
689e0297d1eSnonaka }
690e0297d1eSnonaka if (error == 0 && ocrp != NULL)
691e0297d1eSnonaka *ocrp = MMC_R4(cmd.c_resp);
692e0297d1eSnonaka
693e0297d1eSnonaka DPRINTF(("sdmmc_io_send_op_cond: error = %d\n", error));
694e0297d1eSnonaka
695e0297d1eSnonaka return error;
696e0297d1eSnonaka }
697e0297d1eSnonaka
698e0297d1eSnonaka /*
699e0297d1eSnonaka * Card interrupt handling
700e0297d1eSnonaka */
701e0297d1eSnonaka
702e0297d1eSnonaka void
sdmmc_intr_enable(struct sdmmc_function * sf)703e0297d1eSnonaka sdmmc_intr_enable(struct sdmmc_function *sf)
704e0297d1eSnonaka {
705e0297d1eSnonaka struct sdmmc_softc *sc = sf->sc;
706e0297d1eSnonaka struct sdmmc_function *sf0 = sc->sc_fn0;
707e0297d1eSnonaka uint8_t reg;
708e0297d1eSnonaka
709e0297d1eSnonaka SDMMC_LOCK(sc);
710e0297d1eSnonaka reg = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_INTEN);
711e0297d1eSnonaka reg |= 1 << sf->number;
712e0297d1eSnonaka sdmmc_io_write_1(sf0, SD_IO_CCCR_FN_INTEN, reg);
713e0297d1eSnonaka SDMMC_UNLOCK(sc);
714e0297d1eSnonaka }
715e0297d1eSnonaka
716e0297d1eSnonaka void
sdmmc_intr_disable(struct sdmmc_function * sf)717e0297d1eSnonaka sdmmc_intr_disable(struct sdmmc_function *sf)
718e0297d1eSnonaka {
719e0297d1eSnonaka struct sdmmc_softc *sc = sf->sc;
720e0297d1eSnonaka struct sdmmc_function *sf0 = sc->sc_fn0;
721e0297d1eSnonaka uint8_t reg;
722e0297d1eSnonaka
723e0297d1eSnonaka SDMMC_LOCK(sc);
724e0297d1eSnonaka reg = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_INTEN);
725e0297d1eSnonaka reg &= ~(1 << sf->number);
726e0297d1eSnonaka sdmmc_io_write_1(sf0, SD_IO_CCCR_FN_INTEN, reg);
727e0297d1eSnonaka SDMMC_UNLOCK(sc);
728e0297d1eSnonaka }
729e0297d1eSnonaka
730e0297d1eSnonaka /*
731e0297d1eSnonaka * Establish a handler for the SDIO card interrupt. Because the
732e0297d1eSnonaka * interrupt may be shared with different SDIO functions, multiple
733e0297d1eSnonaka * handlers can be established.
734e0297d1eSnonaka */
735e0297d1eSnonaka void *
sdmmc_intr_establish(device_t dev,int (* fun)(void *),void * arg,const char * name)736e0297d1eSnonaka sdmmc_intr_establish(device_t dev, int (*fun)(void *), void *arg,
737e0297d1eSnonaka const char *name)
738e0297d1eSnonaka {
739e0297d1eSnonaka struct sdmmc_softc *sc = device_private(dev);
740e0297d1eSnonaka struct sdmmc_intr_handler *ih;
741e0297d1eSnonaka
742e0297d1eSnonaka if (sc->sc_sct->card_enable_intr == NULL)
743e0297d1eSnonaka return NULL;
744e0297d1eSnonaka
745bcc384fdSjdolecek ih = malloc(sizeof *ih, M_DEVBUF, M_WAITOK|M_ZERO);
746e0297d1eSnonaka if (ih == NULL)
747e0297d1eSnonaka return NULL;
748e0297d1eSnonaka
749bcc384fdSjdolecek ih->ih_name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK|M_ZERO);
750e0297d1eSnonaka if (ih->ih_name == NULL) {
751e0297d1eSnonaka free(ih, M_DEVBUF);
752e0297d1eSnonaka return NULL;
753e0297d1eSnonaka }
754e0297d1eSnonaka strlcpy(ih->ih_name, name, strlen(name));
755e0297d1eSnonaka ih->ih_softc = sc;
756e0297d1eSnonaka ih->ih_fun = fun;
757e0297d1eSnonaka ih->ih_arg = arg;
758e0297d1eSnonaka
759ab5c3234Smlelstv mutex_enter(&sc->sc_mtx);
760e0297d1eSnonaka if (TAILQ_EMPTY(&sc->sc_intrq)) {
761e0297d1eSnonaka sdmmc_intr_enable(sc->sc_fn0);
762e0297d1eSnonaka sdmmc_chip_card_enable_intr(sc->sc_sct, sc->sc_sch, 1);
763e0297d1eSnonaka }
764e0297d1eSnonaka TAILQ_INSERT_TAIL(&sc->sc_intrq, ih, entry);
765ab5c3234Smlelstv mutex_exit(&sc->sc_mtx);
766e0297d1eSnonaka
767e0297d1eSnonaka return ih;
768e0297d1eSnonaka }
769e0297d1eSnonaka
770e0297d1eSnonaka /*
771e0297d1eSnonaka * Disestablish the given handler.
772e0297d1eSnonaka */
773e0297d1eSnonaka void
sdmmc_intr_disestablish(void * cookie)774e0297d1eSnonaka sdmmc_intr_disestablish(void *cookie)
775e0297d1eSnonaka {
776e0297d1eSnonaka struct sdmmc_intr_handler *ih = cookie;
777e0297d1eSnonaka struct sdmmc_softc *sc = ih->ih_softc;
778e0297d1eSnonaka
779e0297d1eSnonaka if (sc->sc_sct->card_enable_intr == NULL)
780e0297d1eSnonaka return;
781e0297d1eSnonaka
782ab5c3234Smlelstv mutex_enter(&sc->sc_mtx);
783e0297d1eSnonaka TAILQ_REMOVE(&sc->sc_intrq, ih, entry);
784e0297d1eSnonaka if (TAILQ_EMPTY(&sc->sc_intrq)) {
785e0297d1eSnonaka sdmmc_chip_card_enable_intr(sc->sc_sct, sc->sc_sch, 0);
786e0297d1eSnonaka sdmmc_intr_disable(sc->sc_fn0);
787e0297d1eSnonaka }
788ab5c3234Smlelstv mutex_exit(&sc->sc_mtx);
789e0297d1eSnonaka
790e0297d1eSnonaka free(ih->ih_name, M_DEVBUF);
791e0297d1eSnonaka free(ih, M_DEVBUF);
792e0297d1eSnonaka }
793e0297d1eSnonaka
794e0297d1eSnonaka /*
795e0297d1eSnonaka * Call established SDIO card interrupt handlers. The host controller
796e0297d1eSnonaka * must call this function from its own interrupt handler to handle an
797e0297d1eSnonaka * SDIO interrupt from the card.
798e0297d1eSnonaka */
799e0297d1eSnonaka void
sdmmc_card_intr(device_t dev)800e0297d1eSnonaka sdmmc_card_intr(device_t dev)
801e0297d1eSnonaka {
802e0297d1eSnonaka struct sdmmc_softc *sc = device_private(dev);
803e0297d1eSnonaka
804ff5bbabeSmlelstv if (sc->sc_sct->card_enable_intr == NULL)
805ff5bbabeSmlelstv return;
806ff5bbabeSmlelstv
807e0297d1eSnonaka sdmmc_add_task(sc, &sc->sc_intr_task);
808e0297d1eSnonaka }
809e0297d1eSnonaka
810e0297d1eSnonaka void
sdmmc_intr_task(void * arg)811e0297d1eSnonaka sdmmc_intr_task(void *arg)
812e0297d1eSnonaka {
813e0297d1eSnonaka struct sdmmc_softc *sc = (struct sdmmc_softc *)arg;
814e0297d1eSnonaka struct sdmmc_intr_handler *ih;
815e0297d1eSnonaka
816ab5c3234Smlelstv mutex_enter(&sc->sc_mtx);
817e0297d1eSnonaka TAILQ_FOREACH(ih, &sc->sc_intrq, entry) {
818e0297d1eSnonaka /* XXX examine return value and do evcount stuff*/
819e0297d1eSnonaka (void)(*ih->ih_fun)(ih->ih_arg);
820e0297d1eSnonaka }
821ab5c3234Smlelstv mutex_exit(&sc->sc_mtx);
8221c4105dcSmlelstv
8231c4105dcSmlelstv sdmmc_chip_card_intr_ack(sc->sc_sct, sc->sc_sch);
824e0297d1eSnonaka }
8255ab3b2b2Smlelstv
8265ab3b2b2Smlelstv int
sdmmc_io_set_blocklen(struct sdmmc_function * sf,int blklen)82734287373Smlelstv sdmmc_io_set_blocklen(struct sdmmc_function *sf,
8285ab3b2b2Smlelstv int blklen)
8295ab3b2b2Smlelstv {
83034287373Smlelstv struct sdmmc_softc *sc = sf->sc;
8315ab3b2b2Smlelstv struct sdmmc_function *sf0 = sc->sc_fn0;
8325ab3b2b2Smlelstv int error = EINVAL;
8335ab3b2b2Smlelstv
8345ab3b2b2Smlelstv SDMMC_LOCK(sc);
8355ab3b2b2Smlelstv
8365ab3b2b2Smlelstv if (blklen <= 0 ||
8375ab3b2b2Smlelstv blklen > sdmmc_chip_host_maxblklen(sc->sc_sct, sc->sc_sch))
8385ab3b2b2Smlelstv goto err;
8395ab3b2b2Smlelstv
8405ab3b2b2Smlelstv sdmmc_io_write_1(sf0, SD_IO_FBR(sf->number) +
8415ab3b2b2Smlelstv SD_IO_FBR_BLOCKLEN, blklen & 0xff);
8425ab3b2b2Smlelstv sdmmc_io_write_1(sf0, SD_IO_FBR(sf->number) +
8435ab3b2b2Smlelstv SD_IO_FBR_BLOCKLEN + 1, (blklen >> 8) & 0xff);
8445ab3b2b2Smlelstv
8455ab3b2b2Smlelstv sf->blklen = blklen;
8465ab3b2b2Smlelstv error = 0;
8475ab3b2b2Smlelstv
8485ab3b2b2Smlelstv err:
8495ab3b2b2Smlelstv SDMMC_UNLOCK(sc);
8505ab3b2b2Smlelstv
8515ab3b2b2Smlelstv return error;
8525ab3b2b2Smlelstv }
853c301b5e4Smlelstv
854