1 /* $OpenBSD: sdmmc_io.c,v 1.17 2009/11/11 21:59:16 jasper Exp $ */
2
3 /*
4 * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /* Routines for SD I/O cards. */
20
21 #include <sys/param.h>
22 #include <sys/device.h>
23 #include <sys/kernel.h>
24 #include <sys/malloc.h>
25 #include <sys/proc.h>
26 #include <sys/systm.h>
27
28 #include <dev/sdmmc/sdmmc_ioreg.h>
29 #include <dev/sdmmc/sdmmcchip.h>
30 #include <dev/sdmmc/sdmmcreg.h>
31 #include <dev/sdmmc/sdmmcvar.h>
32
33 struct sdmmc_intr_handler {
34 struct sdmmc_softc *ih_softc;
35 const char *ih_name;
36 int (*ih_fun)(void *);
37 void *ih_arg;
38 TAILQ_ENTRY(sdmmc_intr_handler) entry;
39 };
40
41 int sdmmc_submatch(struct device *, void *, void *);
42 int sdmmc_print(void *, const char *);
43 int sdmmc_io_rw_direct(struct sdmmc_softc *, struct sdmmc_function *,
44 int, u_char *, int);
45 int sdmmc_io_rw_extended(struct sdmmc_softc *, struct sdmmc_function *,
46 int, u_char *, int, int);
47 int sdmmc_io_xchg(struct sdmmc_softc *, struct sdmmc_function *,
48 int, u_char *);
49 void sdmmc_io_reset(struct sdmmc_softc *);
50 int sdmmc_io_send_op_cond(struct sdmmc_softc *, u_int32_t, u_int32_t *);
51
52 #ifdef SDMMC_DEBUG
53 #define DPRINTF(s) printf s
54 #else
55 #define DPRINTF(s) /**/
56 #endif
57
58 #ifdef SDMMC_DEBUG
59 int sdmmc_verbose = 1;
60 #else
61 int sdmmc_verbose = 0;
62 #endif
63
64 /*
65 * Initialize SD I/O card functions (before memory cards). The host
66 * system and controller must support card interrupts in order to use
67 * I/O functions.
68 */
69 int
sdmmc_io_enable(struct sdmmc_softc * sc)70 sdmmc_io_enable(struct sdmmc_softc *sc)
71 {
72 u_int32_t host_ocr;
73 u_int32_t card_ocr;
74
75 SDMMC_ASSERT_LOCKED(sc);
76
77 /* Set host mode to SD "combo" card. */
78 SET(sc->sc_flags, SMF_SD_MODE|SMF_IO_MODE|SMF_MEM_MODE);
79
80 /* Reset I/O functions. */
81 sdmmc_io_reset(sc);
82
83 /*
84 * Read the I/O OCR value, determine the number of I/O
85 * functions and whether memory is also present (a "combo
86 * card") by issuing CMD5. SD memory-only and MMC cards
87 * do not respond to CMD5.
88 */
89 if (sdmmc_io_send_op_cond(sc, 0, &card_ocr) != 0) {
90 /* No SDIO card; switch to SD memory-only mode. */
91 CLR(sc->sc_flags, SMF_IO_MODE);
92 return 0;
93 }
94
95 /* Parse the additional bits in the I/O OCR value. */
96 if (!ISSET(card_ocr, SD_IO_OCR_MEM_PRESENT)) {
97 /* SDIO card without memory (not a "combo card"). */
98 DPRINTF(("%s: no memory present\n", SDMMCDEVNAME(sc)));
99 CLR(sc->sc_flags, SMF_MEM_MODE);
100 }
101 sc->sc_function_count = SD_IO_OCR_NUM_FUNCTIONS(card_ocr);
102 if (sc->sc_function_count == 0) {
103 /* Useless SDIO card without any I/O functions. */
104 DPRINTF(("%s: no I/O functions\n", SDMMCDEVNAME(sc)));
105 CLR(sc->sc_flags, SMF_IO_MODE);
106 return 0;
107 }
108 card_ocr &= SD_IO_OCR_MASK;
109
110 /* Set the lowest voltage supported by the card and host. */
111 host_ocr = sdmmc_chip_host_ocr(sc->sct, sc->sch);
112 if (sdmmc_set_bus_power(sc, host_ocr, card_ocr) != 0) {
113 printf("%s: can't supply voltage requested by card\n",
114 SDMMCDEVNAME(sc));
115 return 1;
116 }
117
118 /* Reset I/O functions (again). */
119 sdmmc_io_reset(sc);
120
121 /* Send the new OCR value until all cards are ready. */
122 if (sdmmc_io_send_op_cond(sc, host_ocr, NULL) != 0) {
123 printf("%s: can't send I/O OCR\n", SDMMCDEVNAME(sc));
124 return 1;
125 }
126 return 0;
127 }
128
129 /*
130 * Allocate sdmmc_function structures for SD card I/O function
131 * (including function 0).
132 */
133 void
sdmmc_io_scan(struct sdmmc_softc * sc)134 sdmmc_io_scan(struct sdmmc_softc *sc)
135 {
136 struct sdmmc_function *sf0, *sf;
137 int i;
138
139 SDMMC_ASSERT_LOCKED(sc);
140
141 sf0 = sdmmc_function_alloc(sc);
142 sf0->number = 0;
143 if (sdmmc_set_relative_addr(sc, sf0) != 0) {
144 printf("%s: can't set I/O RCA\n", SDMMCDEVNAME(sc));
145 SET(sf0->flags, SFF_ERROR);
146 return;
147 }
148 sc->sc_fn0 = sf0;
149 SIMPLEQ_INSERT_TAIL(&sc->sf_head, sf0, sf_list);
150
151 /* Verify that the RCA has been set by selecting the card. */
152 if (sdmmc_select_card(sc, sf0) != 0) {
153 printf("%s: can't select I/O RCA %d\n", SDMMCDEVNAME(sc),
154 sf0->rca);
155 SET(sf0->flags, SFF_ERROR);
156 return;
157 }
158
159 for (i = 1; i <= sc->sc_function_count; i++) {
160 sf = sdmmc_function_alloc(sc);
161 sf->number = i;
162 sf->rca = sf0->rca;
163
164 SIMPLEQ_INSERT_TAIL(&sc->sf_head, sf, sf_list);
165 }
166 }
167
168 /*
169 * Initialize SDIO card functions.
170 */
171 int
sdmmc_io_init(struct sdmmc_softc * sc,struct sdmmc_function * sf)172 sdmmc_io_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
173 {
174 SDMMC_ASSERT_LOCKED(sc);
175
176 if (sf->number == 0) {
177 sdmmc_io_write_1(sf, SD_IO_CCCR_BUS_WIDTH,
178 CCCR_BUS_WIDTH_1);
179
180 if (sdmmc_read_cis(sf, &sf->cis) != 0) {
181 printf("%s: can't read CIS\n", SDMMCDEVNAME(sc));
182 SET(sf->flags, SFF_ERROR);
183 return 1;
184 }
185
186 sdmmc_check_cis_quirks(sf);
187
188 if (sdmmc_verbose)
189 sdmmc_print_cis(sf);
190 }
191 return 0;
192 }
193
194 /*
195 * Indicate whether the function is ready to operate.
196 */
197 int
sdmmc_io_function_ready(struct sdmmc_function * sf)198 sdmmc_io_function_ready(struct sdmmc_function *sf)
199 {
200 struct sdmmc_softc *sc = sf->sc;
201 struct sdmmc_function *sf0 = sc->sc_fn0;
202 u_int8_t rv;
203
204 SDMMC_ASSERT_LOCKED(sc);
205
206 if (sf->number == 0)
207 return 1; /* FN0 is always ready */
208
209 rv = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_READY);
210
211 return (rv & (1 << sf->number)) != 0;
212 }
213
214 /*
215 * Enable the I/O function. Return zero if the function was
216 * enabled successfully.
217 */
218 int
sdmmc_io_function_enable(struct sdmmc_function * sf)219 sdmmc_io_function_enable(struct sdmmc_function *sf)
220 {
221 struct sdmmc_softc *sc = sf->sc;
222 struct sdmmc_function *sf0 = sc->sc_fn0;
223 u_int8_t rv;
224 int retry = 5;
225
226 if (sf->number == 0)
227 return 0; /* FN0 is always enabled */
228
229 SDMMC_LOCK(sc);
230 rv = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_ENABLE);
231 rv |= (1<<sf->number);
232 sdmmc_io_write_1(sf0, SD_IO_CCCR_FN_ENABLE, rv);
233 SDMMC_UNLOCK(sc);
234
235 while (!sdmmc_io_function_ready(sf) && retry-- > 0)
236 tsleep(&lbolt, PPAUSE, "pause", 0);
237 return (retry >= 0) ? 0 : ETIMEDOUT;
238 }
239
240 /*
241 * Disable the I/O function. Return zero if the function was
242 * disabled successfully.
243 */
244 void
sdmmc_io_function_disable(struct sdmmc_function * sf)245 sdmmc_io_function_disable(struct sdmmc_function *sf)
246 {
247 struct sdmmc_softc *sc = sf->sc;
248 struct sdmmc_function *sf0 = sc->sc_fn0;
249 u_int8_t rv;
250
251 SDMMC_ASSERT_LOCKED(sc);
252
253 if (sf->number == 0)
254 return; /* FN0 is always enabled */
255
256 rv = sdmmc_io_read_1(sf0, SD_IO_CCCR_FN_ENABLE);
257 rv &= ~(1<<sf->number);
258 sdmmc_io_write_1(sf0, SD_IO_CCCR_FN_ENABLE, rv);
259 }
260
261 void
sdmmc_io_attach(struct sdmmc_softc * sc)262 sdmmc_io_attach(struct sdmmc_softc *sc)
263 {
264 struct sdmmc_function *sf;
265 struct sdmmc_attach_args saa;
266
267 SDMMC_ASSERT_LOCKED(sc);
268
269 SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
270 if (sf->number < 1)
271 continue;
272
273 bzero(&saa, sizeof saa);
274 saa.sf = sf;
275
276 sf->child = config_found_sm(&sc->sc_dev, &saa, sdmmc_print,
277 sdmmc_submatch);
278 }
279 }
280
281 int
sdmmc_submatch(struct device * parent,void * match,void * aux)282 sdmmc_submatch(struct device *parent, void *match, void *aux)
283 {
284 struct cfdata *cf = match;
285
286 /* Skip the scsibus, it is configured directly. */
287 if (strcmp(cf->cf_driver->cd_name, "scsibus") == 0)
288 return 0;
289
290 return cf->cf_attach->ca_match(parent, cf, aux);
291 }
292
293 int
sdmmc_print(void * aux,const char * pnp)294 sdmmc_print(void *aux, const char *pnp)
295 {
296 struct sdmmc_attach_args *sa = aux;
297 struct sdmmc_function *sf = sa->sf;
298 struct sdmmc_cis *cis = &sf->sc->sc_fn0->cis;
299 int i;
300
301 if (pnp) {
302 if (sf->number == 0)
303 return QUIET;
304
305 for (i = 0; i < 4 && cis->cis1_info[i]; i++)
306 printf("%s%s", i ? ", " : "\"", cis->cis1_info[i]);
307 if (i != 0)
308 printf("\"");
309
310 if (cis->manufacturer != SDMMC_VENDOR_INVALID &&
311 cis->product != SDMMC_PRODUCT_INVALID) {
312 printf("%s(", i ? " " : "");
313 if (cis->manufacturer != SDMMC_VENDOR_INVALID)
314 printf("manufacturer 0x%x%s",
315 cis->manufacturer,
316 cis->product == SDMMC_PRODUCT_INVALID ?
317 "" : ", ");
318 if (cis->product != SDMMC_PRODUCT_INVALID)
319 printf("product 0x%x", cis->product);
320 printf(")");
321 }
322 printf("%sat %s", i ? " " : "", pnp);
323 }
324 printf(" function %d", sf->number);
325
326 if (!pnp) {
327 for (i = 0; i < 3 && cis->cis1_info[i]; i++)
328 printf("%s%s", i ? ", " : " \"", cis->cis1_info[i]);
329 if (i != 0)
330 printf("\"");
331 }
332 return UNCONF;
333 }
334
335 void
sdmmc_io_detach(struct sdmmc_softc * sc)336 sdmmc_io_detach(struct sdmmc_softc *sc)
337 {
338 struct sdmmc_function *sf;
339
340 SDMMC_ASSERT_LOCKED(sc);
341
342 SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
343 if (sf->child != NULL) {
344 config_detach(sf->child, DETACH_FORCE);
345 sf->child = NULL;
346 }
347 }
348
349 KASSERT(TAILQ_EMPTY(&sc->sc_intrq));
350 }
351
352 int
sdmmc_io_rw_direct(struct sdmmc_softc * sc,struct sdmmc_function * sf,int reg,u_char * datap,int arg)353 sdmmc_io_rw_direct(struct sdmmc_softc *sc, struct sdmmc_function *sf,
354 int reg, u_char *datap, int arg)
355 {
356 struct sdmmc_command cmd;
357 int error;
358
359 SDMMC_ASSERT_LOCKED(sc);
360
361 /* Make sure the card is selected. */
362 if ((error = sdmmc_select_card(sc, sf)) != 0) {
363 SDMMC_UNLOCK(sc);
364 return error;
365 }
366
367 arg |= ((sf == NULL ? 0 : sf->number) & SD_ARG_CMD52_FUNC_MASK) <<
368 SD_ARG_CMD52_FUNC_SHIFT;
369 arg |= (reg & SD_ARG_CMD52_REG_MASK) <<
370 SD_ARG_CMD52_REG_SHIFT;
371 arg |= (*datap & SD_ARG_CMD52_DATA_MASK) <<
372 SD_ARG_CMD52_DATA_SHIFT;
373
374 bzero(&cmd, sizeof cmd);
375 cmd.c_opcode = SD_IO_RW_DIRECT;
376 cmd.c_arg = arg;
377 cmd.c_flags = SCF_CMD_AC | SCF_RSP_R5;
378
379 error = sdmmc_mmc_command(sc, &cmd);
380 *datap = SD_R5_DATA(cmd.c_resp);
381
382 return error;
383 }
384
385 /*
386 * Useful values of `arg' to pass in are either SD_ARG_CMD53_READ or
387 * SD_ARG_CMD53_WRITE. SD_ARG_CMD53_INCREMENT may be ORed into `arg'
388 * to access successive register locations instead of accessing the
389 * same register many times.
390 */
391 int
sdmmc_io_rw_extended(struct sdmmc_softc * sc,struct sdmmc_function * sf,int reg,u_char * datap,int datalen,int arg)392 sdmmc_io_rw_extended(struct sdmmc_softc *sc, struct sdmmc_function *sf,
393 int reg, u_char *datap, int datalen, int arg)
394 {
395 struct sdmmc_command cmd;
396 int error;
397
398 SDMMC_ASSERT_LOCKED(sc);
399
400 #if 0
401 /* Make sure the card is selected. */
402 if ((error = sdmmc_select_card(sc, sf)) != 0) {
403 SDMMC_UNLOCK(sc);
404 return error;
405 }
406 #endif
407
408 arg |= ((sf == NULL ? 0 : sf->number) & SD_ARG_CMD53_FUNC_MASK) <<
409 SD_ARG_CMD53_FUNC_SHIFT;
410 arg |= (reg & SD_ARG_CMD53_REG_MASK) <<
411 SD_ARG_CMD53_REG_SHIFT;
412 arg |= (datalen & SD_ARG_CMD53_LENGTH_MASK) <<
413 SD_ARG_CMD53_LENGTH_SHIFT;
414
415 bzero(&cmd, sizeof cmd);
416 cmd.c_opcode = SD_IO_RW_EXTENDED;
417 cmd.c_arg = arg;
418 cmd.c_flags = SCF_CMD_AC | SCF_RSP_R5;
419 cmd.c_data = datap;
420 cmd.c_datalen = datalen;
421 cmd.c_blklen = MIN(datalen, sdmmc_chip_host_maxblklen(sc->sct, sc->sch));
422
423 if (!ISSET(arg, SD_ARG_CMD53_WRITE))
424 cmd.c_flags |= SCF_CMD_READ;
425
426 error = sdmmc_mmc_command(sc, &cmd);
427 SDMMC_UNLOCK(sc);
428 return error;
429 }
430
431 u_int8_t
sdmmc_io_read_1(struct sdmmc_function * sf,int reg)432 sdmmc_io_read_1(struct sdmmc_function *sf, int reg)
433 {
434 u_int8_t data = 0;
435
436 SDMMC_ASSERT_LOCKED(sf->sc);
437
438 (void)sdmmc_io_rw_direct(sf->sc, sf, reg, (u_char *)&data,
439 SD_ARG_CMD52_READ);
440 return data;
441 }
442
443 void
sdmmc_io_write_1(struct sdmmc_function * sf,int reg,u_int8_t data)444 sdmmc_io_write_1(struct sdmmc_function *sf, int reg, u_int8_t data)
445 {
446 SDMMC_ASSERT_LOCKED(sf->sc);
447
448 (void)sdmmc_io_rw_direct(sf->sc, sf, reg, (u_char *)&data,
449 SD_ARG_CMD52_WRITE);
450 }
451
452 u_int16_t
sdmmc_io_read_2(struct sdmmc_function * sf,int reg)453 sdmmc_io_read_2(struct sdmmc_function *sf, int reg)
454 {
455 u_int16_t data = 0;
456
457 SDMMC_ASSERT_LOCKED(sf->sc);
458
459 (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 2,
460 SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT);
461 return data;
462 }
463
464 void
sdmmc_io_write_2(struct sdmmc_function * sf,int reg,u_int16_t data)465 sdmmc_io_write_2(struct sdmmc_function *sf, int reg, u_int16_t data)
466 {
467 SDMMC_ASSERT_LOCKED(sf->sc);
468
469 (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 2,
470 SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT);
471 }
472
473 u_int32_t
sdmmc_io_read_4(struct sdmmc_function * sf,int reg)474 sdmmc_io_read_4(struct sdmmc_function *sf, int reg)
475 {
476 u_int32_t data = 0;
477
478 SDMMC_ASSERT_LOCKED(sf->sc);
479
480 (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 4,
481 SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT);
482 return data;
483 }
484
485 void
sdmmc_io_write_4(struct sdmmc_function * sf,int reg,u_int32_t data)486 sdmmc_io_write_4(struct sdmmc_function *sf, int reg, u_int32_t data)
487 {
488 SDMMC_ASSERT_LOCKED(sf->sc);
489
490 (void)sdmmc_io_rw_extended(sf->sc, sf, reg, (u_char *)&data, 4,
491 SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT);
492 }
493
494 int
sdmmc_io_read_multi_1(struct sdmmc_function * sf,int reg,u_char * data,int datalen)495 sdmmc_io_read_multi_1(struct sdmmc_function *sf, int reg, u_char *data,
496 int datalen)
497 {
498 int error;
499
500 SDMMC_ASSERT_LOCKED(sf->sc);
501
502 while (datalen > SD_ARG_CMD53_LENGTH_MAX) {
503 error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
504 SD_ARG_CMD53_LENGTH_MAX, SD_ARG_CMD53_READ);
505 if (error)
506 return error;
507 data += SD_ARG_CMD53_LENGTH_MAX;
508 datalen -= SD_ARG_CMD53_LENGTH_MAX;
509 }
510
511 return sdmmc_io_rw_extended(sf->sc, sf, reg, data, datalen,
512 SD_ARG_CMD53_READ);
513 }
514
515 int
sdmmc_io_write_multi_1(struct sdmmc_function * sf,int reg,u_char * data,int datalen)516 sdmmc_io_write_multi_1(struct sdmmc_function *sf, int reg, u_char *data,
517 int datalen)
518 {
519 int error;
520
521 SDMMC_ASSERT_LOCKED(sf->sc);
522
523 while (datalen > SD_ARG_CMD53_LENGTH_MAX) {
524 error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
525 SD_ARG_CMD53_LENGTH_MAX, SD_ARG_CMD53_WRITE);
526 if (error)
527 return error;
528 data += SD_ARG_CMD53_LENGTH_MAX;
529 datalen -= SD_ARG_CMD53_LENGTH_MAX;
530 }
531
532 return sdmmc_io_rw_extended(sf->sc, sf, reg, data, datalen,
533 SD_ARG_CMD53_WRITE);
534 }
535
536 int
sdmmc_io_xchg(struct sdmmc_softc * sc,struct sdmmc_function * sf,int reg,u_char * datap)537 sdmmc_io_xchg(struct sdmmc_softc *sc, struct sdmmc_function *sf,
538 int reg, u_char *datap)
539 {
540
541 SDMMC_ASSERT_LOCKED(sc);
542
543 return sdmmc_io_rw_direct(sc, sf, reg, datap,
544 SD_ARG_CMD52_WRITE|SD_ARG_CMD52_EXCHANGE);
545 }
546
547 /*
548 * Reset the I/O functions of the card.
549 */
550 void
sdmmc_io_reset(struct sdmmc_softc * sc)551 sdmmc_io_reset(struct sdmmc_softc *sc)
552 {
553 #if 0 /* XXX command fails */
554 (void)sdmmc_io_write(sc, NULL, SD_IO_REG_CCCR_CTL, CCCR_CTL_RES);
555 sdmmc_delay(100000);
556 #endif
557 }
558
559 /*
560 * Get or set the card's I/O OCR value (SDIO).
561 */
562 int
sdmmc_io_send_op_cond(struct sdmmc_softc * sc,u_int32_t ocr,u_int32_t * ocrp)563 sdmmc_io_send_op_cond(struct sdmmc_softc *sc, u_int32_t ocr, u_int32_t *ocrp)
564 {
565 struct sdmmc_command cmd;
566 int error;
567 int i;
568
569 SDMMC_ASSERT_LOCKED(sc);
570
571 /*
572 * If we change the OCR value, retry the command until the OCR
573 * we receive in response has the "CARD BUSY" bit set, meaning
574 * that all cards are ready for identification.
575 */
576 for (i = 0; i < 100; i++) {
577 bzero(&cmd, sizeof cmd);
578 cmd.c_opcode = SD_IO_SEND_OP_COND;
579 cmd.c_arg = ocr;
580 cmd.c_flags = SCF_CMD_BCR | SCF_RSP_R4;
581
582 error = sdmmc_mmc_command(sc, &cmd);
583 if (error != 0)
584 break;
585 if (ISSET(MMC_R4(cmd.c_resp), SD_IO_OCR_MEM_READY) ||
586 ocr == 0)
587 break;
588 error = ETIMEDOUT;
589 sdmmc_delay(10000);
590 }
591 if (error == 0 && ocrp != NULL)
592 *ocrp = MMC_R4(cmd.c_resp);
593
594 return error;
595 }
596
597 /*
598 * Card interrupt handling
599 */
600
601 void
sdmmc_intr_enable(struct sdmmc_function * sf)602 sdmmc_intr_enable(struct sdmmc_function *sf)
603 {
604 struct sdmmc_softc *sc = sf->sc;
605 struct sdmmc_function *sf0 = sc->sc_fn0;
606 u_int8_t imask;
607
608 SDMMC_LOCK(sc);
609 imask = sdmmc_io_read_1(sf0, SD_IO_CCCR_INT_ENABLE);
610 imask |= 1 << sf->number;
611 sdmmc_io_write_1(sf0, SD_IO_CCCR_INT_ENABLE, imask);
612 SDMMC_UNLOCK(sc);
613 }
614
615 void
sdmmc_intr_disable(struct sdmmc_function * sf)616 sdmmc_intr_disable(struct sdmmc_function *sf)
617 {
618 struct sdmmc_softc *sc = sf->sc;
619 struct sdmmc_function *sf0 = sc->sc_fn0;
620 u_int8_t imask;
621
622 SDMMC_LOCK(sc);
623 imask = sdmmc_io_read_1(sf0, SD_IO_CCCR_INT_ENABLE);
624 imask &= ~(1 << sf->number);
625 sdmmc_io_write_1(sf0, SD_IO_CCCR_INT_ENABLE, imask);
626 SDMMC_UNLOCK(sc);
627 }
628
629 /*
630 * Establish a handler for the SDIO card interrupt. Because the
631 * interrupt may be shared with different SDIO functions, multiple
632 * handlers can be established.
633 */
634 void *
sdmmc_intr_establish(struct device * sdmmc,int (* fun)(void *),void * arg,const char * name)635 sdmmc_intr_establish(struct device *sdmmc, int (*fun)(void *),
636 void *arg, const char *name)
637 {
638 struct sdmmc_softc *sc = (struct sdmmc_softc *)sdmmc;
639 struct sdmmc_intr_handler *ih;
640 int s;
641
642 if (sc->sct->card_intr_mask == NULL)
643 return NULL;
644
645 ih = malloc(sizeof *ih, M_DEVBUF, M_WAITOK | M_CANFAIL | M_ZERO);
646 if (ih == NULL)
647 return NULL;
648
649 ih->ih_name = name;
650 ih->ih_softc = sc;
651 ih->ih_fun = fun;
652 ih->ih_arg = arg;
653
654 s = splhigh();
655 if (TAILQ_EMPTY(&sc->sc_intrq)) {
656 sdmmc_intr_enable(sc->sc_fn0);
657 sdmmc_chip_card_intr_mask(sc->sct, sc->sch, 1);
658 }
659 TAILQ_INSERT_TAIL(&sc->sc_intrq, ih, entry);
660 splx(s);
661 return ih;
662 }
663
664 /*
665 * Disestablish the given handler.
666 */
667 void
sdmmc_intr_disestablish(void * cookie)668 sdmmc_intr_disestablish(void *cookie)
669 {
670 struct sdmmc_intr_handler *ih = cookie;
671 struct sdmmc_softc *sc = ih->ih_softc;
672 int s;
673
674 if (sc->sct->card_intr_mask == NULL)
675 return;
676
677 s = splhigh();
678 TAILQ_REMOVE(&sc->sc_intrq, ih, entry);
679 if (TAILQ_EMPTY(&sc->sc_intrq)) {
680 sdmmc_chip_card_intr_mask(sc->sct, sc->sch, 0);
681 sdmmc_intr_disable(sc->sc_fn0);
682 }
683 splx(s);
684
685 free(ih, M_DEVBUF);
686 }
687
688 /*
689 * Call established SDIO card interrupt handlers. The host controller
690 * must call this function from its own interrupt handler to handle an
691 * SDIO interrupt from the card.
692 */
693 void
sdmmc_card_intr(struct device * sdmmc)694 sdmmc_card_intr(struct device *sdmmc)
695 {
696 struct sdmmc_softc *sc = (struct sdmmc_softc *)sdmmc;
697
698 if (sc->sct->card_intr_mask == NULL)
699 return;
700
701 if (!sdmmc_task_pending(&sc->sc_intr_task))
702 sdmmc_add_task(sc, &sc->sc_intr_task);
703 }
704
705 void
sdmmc_intr_task(void * arg)706 sdmmc_intr_task(void *arg)
707 {
708 struct sdmmc_softc *sc = arg;
709 struct sdmmc_intr_handler *ih;
710 int s;
711
712 s = splhigh();
713 TAILQ_FOREACH(ih, &sc->sc_intrq, entry) {
714 splx(s);
715
716 /* XXX examine return value and do evcount stuff*/
717 (void)ih->ih_fun(ih->ih_arg);
718
719 s = splhigh();
720 }
721 sdmmc_chip_card_intr_ack(sc->sct, sc->sch);
722 splx(s);
723 }
724