xref: /netbsd-src/sys/dev/sdmmc/sdmmc_io.c (revision cc534ef5d96ce53b945aad1208c11a16859b8009)
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