1 | /* $NetBSD: sdmmc.c,v 1.33 2015/12/22 09:55:38 mlelstv Exp $ */ |
2 | /* $OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> |
6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. |
10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | */ |
19 | |
20 | /*- |
21 | * Copyright (C) 2007, 2008, 2009 NONAKA Kimihiro <nonaka@netbsd.org> |
22 | * All rights reserved. |
23 | * |
24 | * Redistribution and use in source and binary forms, with or without |
25 | * modification, are permitted provided that the following conditions |
26 | * are met: |
27 | * 1. Redistributions of source code must retain the above copyright |
28 | * notice, this list of conditions and the following disclaimer. |
29 | * 2. Redistributions in binary form must reproduce the above copyright |
30 | * notice, this list of conditions and the following disclaimer in the |
31 | * documentation and/or other materials provided with the distribution. |
32 | * |
33 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
34 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
35 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
36 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
37 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
38 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
39 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
40 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
41 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
42 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
43 | */ |
44 | |
45 | /* |
46 | * Host controller independent SD/MMC bus driver based on information |
47 | * from SanDisk SD Card Product Manual Revision 2.2 (SanDisk), SDIO |
48 | * Simple Specification Version 1.0 (SDIO) and the Linux "mmc" driver. |
49 | */ |
50 | |
51 | #include <sys/cdefs.h> |
52 | __KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.33 2015/12/22 09:55:38 mlelstv Exp $" ); |
53 | |
54 | #ifdef _KERNEL_OPT |
55 | #include "opt_sdmmc.h" |
56 | #endif |
57 | |
58 | #include <sys/param.h> |
59 | #include <sys/device.h> |
60 | #include <sys/kernel.h> |
61 | #include <sys/kthread.h> |
62 | #include <sys/malloc.h> |
63 | #include <sys/proc.h> |
64 | #include <sys/systm.h> |
65 | #include <sys/callout.h> |
66 | |
67 | #include <machine/vmparam.h> |
68 | |
69 | #include <dev/sdmmc/sdmmc_ioreg.h> |
70 | #include <dev/sdmmc/sdmmcchip.h> |
71 | #include <dev/sdmmc/sdmmcreg.h> |
72 | #include <dev/sdmmc/sdmmcvar.h> |
73 | |
74 | #ifdef SDMMC_DEBUG |
75 | int sdmmcdebug = 0; |
76 | static void sdmmc_dump_command(struct sdmmc_softc *, struct sdmmc_command *); |
77 | #define DPRINTF(n,s) do { if ((n) <= sdmmcdebug) printf s; } while (0) |
78 | #else |
79 | #define DPRINTF(n,s) do {} while (0) |
80 | #endif |
81 | |
82 | #define DEVNAME(sc) SDMMCDEVNAME(sc) |
83 | |
84 | static int sdmmc_match(device_t, cfdata_t, void *); |
85 | static void sdmmc_attach(device_t, device_t, void *); |
86 | static int sdmmc_detach(device_t, int); |
87 | |
88 | CFATTACH_DECL_NEW(sdmmc, sizeof(struct sdmmc_softc), |
89 | sdmmc_match, sdmmc_attach, sdmmc_detach, NULL); |
90 | |
91 | static void sdmmc_doattach(device_t); |
92 | static void sdmmc_task_thread(void *); |
93 | static void sdmmc_discover_task(void *); |
94 | static void sdmmc_polling_card(void *); |
95 | static void sdmmc_card_attach(struct sdmmc_softc *); |
96 | static void sdmmc_card_detach(struct sdmmc_softc *, int); |
97 | static int sdmmc_print(void *, const char *); |
98 | static int sdmmc_enable(struct sdmmc_softc *); |
99 | static void sdmmc_disable(struct sdmmc_softc *); |
100 | static int sdmmc_scan(struct sdmmc_softc *); |
101 | static int sdmmc_init(struct sdmmc_softc *); |
102 | |
103 | static int |
104 | sdmmc_match(device_t parent, cfdata_t cf, void *aux) |
105 | { |
106 | struct sdmmcbus_attach_args *saa = (struct sdmmcbus_attach_args *)aux; |
107 | |
108 | if (strcmp(saa->saa_busname, cf->cf_name) == 0) |
109 | return 1; |
110 | return 0; |
111 | } |
112 | |
113 | static void |
114 | sdmmc_attach(device_t parent, device_t self, void *aux) |
115 | { |
116 | struct sdmmc_softc *sc = device_private(self); |
117 | struct sdmmcbus_attach_args *saa = (struct sdmmcbus_attach_args *)aux; |
118 | int error; |
119 | |
120 | aprint_normal("\n" ); |
121 | aprint_naive("\n" ); |
122 | |
123 | sc->sc_dev = self; |
124 | sc->sc_sct = saa->saa_sct; |
125 | sc->sc_spi_sct = saa->saa_spi_sct; |
126 | sc->sc_sch = saa->saa_sch; |
127 | sc->sc_dmat = saa->saa_dmat; |
128 | sc->sc_clkmin = saa->saa_clkmin; |
129 | sc->sc_clkmax = saa->saa_clkmax; |
130 | sc->sc_busclk = sc->sc_clkmax; |
131 | sc->sc_buswidth = 1; |
132 | sc->sc_caps = saa->saa_caps; |
133 | |
134 | if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) { |
135 | error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SDMMC_MAXNSEGS, |
136 | MAXPHYS, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &sc->sc_dmap); |
137 | if (error) { |
138 | aprint_error_dev(sc->sc_dev, |
139 | "couldn't create dma map. (error=%d)\n" , error); |
140 | return; |
141 | } |
142 | } |
143 | |
144 | SIMPLEQ_INIT(&sc->sf_head); |
145 | TAILQ_INIT(&sc->sc_tskq); |
146 | TAILQ_INIT(&sc->sc_intrq); |
147 | |
148 | sdmmc_init_task(&sc->sc_discover_task, sdmmc_discover_task, sc); |
149 | sdmmc_init_task(&sc->sc_intr_task, sdmmc_intr_task, sc); |
150 | |
151 | mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NONE); |
152 | mutex_init(&sc->sc_tskq_mtx, MUTEX_DEFAULT, IPL_SDMMC); |
153 | mutex_init(&sc->sc_discover_task_mtx, MUTEX_DEFAULT, IPL_SDMMC); |
154 | mutex_init(&sc->sc_intr_task_mtx, MUTEX_DEFAULT, IPL_SDMMC); |
155 | cv_init(&sc->sc_tskq_cv, "mmctaskq" ); |
156 | |
157 | evcnt_attach_dynamic(&sc->sc_ev_xfer, EVCNT_TYPE_MISC, NULL, |
158 | device_xname(self), "xfer" ); |
159 | evcnt_attach_dynamic(&sc->sc_ev_xfer_aligned[0], EVCNT_TYPE_MISC, |
160 | &sc->sc_ev_xfer, device_xname(self), "xfer 512" ); |
161 | evcnt_attach_dynamic(&sc->sc_ev_xfer_aligned[1], EVCNT_TYPE_MISC, |
162 | &sc->sc_ev_xfer, device_xname(self), "xfer 1024" ); |
163 | evcnt_attach_dynamic(&sc->sc_ev_xfer_aligned[2], EVCNT_TYPE_MISC, |
164 | &sc->sc_ev_xfer, device_xname(self), "xfer 2048" ); |
165 | evcnt_attach_dynamic(&sc->sc_ev_xfer_aligned[3], EVCNT_TYPE_MISC, |
166 | &sc->sc_ev_xfer, device_xname(self), "xfer 4096" ); |
167 | evcnt_attach_dynamic(&sc->sc_ev_xfer_aligned[4], EVCNT_TYPE_MISC, |
168 | &sc->sc_ev_xfer, device_xname(self), "xfer 8192" ); |
169 | evcnt_attach_dynamic(&sc->sc_ev_xfer_aligned[5], EVCNT_TYPE_MISC, |
170 | &sc->sc_ev_xfer, device_xname(self), "xfer 16384" ); |
171 | evcnt_attach_dynamic(&sc->sc_ev_xfer_aligned[6], EVCNT_TYPE_MISC, |
172 | &sc->sc_ev_xfer, device_xname(self), "xfer 32768" ); |
173 | evcnt_attach_dynamic(&sc->sc_ev_xfer_aligned[7], EVCNT_TYPE_MISC, |
174 | &sc->sc_ev_xfer, device_xname(self), "xfer 65536" ); |
175 | evcnt_attach_dynamic(&sc->sc_ev_xfer_unaligned, EVCNT_TYPE_MISC, |
176 | &sc->sc_ev_xfer, device_xname(self), "xfer unaligned" ); |
177 | evcnt_attach_dynamic(&sc->sc_ev_xfer_error, EVCNT_TYPE_MISC, |
178 | &sc->sc_ev_xfer, device_xname(self), "xfer error" ); |
179 | |
180 | if (ISSET(sc->sc_caps, SMC_CAPS_POLL_CARD_DET)) { |
181 | callout_init(&sc->sc_card_detect_ch, 0); |
182 | callout_reset(&sc->sc_card_detect_ch, hz, |
183 | sdmmc_polling_card, sc); |
184 | } |
185 | |
186 | if (!pmf_device_register(self, NULL, NULL)) { |
187 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
188 | } |
189 | |
190 | SET(sc->sc_flags, SMF_INITED); |
191 | |
192 | /* |
193 | * Create the event thread that will attach and detach cards |
194 | * and perform other lengthy operations. |
195 | */ |
196 | config_pending_incr(self); |
197 | config_interrupts(self, sdmmc_doattach); |
198 | } |
199 | |
200 | static int |
201 | sdmmc_detach(device_t self, int flags) |
202 | { |
203 | struct sdmmc_softc *sc = device_private(self); |
204 | int error, i; |
205 | |
206 | mutex_enter(&sc->sc_tskq_mtx); |
207 | sc->sc_dying = 1; |
208 | cv_signal(&sc->sc_tskq_cv); |
209 | while (sc->sc_tskq_lwp != NULL) |
210 | cv_wait(&sc->sc_tskq_cv, &sc->sc_tskq_mtx); |
211 | mutex_exit(&sc->sc_tskq_mtx); |
212 | |
213 | pmf_device_deregister(self); |
214 | |
215 | error = config_detach_children(self, flags); |
216 | if (error) |
217 | return error; |
218 | |
219 | if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) { |
220 | bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap); |
221 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap); |
222 | } |
223 | |
224 | if (ISSET(sc->sc_caps, SMC_CAPS_POLL_CARD_DET)) { |
225 | callout_halt(&sc->sc_card_detect_ch, NULL); |
226 | callout_destroy(&sc->sc_card_detect_ch); |
227 | } |
228 | |
229 | cv_destroy(&sc->sc_tskq_cv); |
230 | mutex_destroy(&sc->sc_intr_task_mtx); |
231 | mutex_destroy(&sc->sc_discover_task_mtx); |
232 | mutex_destroy(&sc->sc_tskq_mtx); |
233 | mutex_destroy(&sc->sc_mtx); |
234 | |
235 | evcnt_detach(&sc->sc_ev_xfer_error); |
236 | evcnt_detach(&sc->sc_ev_xfer_unaligned); |
237 | for (i = 0; i < __arraycount(sc->sc_ev_xfer_aligned); i++) |
238 | evcnt_detach(&sc->sc_ev_xfer_aligned[i]); |
239 | evcnt_detach(&sc->sc_ev_xfer); |
240 | |
241 | return 0; |
242 | } |
243 | |
244 | static void |
245 | sdmmc_doattach(device_t dev) |
246 | { |
247 | struct sdmmc_softc *sc = device_private(dev); |
248 | |
249 | if (kthread_create(PRI_BIO, 0, NULL, |
250 | sdmmc_task_thread, sc, &sc->sc_tskq_lwp, "%s" , device_xname(dev))) { |
251 | aprint_error_dev(dev, "couldn't create task thread\n" ); |
252 | } |
253 | } |
254 | |
255 | void |
256 | sdmmc_add_task(struct sdmmc_softc *sc, struct sdmmc_task *task) |
257 | { |
258 | |
259 | mutex_enter(&sc->sc_tskq_mtx); |
260 | task->onqueue = 1; |
261 | task->sc = sc; |
262 | TAILQ_INSERT_TAIL(&sc->sc_tskq, task, next); |
263 | cv_broadcast(&sc->sc_tskq_cv); |
264 | mutex_exit(&sc->sc_tskq_mtx); |
265 | } |
266 | |
267 | static inline void |
268 | sdmmc_del_task1(struct sdmmc_softc *sc, struct sdmmc_task *task) |
269 | { |
270 | |
271 | TAILQ_REMOVE(&sc->sc_tskq, task, next); |
272 | task->sc = NULL; |
273 | task->onqueue = 0; |
274 | } |
275 | |
276 | void |
277 | sdmmc_del_task(struct sdmmc_task *task) |
278 | { |
279 | struct sdmmc_softc *sc = (struct sdmmc_softc *)task->sc; |
280 | |
281 | if (sc != NULL) { |
282 | mutex_enter(&sc->sc_tskq_mtx); |
283 | sdmmc_del_task1(sc, task); |
284 | mutex_exit(&sc->sc_tskq_mtx); |
285 | } |
286 | } |
287 | |
288 | static void |
289 | sdmmc_task_thread(void *arg) |
290 | { |
291 | struct sdmmc_softc *sc = (struct sdmmc_softc *)arg; |
292 | struct sdmmc_task *task; |
293 | |
294 | sdmmc_discover_task(sc); |
295 | config_pending_decr(sc->sc_dev); |
296 | |
297 | mutex_enter(&sc->sc_tskq_mtx); |
298 | for (;;) { |
299 | task = TAILQ_FIRST(&sc->sc_tskq); |
300 | if (task != NULL) { |
301 | sdmmc_del_task1(sc, task); |
302 | mutex_exit(&sc->sc_tskq_mtx); |
303 | (*task->func)(task->arg); |
304 | mutex_enter(&sc->sc_tskq_mtx); |
305 | } else { |
306 | /* Check for the exit condition. */ |
307 | if (sc->sc_dying) |
308 | break; |
309 | cv_wait(&sc->sc_tskq_cv, &sc->sc_tskq_mtx); |
310 | } |
311 | } |
312 | /* time to die. */ |
313 | sc->sc_dying = 0; |
314 | if (ISSET(sc->sc_flags, SMF_CARD_PRESENT)) { |
315 | /* |
316 | * sdmmc_card_detach() may issue commands, |
317 | * so temporarily drop the interrupt-blocking lock. |
318 | */ |
319 | mutex_exit(&sc->sc_tskq_mtx); |
320 | sdmmc_card_detach(sc, DETACH_FORCE); |
321 | mutex_enter(&sc->sc_tskq_mtx); |
322 | } |
323 | sc->sc_tskq_lwp = NULL; |
324 | cv_broadcast(&sc->sc_tskq_cv); |
325 | mutex_exit(&sc->sc_tskq_mtx); |
326 | kthread_exit(0); |
327 | } |
328 | |
329 | void |
330 | sdmmc_needs_discover(device_t dev) |
331 | { |
332 | struct sdmmc_softc *sc = device_private(dev); |
333 | |
334 | if (!ISSET(sc->sc_flags, SMF_INITED)) |
335 | return; |
336 | |
337 | mutex_enter(&sc->sc_discover_task_mtx); |
338 | if (!sdmmc_task_pending(&sc->sc_discover_task)) |
339 | sdmmc_add_task(sc, &sc->sc_discover_task); |
340 | mutex_exit(&sc->sc_discover_task_mtx); |
341 | } |
342 | |
343 | static void |
344 | sdmmc_discover_task(void *arg) |
345 | { |
346 | struct sdmmc_softc *sc = (struct sdmmc_softc *)arg; |
347 | int card_detect, card_present; |
348 | |
349 | mutex_enter(&sc->sc_discover_task_mtx); |
350 | card_detect = sdmmc_chip_card_detect(sc->sc_sct, sc->sc_sch); |
351 | card_present = ISSET(sc->sc_flags, SMF_CARD_PRESENT); |
352 | if (card_detect) |
353 | SET(sc->sc_flags, SMF_CARD_PRESENT); |
354 | else |
355 | CLR(sc->sc_flags, SMF_CARD_PRESENT); |
356 | mutex_exit(&sc->sc_discover_task_mtx); |
357 | |
358 | if (card_detect) { |
359 | if (!card_present) { |
360 | sdmmc_card_attach(sc); |
361 | mutex_enter(&sc->sc_discover_task_mtx); |
362 | if (!ISSET(sc->sc_flags, SMF_CARD_ATTACHED)) |
363 | CLR(sc->sc_flags, SMF_CARD_PRESENT); |
364 | mutex_exit(&sc->sc_discover_task_mtx); |
365 | } |
366 | } else { |
367 | if (card_present) |
368 | sdmmc_card_detach(sc, DETACH_FORCE); |
369 | } |
370 | } |
371 | |
372 | static void |
373 | sdmmc_polling_card(void *arg) |
374 | { |
375 | struct sdmmc_softc *sc = (struct sdmmc_softc *)arg; |
376 | int card_detect, card_present; |
377 | |
378 | mutex_enter(&sc->sc_discover_task_mtx); |
379 | card_detect = sdmmc_chip_card_detect(sc->sc_sct, sc->sc_sch); |
380 | card_present = ISSET(sc->sc_flags, SMF_CARD_PRESENT); |
381 | mutex_exit(&sc->sc_discover_task_mtx); |
382 | |
383 | if (card_detect != card_present) |
384 | sdmmc_needs_discover(sc->sc_dev); |
385 | |
386 | callout_schedule(&sc->sc_card_detect_ch, hz); |
387 | } |
388 | |
389 | /* |
390 | * Called from process context when a card is present. |
391 | */ |
392 | static void |
393 | sdmmc_card_attach(struct sdmmc_softc *sc) |
394 | { |
395 | struct sdmmc_function *sf; |
396 | struct sdmmc_attach_args saa; |
397 | int error; |
398 | |
399 | DPRINTF(1,("%s: attach card\n" , DEVNAME(sc))); |
400 | |
401 | CLR(sc->sc_flags, SMF_CARD_ATTACHED); |
402 | |
403 | /* |
404 | * Power up the card (or card stack). |
405 | */ |
406 | error = sdmmc_enable(sc); |
407 | if (error) { |
408 | if (!ISSET(sc->sc_caps, SMC_CAPS_POLL_CARD_DET)) { |
409 | aprint_error_dev(sc->sc_dev, "couldn't enable card: %d\n" , error); |
410 | } |
411 | goto err; |
412 | } |
413 | |
414 | /* |
415 | * Scan for I/O functions and memory cards on the bus, |
416 | * allocating a sdmmc_function structure for each. |
417 | */ |
418 | error = sdmmc_scan(sc); |
419 | if (error) { |
420 | aprint_error_dev(sc->sc_dev, "no functions\n" ); |
421 | goto err; |
422 | } |
423 | |
424 | /* |
425 | * Initialize the I/O functions and memory cards. |
426 | */ |
427 | error = sdmmc_init(sc); |
428 | if (error) { |
429 | aprint_error_dev(sc->sc_dev, "init failed\n" ); |
430 | goto err; |
431 | } |
432 | |
433 | SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) { |
434 | if (ISSET(sc->sc_flags, SMF_IO_MODE) && sf->number < 1) |
435 | continue; |
436 | |
437 | memset(&saa, 0, sizeof saa); |
438 | saa.manufacturer = sf->cis.manufacturer; |
439 | saa.product = sf->cis.product; |
440 | saa.interface = sf->interface; |
441 | saa.sf = sf; |
442 | |
443 | sf->child = |
444 | config_found_ia(sc->sc_dev, "sdmmc" , &saa, sdmmc_print); |
445 | } |
446 | |
447 | SET(sc->sc_flags, SMF_CARD_ATTACHED); |
448 | return; |
449 | |
450 | err: |
451 | sdmmc_card_detach(sc, DETACH_FORCE); |
452 | } |
453 | |
454 | /* |
455 | * Called from process context with DETACH_* flags from <sys/device.h> |
456 | * when cards are gone. |
457 | */ |
458 | static void |
459 | sdmmc_card_detach(struct sdmmc_softc *sc, int flags) |
460 | { |
461 | struct sdmmc_function *sf, *sfnext; |
462 | |
463 | DPRINTF(1,("%s: detach card\n" , DEVNAME(sc))); |
464 | |
465 | if (ISSET(sc->sc_flags, SMF_CARD_ATTACHED)) { |
466 | SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) { |
467 | if (sf->child != NULL) { |
468 | config_detach(sf->child, DETACH_FORCE); |
469 | sf->child = NULL; |
470 | } |
471 | } |
472 | |
473 | KASSERT(TAILQ_EMPTY(&sc->sc_intrq)); |
474 | |
475 | CLR(sc->sc_flags, SMF_CARD_ATTACHED); |
476 | } |
477 | |
478 | /* Power down. */ |
479 | sdmmc_disable(sc); |
480 | |
481 | /* Free all sdmmc_function structures. */ |
482 | for (sf = SIMPLEQ_FIRST(&sc->sf_head); sf != NULL; sf = sfnext) { |
483 | sfnext = SIMPLEQ_NEXT(sf, sf_list); |
484 | sdmmc_function_free(sf); |
485 | } |
486 | SIMPLEQ_INIT(&sc->sf_head); |
487 | sc->sc_function_count = 0; |
488 | sc->sc_fn0 = NULL; |
489 | } |
490 | |
491 | static int |
492 | sdmmc_print(void *aux, const char *pnp) |
493 | { |
494 | struct sdmmc_attach_args *sa = aux; |
495 | struct sdmmc_function *sf = sa->sf; |
496 | struct sdmmc_cis *cis = &sf->sc->sc_fn0->cis; |
497 | int i, x; |
498 | |
499 | if (pnp) { |
500 | if (sf->number == 0) |
501 | return QUIET; |
502 | |
503 | for (i = 0; i < 4 && cis->cis1_info[i]; i++) |
504 | printf("%s%s" , i ? ", " : "\"" , cis->cis1_info[i]); |
505 | if (i != 0) |
506 | printf("\"" ); |
507 | |
508 | if ((cis->manufacturer != SDMMC_VENDOR_INVALID && |
509 | cis->product != SDMMC_PRODUCT_INVALID) || |
510 | sa->interface != SD_IO_SFIC_NO_STANDARD) { |
511 | x = !!(cis->manufacturer != SDMMC_VENDOR_INVALID); |
512 | x += !!(cis->product != SDMMC_PRODUCT_INVALID); |
513 | x += !!(sa->interface != SD_IO_SFIC_NO_STANDARD); |
514 | printf("%s(" , i ? " " : "" ); |
515 | if (cis->manufacturer != SDMMC_VENDOR_INVALID) |
516 | printf("manufacturer 0x%x%s" , |
517 | cis->manufacturer, (--x == 0) ? "" : ", " ); |
518 | if (cis->product != SDMMC_PRODUCT_INVALID) |
519 | printf("product 0x%x%s" , |
520 | cis->product, (--x == 0) ? "" : ", " ); |
521 | if (sa->interface != SD_IO_SFIC_NO_STANDARD) |
522 | printf("standard function interface code 0x%x" , |
523 | sf->interface); |
524 | printf(")" ); |
525 | } |
526 | printf("%sat %s" , i ? " " : "" , pnp); |
527 | } |
528 | if (sf->number > 0) |
529 | printf(" function %d" , sf->number); |
530 | |
531 | if (!pnp) { |
532 | for (i = 0; i < 3 && cis->cis1_info[i]; i++) |
533 | printf("%s%s" , i ? ", " : " \"" , cis->cis1_info[i]); |
534 | if (i != 0) |
535 | printf("\"" ); |
536 | } |
537 | return UNCONF; |
538 | } |
539 | |
540 | static int |
541 | sdmmc_enable(struct sdmmc_softc *sc) |
542 | { |
543 | int error; |
544 | |
545 | /* |
546 | * Calculate the equivalent of the card OCR from the host |
547 | * capabilities and select the maximum supported bus voltage. |
548 | */ |
549 | error = sdmmc_chip_bus_power(sc->sc_sct, sc->sc_sch, |
550 | sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch)); |
551 | if (error) { |
552 | aprint_error_dev(sc->sc_dev, "couldn't supply bus power\n" ); |
553 | goto out; |
554 | } |
555 | |
556 | /* |
557 | * Select the minimum clock frequency. |
558 | */ |
559 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_400K, |
560 | false); |
561 | if (error) { |
562 | aprint_error_dev(sc->sc_dev, "couldn't supply clock\n" ); |
563 | goto out; |
564 | } |
565 | |
566 | /* XXX wait for card to power up */ |
567 | sdmmc_delay(100000); |
568 | |
569 | if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) { |
570 | /* Initialize SD I/O card function(s). */ |
571 | error = sdmmc_io_enable(sc); |
572 | if (error) { |
573 | DPRINTF(1, ("%s: sdmmc_io_enable failed %d\n" , DEVNAME(sc), error)); |
574 | goto out; |
575 | } |
576 | } |
577 | |
578 | /* Initialize SD/MMC memory card(s). */ |
579 | if (ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE) || |
580 | ISSET(sc->sc_flags, SMF_MEM_MODE)) { |
581 | error = sdmmc_mem_enable(sc); |
582 | if (error) { |
583 | DPRINTF(1, ("%s: sdmmc_mem_enable failed %d\n" , DEVNAME(sc), error)); |
584 | goto out; |
585 | } |
586 | } |
587 | |
588 | out: |
589 | if (error) |
590 | sdmmc_disable(sc); |
591 | return error; |
592 | } |
593 | |
594 | static void |
595 | sdmmc_disable(struct sdmmc_softc *sc) |
596 | { |
597 | /* XXX complete commands if card is still present. */ |
598 | |
599 | if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) { |
600 | /* Make sure no card is still selected. */ |
601 | (void)sdmmc_select_card(sc, NULL); |
602 | } |
603 | |
604 | /* Turn off bus power and clock. */ |
605 | (void)sdmmc_chip_bus_width(sc->sc_sct, sc->sc_sch, 1); |
606 | (void)sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_OFF, |
607 | false); |
608 | (void)sdmmc_chip_bus_power(sc->sc_sct, sc->sc_sch, 0); |
609 | sc->sc_busclk = sc->sc_clkmax; |
610 | } |
611 | |
612 | /* |
613 | * Set the lowest bus voltage supported by the card and the host. |
614 | */ |
615 | int |
616 | sdmmc_set_bus_power(struct sdmmc_softc *sc, uint32_t host_ocr, |
617 | uint32_t card_ocr) |
618 | { |
619 | uint32_t bit; |
620 | |
621 | /* Mask off unsupported voltage levels and select the lowest. */ |
622 | DPRINTF(1,("%s: host_ocr=%x " , DEVNAME(sc), host_ocr)); |
623 | host_ocr &= card_ocr; |
624 | for (bit = 4; bit < 23; bit++) { |
625 | if (ISSET(host_ocr, (1 << bit))) { |
626 | host_ocr &= (3 << bit); |
627 | break; |
628 | } |
629 | } |
630 | DPRINTF(1,("card_ocr=%x new_ocr=%x\n" , card_ocr, host_ocr)); |
631 | |
632 | if (host_ocr == 0 || |
633 | sdmmc_chip_bus_power(sc->sc_sct, sc->sc_sch, host_ocr) != 0) |
634 | return 1; |
635 | return 0; |
636 | } |
637 | |
638 | struct sdmmc_function * |
639 | sdmmc_function_alloc(struct sdmmc_softc *sc) |
640 | { |
641 | struct sdmmc_function *sf; |
642 | |
643 | sf = malloc(sizeof *sf, M_DEVBUF, M_WAITOK|M_ZERO); |
644 | if (sf == NULL) { |
645 | aprint_error_dev(sc->sc_dev, |
646 | "couldn't alloc memory (sdmmc function)\n" ); |
647 | return NULL; |
648 | } |
649 | |
650 | sf->sc = sc; |
651 | sf->number = -1; |
652 | sf->cis.manufacturer = SDMMC_VENDOR_INVALID; |
653 | sf->cis.product = SDMMC_PRODUCT_INVALID; |
654 | sf->cis.function = SDMMC_FUNCTION_INVALID; |
655 | sf->width = 1; |
656 | |
657 | if (ISSET(sc->sc_flags, SMF_MEM_MODE) && |
658 | ISSET(sc->sc_caps, SMC_CAPS_DMA) && |
659 | !ISSET(sc->sc_caps, SMC_CAPS_MULTI_SEG_DMA)) { |
660 | bus_dma_segment_t ds; |
661 | int rseg, error; |
662 | |
663 | error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, 1, |
664 | MAXPHYS, 0, BUS_DMA_WAITOK, &sf->bbuf_dmap); |
665 | if (error) |
666 | goto fail1; |
667 | error = bus_dmamem_alloc(sc->sc_dmat, MAXPHYS, |
668 | PAGE_SIZE, 0, &ds, 1, &rseg, BUS_DMA_WAITOK); |
669 | if (error) |
670 | goto fail2; |
671 | error = bus_dmamem_map(sc->sc_dmat, &ds, 1, MAXPHYS, |
672 | &sf->bbuf, BUS_DMA_WAITOK); |
673 | if (error) |
674 | goto fail3; |
675 | error = bus_dmamap_load(sc->sc_dmat, sf->bbuf_dmap, |
676 | sf->bbuf, MAXPHYS, NULL, |
677 | BUS_DMA_WAITOK|BUS_DMA_READ|BUS_DMA_WRITE); |
678 | if (error) |
679 | goto fail4; |
680 | error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, 1, |
681 | MAXPHYS, 0, BUS_DMA_WAITOK, &sf->sseg_dmap); |
682 | if (!error) |
683 | goto out; |
684 | |
685 | bus_dmamap_unload(sc->sc_dmat, sf->bbuf_dmap); |
686 | fail4: |
687 | bus_dmamem_unmap(sc->sc_dmat, sf->bbuf, MAXPHYS); |
688 | fail3: |
689 | bus_dmamem_free(sc->sc_dmat, &ds, 1); |
690 | fail2: |
691 | bus_dmamap_destroy(sc->sc_dmat, sf->bbuf_dmap); |
692 | fail1: |
693 | free(sf, M_DEVBUF); |
694 | sf = NULL; |
695 | } |
696 | out: |
697 | |
698 | return sf; |
699 | } |
700 | |
701 | void |
702 | sdmmc_function_free(struct sdmmc_function *sf) |
703 | { |
704 | struct sdmmc_softc *sc = sf->sc; |
705 | |
706 | if (ISSET(sc->sc_flags, SMF_MEM_MODE) && |
707 | ISSET(sc->sc_caps, SMC_CAPS_DMA) && |
708 | !ISSET(sc->sc_caps, SMC_CAPS_MULTI_SEG_DMA)) { |
709 | bus_dmamap_destroy(sc->sc_dmat, sf->sseg_dmap); |
710 | bus_dmamap_unload(sc->sc_dmat, sf->bbuf_dmap); |
711 | bus_dmamem_unmap(sc->sc_dmat, sf->bbuf, MAXPHYS); |
712 | bus_dmamem_free(sc->sc_dmat, |
713 | sf->bbuf_dmap->dm_segs, sf->bbuf_dmap->dm_nsegs); |
714 | bus_dmamap_destroy(sc->sc_dmat, sf->bbuf_dmap); |
715 | } |
716 | |
717 | free(sf, M_DEVBUF); |
718 | } |
719 | |
720 | /* |
721 | * Scan for I/O functions and memory cards on the bus, allocating a |
722 | * sdmmc_function structure for each. |
723 | */ |
724 | static int |
725 | sdmmc_scan(struct sdmmc_softc *sc) |
726 | { |
727 | |
728 | if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) { |
729 | /* Scan for I/O functions. */ |
730 | if (ISSET(sc->sc_flags, SMF_IO_MODE)) |
731 | sdmmc_io_scan(sc); |
732 | } |
733 | |
734 | /* Scan for memory cards on the bus. */ |
735 | if (ISSET(sc->sc_flags, SMF_MEM_MODE)) |
736 | sdmmc_mem_scan(sc); |
737 | |
738 | /* There should be at least one function now. */ |
739 | if (SIMPLEQ_EMPTY(&sc->sf_head)) { |
740 | aprint_error_dev(sc->sc_dev, "couldn't identify card\n" ); |
741 | return 1; |
742 | } |
743 | return 0; |
744 | } |
745 | |
746 | /* |
747 | * Initialize all the distinguished functions of the card, be it I/O |
748 | * or memory functions. |
749 | */ |
750 | static int |
751 | sdmmc_init(struct sdmmc_softc *sc) |
752 | { |
753 | struct sdmmc_function *sf; |
754 | |
755 | /* Initialize all identified card functions. */ |
756 | SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) { |
757 | if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) { |
758 | if (ISSET(sc->sc_flags, SMF_IO_MODE) && |
759 | sdmmc_io_init(sc, sf) != 0) { |
760 | aprint_error_dev(sc->sc_dev, |
761 | "i/o init failed\n" ); |
762 | } |
763 | } |
764 | |
765 | if (ISSET(sc->sc_flags, SMF_MEM_MODE) && |
766 | sdmmc_mem_init(sc, sf) != 0) { |
767 | aprint_error_dev(sc->sc_dev, "mem init failed\n" ); |
768 | } |
769 | } |
770 | |
771 | /* Any good functions left after initialization? */ |
772 | SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) { |
773 | if (!ISSET(sf->flags, SFF_ERROR)) |
774 | return 0; |
775 | } |
776 | |
777 | /* No, we should probably power down the card. */ |
778 | return 1; |
779 | } |
780 | |
781 | void |
782 | sdmmc_delay(u_int usecs) |
783 | { |
784 | |
785 | delay(usecs); |
786 | } |
787 | |
788 | int |
789 | sdmmc_app_command(struct sdmmc_softc *sc, struct sdmmc_function *sf, struct sdmmc_command *cmd) |
790 | { |
791 | struct sdmmc_command acmd; |
792 | int error; |
793 | |
794 | DPRINTF(1,("sdmmc_app_command: start\n" )); |
795 | |
796 | /* Don't lock */ |
797 | |
798 | memset(&acmd, 0, sizeof(acmd)); |
799 | acmd.c_opcode = MMC_APP_CMD; |
800 | acmd.c_arg = (sf != NULL) ? (sf->rca << 16) : 0; |
801 | acmd.c_flags = SCF_CMD_AC | SCF_RSP_R1 | SCF_RSP_SPI_R1 | (cmd->c_flags & SCF_TOUT_OK); |
802 | |
803 | error = sdmmc_mmc_command(sc, &acmd); |
804 | if (error == 0) { |
805 | if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE) && |
806 | !ISSET(MMC_R1(acmd.c_resp), MMC_R1_APP_CMD)) { |
807 | /* Card does not support application commands. */ |
808 | error = ENODEV; |
809 | } else { |
810 | error = sdmmc_mmc_command(sc, cmd); |
811 | } |
812 | } |
813 | DPRINTF(1,("sdmmc_app_command: done (error=%d)\n" , error)); |
814 | return error; |
815 | } |
816 | |
817 | /* |
818 | * Execute MMC command and data transfers. All interactions with the |
819 | * host controller to complete the command happen in the context of |
820 | * the current process. |
821 | */ |
822 | int |
823 | sdmmc_mmc_command(struct sdmmc_softc *sc, struct sdmmc_command *cmd) |
824 | { |
825 | int error; |
826 | |
827 | DPRINTF(1,("sdmmc_mmc_command: cmd=%d, arg=%#x, flags=%#x\n" , |
828 | cmd->c_opcode, cmd->c_arg, cmd->c_flags)); |
829 | |
830 | /* Don't lock */ |
831 | |
832 | #if defined(DIAGNOSTIC) || defined(SDMMC_DEBUG) |
833 | if (cmd->c_data && !ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) { |
834 | if (sc->sc_card == NULL) |
835 | panic("%s: deselected card\n" , DEVNAME(sc)); |
836 | } |
837 | #endif |
838 | |
839 | sdmmc_chip_exec_command(sc->sc_sct, sc->sc_sch, cmd); |
840 | |
841 | #ifdef SDMMC_DEBUG |
842 | sdmmc_dump_command(sc, cmd); |
843 | #endif |
844 | |
845 | error = cmd->c_error; |
846 | |
847 | DPRINTF(1,("sdmmc_mmc_command: error=%d\n" , error)); |
848 | |
849 | if (error && |
850 | (cmd->c_opcode == MMC_READ_BLOCK_MULTIPLE || |
851 | cmd->c_opcode == MMC_WRITE_BLOCK_MULTIPLE)) { |
852 | sdmmc_stop_transmission(sc); |
853 | } |
854 | |
855 | return error; |
856 | } |
857 | |
858 | /* |
859 | * Send the "STOP TRANSMISSION" command |
860 | */ |
861 | void |
862 | sdmmc_stop_transmission(struct sdmmc_softc *sc) |
863 | { |
864 | struct sdmmc_command cmd; |
865 | |
866 | DPRINTF(1,("sdmmc_stop_transmission\n" )); |
867 | |
868 | /* Don't lock */ |
869 | |
870 | memset(&cmd, 0, sizeof(cmd)); |
871 | cmd.c_opcode = MMC_STOP_TRANSMISSION; |
872 | cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1B | SCF_RSP_SPI_R1B; |
873 | |
874 | (void)sdmmc_mmc_command(sc, &cmd); |
875 | } |
876 | |
877 | /* |
878 | * Send the "GO IDLE STATE" command. |
879 | */ |
880 | void |
881 | sdmmc_go_idle_state(struct sdmmc_softc *sc) |
882 | { |
883 | struct sdmmc_command cmd; |
884 | |
885 | DPRINTF(1,("sdmmc_go_idle_state\n" )); |
886 | |
887 | /* Don't lock */ |
888 | |
889 | memset(&cmd, 0, sizeof(cmd)); |
890 | cmd.c_opcode = MMC_GO_IDLE_STATE; |
891 | cmd.c_flags = SCF_CMD_BC | SCF_RSP_R0 | SCF_RSP_SPI_R1; |
892 | |
893 | (void)sdmmc_mmc_command(sc, &cmd); |
894 | } |
895 | |
896 | /* |
897 | * Retrieve (SD) or set (MMC) the relative card address (RCA). |
898 | */ |
899 | int |
900 | sdmmc_set_relative_addr(struct sdmmc_softc *sc, struct sdmmc_function *sf) |
901 | { |
902 | struct sdmmc_command cmd; |
903 | int error; |
904 | |
905 | /* Don't lock */ |
906 | |
907 | if (ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) { |
908 | aprint_error_dev(sc->sc_dev, |
909 | "sdmmc_set_relative_addr: SMC_CAPS_SPI_MODE set" ); |
910 | return EIO; |
911 | } |
912 | |
913 | memset(&cmd, 0, sizeof(cmd)); |
914 | if (ISSET(sc->sc_flags, SMF_SD_MODE)) { |
915 | cmd.c_opcode = SD_SEND_RELATIVE_ADDR; |
916 | cmd.c_flags = SCF_CMD_BCR | SCF_RSP_R6; |
917 | } else { |
918 | cmd.c_opcode = MMC_SET_RELATIVE_ADDR; |
919 | cmd.c_arg = MMC_ARG_RCA(sf->rca); |
920 | cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1; |
921 | } |
922 | error = sdmmc_mmc_command(sc, &cmd); |
923 | if (error) |
924 | return error; |
925 | |
926 | if (ISSET(sc->sc_flags, SMF_SD_MODE)) |
927 | sf->rca = SD_R6_RCA(cmd.c_resp); |
928 | |
929 | return 0; |
930 | } |
931 | |
932 | int |
933 | sdmmc_select_card(struct sdmmc_softc *sc, struct sdmmc_function *sf) |
934 | { |
935 | struct sdmmc_command cmd; |
936 | int error; |
937 | |
938 | /* Don't lock */ |
939 | |
940 | if (ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) { |
941 | aprint_error_dev(sc->sc_dev, |
942 | "sdmmc_select_card: SMC_CAPS_SPI_MODE set" ); |
943 | return EIO; |
944 | } |
945 | |
946 | if (sc->sc_card == sf |
947 | || (sf && sc->sc_card && sc->sc_card->rca == sf->rca)) { |
948 | sc->sc_card = sf; |
949 | return 0; |
950 | } |
951 | |
952 | memset(&cmd, 0, sizeof(cmd)); |
953 | cmd.c_opcode = MMC_SELECT_CARD; |
954 | cmd.c_arg = (sf == NULL) ? 0 : MMC_ARG_RCA(sf->rca); |
955 | cmd.c_flags = SCF_CMD_AC | ((sf == NULL) ? SCF_RSP_R0 : SCF_RSP_R1); |
956 | error = sdmmc_mmc_command(sc, &cmd); |
957 | if (error == 0 || sf == NULL) |
958 | sc->sc_card = sf; |
959 | |
960 | return error; |
961 | } |
962 | |
963 | #ifdef SDMMC_DEBUG |
964 | static void |
965 | sdmmc_dump_command(struct sdmmc_softc *sc, struct sdmmc_command *cmd) |
966 | { |
967 | int i; |
968 | |
969 | DPRINTF(1,("%s: cmd %u arg=%#x data=%p dlen=%d flags=%#x (error %d)\n" , |
970 | DEVNAME(sc), cmd->c_opcode, cmd->c_arg, cmd->c_data, |
971 | cmd->c_datalen, cmd->c_flags, cmd->c_error)); |
972 | |
973 | if (cmd->c_error || sdmmcdebug < 1) |
974 | return; |
975 | |
976 | aprint_normal_dev(sc->sc_dev, "resp=" ); |
977 | if (ISSET(cmd->c_flags, SCF_RSP_136)) |
978 | for (i = 0; i < sizeof cmd->c_resp; i++) |
979 | aprint_normal("%02x " , ((uint8_t *)cmd->c_resp)[i]); |
980 | else if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) |
981 | for (i = 0; i < 4; i++) |
982 | aprint_normal("%02x " , ((uint8_t *)cmd->c_resp)[i]); |
983 | else |
984 | aprint_normal("none" ); |
985 | aprint_normal("\n" ); |
986 | } |
987 | |
988 | void |
989 | sdmmc_dump_data(const char *title, void *ptr, size_t size) |
990 | { |
991 | char buf[16]; |
992 | uint8_t *p = ptr; |
993 | int i, j; |
994 | |
995 | printf("sdmmc_dump_data: %s\n" , title ? title : "" ); |
996 | printf("--------+--------------------------------------------------+------------------+\n" ); |
997 | printf("offset | +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f | data |\n" ); |
998 | printf("--------+--------------------------------------------------+------------------+\n" ); |
999 | for (i = 0; i < (int)size; i++) { |
1000 | if ((i % 16) == 0) { |
1001 | printf("%08x| " , i); |
1002 | } else if ((i % 16) == 8) { |
1003 | printf(" " ); |
1004 | } |
1005 | |
1006 | printf("%02x " , p[i]); |
1007 | buf[i % 16] = p[i]; |
1008 | |
1009 | if ((i % 16) == 15) { |
1010 | printf("| " ); |
1011 | for (j = 0; j < 16; j++) { |
1012 | if (buf[j] >= 0x20 && buf[j] <= 0x7e) { |
1013 | printf("%c" , buf[j]); |
1014 | } else { |
1015 | printf("." ); |
1016 | } |
1017 | } |
1018 | printf(" |\n" ); |
1019 | } |
1020 | } |
1021 | if ((i % 16) != 0) { |
1022 | j = (i % 16); |
1023 | for (; j < 16; j++) { |
1024 | printf(" " ); |
1025 | if ((j % 16) == 8) { |
1026 | printf(" " ); |
1027 | } |
1028 | } |
1029 | |
1030 | printf("| " ); |
1031 | for (j = 0; j < (i % 16); j++) { |
1032 | if (buf[j] >= 0x20 && buf[j] <= 0x7e) { |
1033 | printf("%c" , buf[j]); |
1034 | } else { |
1035 | printf("." ); |
1036 | } |
1037 | } |
1038 | for (; j < 16; j++) { |
1039 | printf(" " ); |
1040 | } |
1041 | printf(" |\n" ); |
1042 | } |
1043 | printf("--------+--------------------------------------------------+------------------+\n" ); |
1044 | } |
1045 | #endif |
1046 | |