1 /*-
2 * Copyright (c) 2006 Bernd Walter. All rights reserved.
3 * Copyright (c) 2006 M. Warner Losh. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: src/sys/arm/at91/at91_mci.c,v 1.11 2008/11/25 00:13:26 imp Exp $");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bio.h>
33 #include <sys/bus.h>
34 #include <sys/conf.h>
35 #include <sys/endian.h>
36 #include <sys/kernel.h>
37 #include <sys/kthread.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/mutex.h>
42 #include <sys/queue.h>
43 #include <sys/resource.h>
44 #include <sys/rman.h>
45 #include <sys/time.h>
46 #include <sys/timetc.h>
47 #include <sys/watchdog.h>
48
49 #include <machine/bus.h>
50 #include <machine/cpu.h>
51 #include <machine/cpufunc.h>
52 #include <machine/resource.h>
53 #include <machine/frame.h>
54 #include <machine/intr.h>
55 #include <arm/at91/at91rm92reg.h>
56 #include <arm/at91/at91var.h>
57 #include <arm/at91/at91_mcireg.h>
58 #include <arm/at91/at91_pdcreg.h>
59 #include <dev/mmc/bridge.h>
60 #include <dev/mmc/mmcreg.h>
61 #include <dev/mmc/mmcbrvar.h>
62
63 #include "mmcbr_if.h"
64
65 #define BBSZ 512
66
67 struct at91_mci_softc {
68 void *intrhand; /* Interrupt handle */
69 device_t dev;
70 int flags;
71 #define CMD_STARTED 1
72 #define STOP_STARTED 2
73 struct resource *irq_res; /* IRQ resource */
74 struct resource *mem_res; /* Memory resource */
75 struct mtx sc_mtx;
76 bus_dma_tag_t dmatag;
77 bus_dmamap_t map;
78 int mapped;
79 struct mmc_host host;
80 int wire4;
81 int bus_busy;
82 struct mmc_request *req;
83 struct mmc_command *curcmd;
84 char bounce_buffer[BBSZ];
85 };
86
87 static inline uint32_t
88 RD4(struct at91_mci_softc *sc, bus_size_t off)
89 {
90 return bus_read_4(sc->mem_res, off);
91 }
92
93 static inline void
94 WR4(struct at91_mci_softc *sc, bus_size_t off, uint32_t val)
95 {
96 bus_write_4(sc->mem_res, off, val);
97 }
98
99 /* bus entry points */
100 static int at91_mci_probe(device_t dev);
101 static int at91_mci_attach(device_t dev);
102 static int at91_mci_detach(device_t dev);
103 static void at91_mci_intr(void *);
104
105 /* helper routines */
106 static int at91_mci_activate(device_t dev);
107 static void at91_mci_deactivate(device_t dev);
108
109 #define AT91_MCI_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
110 #define AT91_MCI_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
111 #define AT91_MCI_LOCK_INIT(_sc) \
112 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
113 "mci", MTX_DEF)
114 #define AT91_MCI_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
115 #define AT91_MCI_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
116 #define AT91_MCI_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
117
118 static void
119 at91_mci_pdc_disable(struct at91_mci_softc *sc)
120 {
121 WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
122 WR4(sc, PDC_RPR, 0);
123 WR4(sc, PDC_RCR, 0);
124 WR4(sc, PDC_RNPR, 0);
125 WR4(sc, PDC_RNCR, 0);
126 WR4(sc, PDC_TPR, 0);
127 WR4(sc, PDC_TCR, 0);
128 WR4(sc, PDC_TNPR, 0);
129 WR4(sc, PDC_TNCR, 0);
130 }
131
132 static void
133 at91_mci_init(device_t dev)
134 {
135 struct at91_mci_softc *sc = device_get_softc(dev);
136
137 WR4(sc, MCI_CR, MCI_CR_MCIEN); /* Enable controller */
138 WR4(sc, MCI_IDR, 0xffffffff); /* Turn off interrupts */
139 WR4(sc, MCI_DTOR, MCI_DTOR_DTOMUL_1M | 1);
140 WR4(sc, MCI_MR, 0x834a); // XXX GROSS HACK FROM LINUX
141 WR4(sc, MCI_SDCR, 0); /* SLOT A, 1 bit bus */
142 }
143
144 static void
145 at91_mci_fini(device_t dev)
146 {
147 struct at91_mci_softc *sc = device_get_softc(dev);
148
149 WR4(sc, MCI_IDR, 0xffffffff); /* Turn off interrupts */
150 at91_mci_pdc_disable(sc);
151 WR4(sc, MCI_CR, MCI_CR_MCIDIS | MCI_CR_SWRST); /* Put the device into reset */
152 }
153
154 static int
155 at91_mci_probe(device_t dev)
156 {
157
158 device_set_desc(dev, "MCI mmc/sd host bridge");
159 return (0);
160 }
161
162 static int
163 at91_mci_attach(device_t dev)
164 {
165 struct at91_mci_softc *sc = device_get_softc(dev);
166 int err;
167 device_t child;
168
169 sc->dev = dev;
170 err = at91_mci_activate(dev);
171 if (err)
172 goto out;
173
174 AT91_MCI_LOCK_INIT(sc);
175
176 /*
177 * Allocate DMA tags and maps
178 */
179 err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
180 BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MAXPHYS, 1,
181 MAXPHYS, BUS_DMA_ALLOCNOW, NULL, NULL, &sc->dmatag);
182 if (err != 0)
183 goto out;
184
185 err = bus_dmamap_create(sc->dmatag, 0, &sc->map);
186 if (err != 0)
187 goto out;
188
189 at91_mci_fini(dev);
190 at91_mci_init(dev);
191
192 /*
193 * Activate the interrupt
194 */
195 err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
196 NULL, at91_mci_intr, sc, &sc->intrhand);
197 if (err) {
198 AT91_MCI_LOCK_DESTROY(sc);
199 goto out;
200 }
201 sc->host.f_min = 375000;
202 sc->host.f_max = 30000000;
203 sc->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
204 sc->host.caps = MMC_CAP_4_BIT_DATA;
205 child = device_add_child(dev, "mmc", 0);
206 device_set_ivars(dev, &sc->host);
207 err = bus_generic_attach(dev);
208 out:;
209 if (err)
210 at91_mci_deactivate(dev);
211 return (err);
212 }
213
214 static int
215 at91_mci_detach(device_t dev)
216 {
217 at91_mci_fini(dev);
218 at91_mci_deactivate(dev);
219 return (EBUSY); /* XXX */
220 }
221
222 static int
223 at91_mci_activate(device_t dev)
224 {
225 struct at91_mci_softc *sc;
226 int rid;
227
228 sc = device_get_softc(dev);
229 rid = 0;
230 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
231 RF_ACTIVE);
232 if (sc->mem_res == NULL)
233 goto errout;
234 rid = 0;
235 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
236 RF_ACTIVE);
237 if (sc->irq_res == NULL)
238 goto errout;
239 return (0);
240 errout:
241 at91_mci_deactivate(dev);
242 return (ENOMEM);
243 }
244
245 static void
246 at91_mci_deactivate(device_t dev)
247 {
248 struct at91_mci_softc *sc;
249
250 sc = device_get_softc(dev);
251 if (sc->intrhand)
252 bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
253 sc->intrhand = 0;
254 bus_generic_detach(sc->dev);
255 if (sc->mem_res)
256 bus_release_resource(dev, SYS_RES_IOPORT,
257 rman_get_rid(sc->mem_res), sc->mem_res);
258 sc->mem_res = 0;
259 if (sc->irq_res)
260 bus_release_resource(dev, SYS_RES_IRQ,
261 rman_get_rid(sc->irq_res), sc->irq_res);
262 sc->irq_res = 0;
263 return;
264 }
265
266 static void
267 at91_mci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
268 {
269 if (error != 0)
270 return;
271 *(bus_addr_t *)arg = segs[0].ds_addr;
272 }
273
274 static int
275 at91_mci_update_ios(device_t brdev, device_t reqdev)
276 {
277 uint32_t at91_master_clock = AT91C_MASTER_CLOCK;
278 struct at91_mci_softc *sc;
279 struct mmc_host *host;
280 struct mmc_ios *ios;
281 uint32_t clkdiv;
282
283 sc = device_get_softc(brdev);
284 host = &sc->host;
285 ios = &host->ios;
286 // bus mode?
287 if (ios->clock == 0) {
288 WR4(sc, MCI_CR, MCI_CR_MCIDIS);
289 clkdiv = 0;
290 } else {
291 WR4(sc, MCI_CR, MCI_CR_MCIEN);
292 if ((at91_master_clock % (ios->clock * 2)) == 0)
293 clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
294 else
295 clkdiv = (at91_master_clock / ios->clock) / 2;
296 }
297 if (ios->bus_width == bus_width_4 && sc->wire4)
298 WR4(sc, MCI_SDCR, RD4(sc, MCI_SDCR) | MCI_SDCR_SDCBUS);
299 else
300 WR4(sc, MCI_SDCR, RD4(sc, MCI_SDCR) & ~MCI_SDCR_SDCBUS);
301 WR4(sc, MCI_MR, (RD4(sc, MCI_MR) & ~MCI_MR_CLKDIV) | clkdiv);
302 /* XXX We need to turn the device on/off here with a GPIO pin */
303 return (0);
304 }
305
306 static void
307 at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd)
308 {
309 uint32_t cmdr, ier = 0, mr;
310 uint32_t *src, *dst;
311 int i;
312 struct mmc_data *data;
313 struct mmc_request *req;
314 size_t block_size = 1 << 9; // Fixed, per mmc/sd spec for 2GB cards
315 void *vaddr;
316 bus_addr_t paddr;
317
318 sc->curcmd = cmd;
319 data = cmd->data;
320 cmdr = cmd->opcode;
321 req = cmd->mrq;
322 if (MMC_RSP(cmd->flags) == MMC_RSP_NONE)
323 cmdr |= MCI_CMDR_RSPTYP_NO;
324 else {
325 /* Allow big timeout for responses */
326 cmdr |= MCI_CMDR_MAXLAT;
327 if (cmd->flags & MMC_RSP_136)
328 cmdr |= MCI_CMDR_RSPTYP_136;
329 else
330 cmdr |= MCI_CMDR_RSPTYP_48;
331 }
332 if (cmd->opcode == MMC_STOP_TRANSMISSION)
333 cmdr |= MCI_CMDR_TRCMD_STOP;
334 if (sc->host.ios.bus_mode == opendrain)
335 cmdr |= MCI_CMDR_OPDCMD;
336 if (!data) {
337 // The no data case is fairly simple
338 at91_mci_pdc_disable(sc);
339 // printf("CMDR %x ARGR %x\n", cmdr, cmd->arg);
340 WR4(sc, MCI_ARGR, cmd->arg);
341 WR4(sc, MCI_CMDR, cmdr);
342 WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_CMDRDY);
343 return;
344 }
345 if (data->flags & MMC_DATA_READ)
346 cmdr |= MCI_CMDR_TRDIR;
347 if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE))
348 cmdr |= MCI_CMDR_TRCMD_START;
349 if (data->flags & MMC_DATA_STREAM)
350 cmdr |= MCI_CMDR_TRTYP_STREAM;
351 if (data->flags & MMC_DATA_MULTI)
352 cmdr |= MCI_CMDR_TRTYP_MULTIPLE;
353 // Set block size and turn on PDC mode for dma xfer and disable
354 // PDC until we're ready.
355 mr = RD4(sc, MCI_MR) & ~MCI_MR_BLKLEN;
356 WR4(sc, MCI_MR, mr | (block_size << 16) | MCI_MR_PDCMODE);
357 WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS);
358 if (cmdr & MCI_CMDR_TRCMD_START) {
359 if (cmdr & MCI_CMDR_TRDIR)
360 vaddr = cmd->data->data;
361 else {
362 if (data->len != BBSZ)
363 panic("Write multiblock write support");
364 vaddr = sc->bounce_buffer;
365 src = (uint32_t *)cmd->data->data;
366 dst = (uint32_t *)vaddr;
367 for (i = 0; i < data->len / 4; i++)
368 dst[i] = bswap32(src[i]);
369 }
370 data->xfer_len = 0;
371 if (bus_dmamap_load(sc->dmatag, sc->map, vaddr, data->len,
372 at91_mci_getaddr, &paddr, 0) != 0) {
373 if (req->cmd->flags & STOP_STARTED)
374 req->stop->error = MMC_ERR_NO_MEMORY;
375 else
376 req->cmd->error = MMC_ERR_NO_MEMORY;
377 sc->req = NULL;
378 sc->curcmd = NULL;
379 req->done(req);
380 return;
381 }
382 sc->mapped++;
383 if (cmdr & MCI_CMDR_TRDIR) {
384 bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_PREREAD);
385 WR4(sc, PDC_RPR, paddr);
386 WR4(sc, PDC_RCR, data->len / 4);
387 ier = MCI_SR_ENDRX;
388 } else {
389 bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_PREWRITE);
390 WR4(sc, PDC_TPR, paddr);
391 WR4(sc, PDC_TCR, data->len / 4);
392 ier = MCI_SR_TXBUFE;
393 }
394 }
395 // printf("CMDR %x ARGR %x with data\n", cmdr, cmd->arg);
396 WR4(sc, MCI_ARGR, cmd->arg);
397 if (cmdr & MCI_CMDR_TRCMD_START) {
398 if (cmdr & MCI_CMDR_TRDIR) {
399 WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN);
400 WR4(sc, MCI_CMDR, cmdr);
401 } else {
402 WR4(sc, MCI_CMDR, cmdr);
403 WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN);
404 }
405 }
406 WR4(sc, MCI_IER, MCI_SR_ERROR | ier);
407 }
408
409 static void
410 at91_mci_start(struct at91_mci_softc *sc)
411 {
412 struct mmc_request *req;
413
414 req = sc->req;
415 if (req == NULL)
416 return;
417 // assert locked
418 if (!(sc->flags & CMD_STARTED)) {
419 sc->flags |= CMD_STARTED;
420 // printf("Starting CMD\n");
421 at91_mci_start_cmd(sc, req->cmd);
422 return;
423 }
424 if (!(sc->flags & STOP_STARTED) && req->stop) {
425 // printf("Starting Stop\n");
426 sc->flags |= STOP_STARTED;
427 at91_mci_start_cmd(sc, req->stop);
428 return;
429 }
430 /* We must be done -- bad idea to do this while locked? */
431 sc->req = NULL;
432 sc->curcmd = NULL;
433 req->done(req);
434 }
435
436 static int
437 at91_mci_request(device_t brdev, device_t reqdev, struct mmc_request *req)
438 {
439 struct at91_mci_softc *sc = device_get_softc(brdev);
440
441 AT91_MCI_LOCK(sc);
442 // XXX do we want to be able to queue up multiple commands?
443 // XXX sounds like a good idea, but all protocols are sync, so
444 // XXX maybe the idea is naive...
445 if (sc->req != NULL) {
446 AT91_MCI_UNLOCK(sc);
447 return EBUSY;
448 }
449 sc->req = req;
450 sc->flags = 0;
451 at91_mci_start(sc);
452 AT91_MCI_UNLOCK(sc);
453 return (0);
454 }
455
456 static int
457 at91_mci_get_ro(device_t brdev, device_t reqdev)
458 {
459 return (0);
460 }
461
462 static int
463 at91_mci_acquire_host(device_t brdev, device_t reqdev)
464 {
465 struct at91_mci_softc *sc = device_get_softc(brdev);
466 int err = 0;
467
468 AT91_MCI_LOCK(sc);
469 while (sc->bus_busy)
470 msleep(sc, &sc->sc_mtx, PZERO, "mciah", hz / 5);
471 sc->bus_busy++;
472 AT91_MCI_UNLOCK(sc);
473 return (err);
474 }
475
476 static int
477 at91_mci_release_host(device_t brdev, device_t reqdev)
478 {
479 struct at91_mci_softc *sc = device_get_softc(brdev);
480
481 AT91_MCI_LOCK(sc);
482 sc->bus_busy--;
483 wakeup(sc);
484 AT91_MCI_UNLOCK(sc);
485 return (0);
486 }
487
488 static void
489 at91_mci_read_done(struct at91_mci_softc *sc)
490 {
491 uint32_t *walker;
492 struct mmc_command *cmd;
493 int i, len;
494
495 cmd = sc->curcmd;
496 bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_POSTREAD);
497 bus_dmamap_unload(sc->dmatag, sc->map);
498 sc->mapped--;
499 walker = (uint32_t *)cmd->data->data;
500 len = cmd->data->len / 4;
501 for (i = 0; i < len; i++)
502 walker[i] = bswap32(walker[i]);
503 // Finish up the sequence...
504 WR4(sc, MCI_IDR, MCI_SR_ENDRX);
505 WR4(sc, MCI_IER, MCI_SR_RXBUFF);
506 WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS);
507 }
508
509 static void
510 at91_mci_xmit_done(struct at91_mci_softc *sc)
511 {
512 // Finish up the sequence...
513 WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS);
514 WR4(sc, MCI_IDR, MCI_SR_TXBUFE);
515 WR4(sc, MCI_IER, MCI_SR_NOTBUSY);
516 bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_POSTWRITE);
517 bus_dmamap_unload(sc->dmatag, sc->map);
518 sc->mapped--;
519 }
520
521 static void
522 at91_mci_intr(void *arg)
523 {
524 struct at91_mci_softc *sc = (struct at91_mci_softc*)arg;
525 uint32_t sr;
526 int i, done = 0;
527 struct mmc_command *cmd;
528
529 AT91_MCI_LOCK(sc);
530 sr = RD4(sc, MCI_SR) & RD4(sc, MCI_IMR);
531 // printf("i 0x%x\n", sr);
532 cmd = sc->curcmd;
533 if (sr & MCI_SR_ERROR) {
534 // Ignore CRC errors on CMD2 and ACMD47, per relevant standards
535 if ((sr & MCI_SR_RCRCE) && (cmd->opcode == MMC_SEND_OP_COND ||
536 cmd->opcode == ACMD_SD_SEND_OP_COND))
537 cmd->error = MMC_ERR_NONE;
538 else if (sr & (MCI_SR_RTOE | MCI_SR_DTOE))
539 cmd->error = MMC_ERR_TIMEOUT;
540 else if (sr & (MCI_SR_RCRCE | MCI_SR_DCRCE))
541 cmd->error = MMC_ERR_BADCRC;
542 else if (sr & (MCI_SR_OVRE | MCI_SR_UNRE))
543 cmd->error = MMC_ERR_FIFO;
544 else
545 cmd->error = MMC_ERR_FAILED;
546 done = 1;
547 if (sc->mapped && cmd->error) {
548 bus_dmamap_unload(sc->dmatag, sc->map);
549 sc->mapped--;
550 }
551 } else {
552 if (sr & MCI_SR_TXBUFE) {
553 // printf("TXBUFE\n");
554 at91_mci_xmit_done(sc);
555 }
556 if (sr & MCI_SR_RXBUFF) {
557 // printf("RXBUFF\n");
558 WR4(sc, MCI_IDR, MCI_SR_RXBUFF);
559 WR4(sc, MCI_IER, MCI_SR_CMDRDY);
560 }
561 if (sr & MCI_SR_ENDTX) {
562 // printf("ENDTX\n");
563 }
564 if (sr & MCI_SR_ENDRX) {
565 // printf("ENDRX\n");
566 at91_mci_read_done(sc);
567 }
568 if (sr & MCI_SR_NOTBUSY) {
569 // printf("NOTBUSY\n");
570 WR4(sc, MCI_IDR, MCI_SR_NOTBUSY);
571 WR4(sc, MCI_IER, MCI_SR_CMDRDY);
572 }
573 if (sr & MCI_SR_DTIP) {
574 // printf("Data transfer in progress\n");
575 }
576 if (sr & MCI_SR_BLKE) {
577 // printf("Block transfer end\n");
578 }
579 if (sr & MCI_SR_TXRDY) {
580 // printf("Ready to transmit\n");
581 }
582 if (sr & MCI_SR_RXRDY) {
583 // printf("Ready to receive\n");
584 }
585 if (sr & MCI_SR_CMDRDY) {
586 // printf("Command ready\n");
587 done = 1;
588 cmd->error = MMC_ERR_NONE;
589 }
590 }
591 if (done) {
592 WR4(sc, MCI_IDR, 0xffffffff);
593 if (cmd != NULL && (cmd->flags & MMC_RSP_PRESENT)) {
594 for (i = 0; i < ((cmd->flags & MMC_RSP_136) ? 4 : 1);
595 i++) {
596 cmd->resp[i] = RD4(sc, MCI_RSPR + i * 4);
597 // printf("RSPR[%d] = %x\n", i, cmd->resp[i]);
598 }
599 }
600 at91_mci_start(sc);
601 }
602 AT91_MCI_UNLOCK(sc);
603 }
604
605 static int
606 at91_mci_read_ivar(device_t bus, device_t child, int which, u_char *result)
607 {
608 struct at91_mci_softc *sc = device_get_softc(bus);
609
610 switch (which) {
611 default:
612 return (EINVAL);
613 case MMCBR_IVAR_BUS_MODE:
614 *(int *)result = sc->host.ios.bus_mode;
615 break;
616 case MMCBR_IVAR_BUS_WIDTH:
617 *(int *)result = sc->host.ios.bus_width;
618 break;
619 case MMCBR_IVAR_CHIP_SELECT:
620 *(int *)result = sc->host.ios.chip_select;
621 break;
622 case MMCBR_IVAR_CLOCK:
623 *(int *)result = sc->host.ios.clock;
624 break;
625 case MMCBR_IVAR_F_MIN:
626 *(int *)result = sc->host.f_min;
627 break;
628 case MMCBR_IVAR_F_MAX:
629 *(int *)result = sc->host.f_max;
630 break;
631 case MMCBR_IVAR_HOST_OCR:
632 *(int *)result = sc->host.host_ocr;
633 break;
634 case MMCBR_IVAR_MODE:
635 *(int *)result = sc->host.mode;
636 break;
637 case MMCBR_IVAR_OCR:
638 *(int *)result = sc->host.ocr;
639 break;
640 case MMCBR_IVAR_POWER_MODE:
641 *(int *)result = sc->host.ios.power_mode;
642 break;
643 case MMCBR_IVAR_VDD:
644 *(int *)result = sc->host.ios.vdd;
645 break;
646 case MMCBR_IVAR_MAX_DATA:
647 *(int *)result = 1;
648 break;
649 }
650 return (0);
651 }
652
653 static int
654 at91_mci_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
655 {
656 struct at91_mci_softc *sc = device_get_softc(bus);
657
658 switch (which) {
659 default:
660 return (EINVAL);
661 case MMCBR_IVAR_BUS_MODE:
662 sc->host.ios.bus_mode = value;
663 break;
664 case MMCBR_IVAR_BUS_WIDTH:
665 sc->host.ios.bus_width = value;
666 break;
667 case MMCBR_IVAR_CHIP_SELECT:
668 sc->host.ios.chip_select = value;
669 break;
670 case MMCBR_IVAR_CLOCK:
671 sc->host.ios.clock = value;
672 break;
673 case MMCBR_IVAR_MODE:
674 sc->host.mode = value;
675 break;
676 case MMCBR_IVAR_OCR:
677 sc->host.ocr = value;
678 break;
679 case MMCBR_IVAR_POWER_MODE:
680 sc->host.ios.power_mode = value;
681 break;
682 case MMCBR_IVAR_VDD:
683 sc->host.ios.vdd = value;
684 break;
685 /* These are read-only */
686 case MMCBR_IVAR_HOST_OCR:
687 case MMCBR_IVAR_F_MIN:
688 case MMCBR_IVAR_F_MAX:
689 case MMCBR_IVAR_MAX_DATA:
690 return (EINVAL);
691 }
692 return (0);
693 }
694
695 static device_method_t at91_mci_methods[] = {
696 /* device_if */
697 DEVMETHOD(device_probe, at91_mci_probe),
698 DEVMETHOD(device_attach, at91_mci_attach),
699 DEVMETHOD(device_detach, at91_mci_detach),
700
701 /* Bus interface */
702 DEVMETHOD(bus_read_ivar, at91_mci_read_ivar),
703 DEVMETHOD(bus_write_ivar, at91_mci_write_ivar),
704
705 /* mmcbr_if */
706 DEVMETHOD(mmcbr_update_ios, at91_mci_update_ios),
707 DEVMETHOD(mmcbr_request, at91_mci_request),
708 DEVMETHOD(mmcbr_get_ro, at91_mci_get_ro),
709 DEVMETHOD(mmcbr_acquire_host, at91_mci_acquire_host),
710 DEVMETHOD(mmcbr_release_host, at91_mci_release_host),
711
712 {0, 0},
713 };
714
715 static driver_t at91_mci_driver = {
716 "at91_mci",
717 at91_mci_methods,
718 sizeof(struct at91_mci_softc),
719 };
720 static devclass_t at91_mci_devclass;
721
722
723 DRIVER_MODULE(at91_mci, atmelarm, at91_mci_driver, at91_mci_devclass, 0, 0);
724 Cache object: 9ff0e385801985060c32fe684fa25c81
|