2 * OMAP on-chip MMC/SD host emulation.
4 * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26 target_phys_addr_t base
;
46 uint16_t blen_counter
;
48 uint16_t nblk_counter
;
58 static void omap_mmc_interrupts_update(struct omap_mmc_s
*s
)
60 qemu_set_irq(s
->irq
, !!(s
->status
& s
->mask
));
63 static void omap_mmc_fifolevel_update(struct omap_mmc_s
*host
)
65 if (!host
->transfer
&& !host
->fifo_len
) {
66 host
->status
&= 0xf3ff;
70 if (host
->fifo_len
> host
->af_level
&& host
->ddir
) {
72 host
->status
&= 0xfbff;
73 qemu_irq_raise(host
->dma
[1]);
75 host
->status
|= 0x0400;
77 host
->status
&= 0xfbff;
78 qemu_irq_lower(host
->dma
[1]);
81 if (host
->fifo_len
< host
->ae_level
&& !host
->ddir
) {
83 host
->status
&= 0xf7ff;
84 qemu_irq_raise(host
->dma
[0]);
86 host
->status
|= 0x0800;
88 qemu_irq_lower(host
->dma
[0]);
89 host
->status
&= 0xf7ff;
94 sd_nore
= 0, /* no response */
95 sd_r1
, /* normal response command */
96 sd_r2
, /* CID, CSD registers */
97 sd_r3
, /* OCR register */
98 sd_r6
= 6, /* Published RCA response */
102 static void omap_mmc_command(struct omap_mmc_s
*host
, int cmd
, int dir
,
103 sd_cmd_type_t type
, int busy
, sd_rsp_type_t resptype
, int init
)
105 uint32_t rspstatus
, mask
;
107 struct sd_request_s request
;
108 uint8_t response
[16];
110 if (resptype
== sd_r1
&& busy
)
113 if (type
== sd_adtc
) {
114 host
->fifo_start
= 0;
125 request
.arg
= host
->arg
;
126 request
.crc
= 0; /* FIXME */
128 rsplen
= sd_do_command(host
->card
, &request
, response
);
130 /* TODO: validate CRCs */
144 mask
= OUT_OF_RANGE
| ADDRESS_ERROR
| BLOCK_LEN_ERROR
|
145 ERASE_SEQ_ERROR
| ERASE_PARAM
| WP_VIOLATION
|
146 LOCK_UNLOCK_FAILED
| COM_CRC_ERROR
| ILLEGAL_COMMAND
|
147 CARD_ECC_FAILED
| CC_ERROR
| SD_ERROR
|
149 if (host
->sdio
& (1 << 13))
150 mask
|= AKE_SEQ_ERROR
;
151 rspstatus
= (response
[0] << 24) | (response
[1] << 16) |
152 (response
[2] << 8) | (response
[3] << 0);
170 rspstatus
= (response
[0] << 24) | (response
[1] << 16) |
171 (response
[2] << 8) | (response
[3] << 0);
172 if (rspstatus
& 0x80000000)
173 host
->status
&= 0xe000;
175 host
->status
|= 0x1000;
185 mask
= 0xe000 | AKE_SEQ_ERROR
;
186 rspstatus
= (response
[2] << 8) | (response
[3] << 0);
189 if (rspstatus
& mask
)
190 host
->status
|= 0x4000;
192 host
->status
&= 0xb000;
195 for (rsplen
= 0; rsplen
< 8; rsplen
++)
196 host
->rsp
[~rsplen
& 7] = response
[(rsplen
<< 1) | 1] |
197 (response
[(rsplen
<< 1) | 0] << 8);
200 host
->status
|= 0x0080;
202 host
->status
|= 0x0005; /* Makes it more real */
204 host
->status
|= 0x0001;
207 static void omap_mmc_transfer(struct omap_mmc_s
*host
)
216 if (host
->fifo_len
> host
->af_level
)
219 value
= sd_read_data(host
->card
);
220 host
->fifo
[(host
->fifo_start
+ host
->fifo_len
) & 31] = value
;
221 if (-- host
->blen_counter
) {
222 value
= sd_read_data(host
->card
);
223 host
->fifo
[(host
->fifo_start
+ host
->fifo_len
) & 31] |=
225 host
->blen_counter
--;
233 value
= host
->fifo
[host
->fifo_start
] & 0xff;
234 sd_write_data(host
->card
, value
);
235 if (-- host
->blen_counter
) {
236 value
= host
->fifo
[host
->fifo_start
] >> 8;
237 sd_write_data(host
->card
, value
);
238 host
->blen_counter
--;
243 host
->fifo_start
&= 31;
246 if (host
->blen_counter
== 0) {
247 host
->nblk_counter
--;
248 host
->blen_counter
= host
->blen
;
250 if (host
->nblk_counter
== 0) {
251 host
->nblk_counter
= host
->nblk
;
253 host
->status
|= 0x0008;
260 static void omap_mmc_update(void *opaque
)
262 struct omap_mmc_s
*s
= opaque
;
263 omap_mmc_transfer(s
);
264 omap_mmc_fifolevel_update(s
);
265 omap_mmc_interrupts_update(s
);
268 static uint32_t omap_mmc_read(void *opaque
, target_phys_addr_t offset
)
271 struct omap_mmc_s
*s
= (struct omap_mmc_s
*) opaque
;
272 offset
&= OMAP_MPUI_REG_MASK
;
275 case 0x00: /* MMC_CMD */
278 case 0x04: /* MMC_ARGL */
279 return s
->arg
& 0x0000ffff;
281 case 0x08: /* MMC_ARGH */
284 case 0x0c: /* MMC_CON */
285 return (s
->dw
<< 15) | (s
->mode
<< 12) | (s
->enable
<< 11);
287 case 0x10: /* MMC_STAT */
290 case 0x14: /* MMC_IE */
293 case 0x18: /* MMC_CTO */
296 case 0x1c: /* MMC_DTO */
299 case 0x20: /* MMC_DATA */
300 /* TODO: support 8-bit access */
301 i
= s
->fifo
[s
->fifo_start
];
302 if (s
->fifo_len
== 0) {
303 printf("MMC: FIFO underrun\n");
309 omap_mmc_transfer(s
);
310 omap_mmc_fifolevel_update(s
);
311 omap_mmc_interrupts_update(s
);
314 case 0x24: /* MMC_BLEN */
315 return s
->blen_counter
;
317 case 0x28: /* MMC_NBLK */
318 return s
->nblk_counter
;
320 case 0x2c: /* MMC_BUF */
321 return (s
->rx_dma
<< 15) | (s
->af_level
<< 8) |
322 (s
->tx_dma
<< 7) | s
->ae_level
;
324 case 0x30: /* MMC_SPI */
326 case 0x34: /* MMC_SDIO */
328 case 0x38: /* MMC_SYST */
331 case 0x3c: /* MMC_REV */
334 case 0x40: /* MMC_RSP0 */
335 case 0x44: /* MMC_RSP1 */
336 case 0x48: /* MMC_RSP2 */
337 case 0x4c: /* MMC_RSP3 */
338 case 0x50: /* MMC_RSP4 */
339 case 0x54: /* MMC_RSP5 */
340 case 0x58: /* MMC_RSP6 */
341 case 0x5c: /* MMC_RSP7 */
342 return s
->rsp
[(offset
- 0x40) >> 2];
345 OMAP_BAD_REG(offset
);
349 static void omap_mmc_write(void *opaque
, target_phys_addr_t offset
,
353 struct omap_mmc_s
*s
= (struct omap_mmc_s
*) opaque
;
354 offset
&= OMAP_MPUI_REG_MASK
;
357 case 0x00: /* MMC_CMD */
362 for (i
= 0; i
< 8; i
++)
364 omap_mmc_command(s
, value
& 63, (value
>> 15) & 1,
365 (sd_cmd_type_t
) ((value
>> 12) & 3),
367 (sd_rsp_type_t
) ((value
>> 8) & 7),
372 case 0x04: /* MMC_ARGL */
373 s
->arg
&= 0xffff0000;
374 s
->arg
|= 0x0000ffff & value
;
377 case 0x08: /* MMC_ARGH */
378 s
->arg
&= 0x0000ffff;
379 s
->arg
|= value
<< 16;
382 case 0x0c: /* MMC_CON */
383 s
->dw
= (value
>> 15) & 1;
384 s
->mode
= (value
>> 12) & 3;
385 s
->enable
= (value
>> 11) & 1;
387 printf("SD mode %i unimplemented!\n", s
->mode
);
389 printf("4-bit SD bus enabled\n");
392 case 0x10: /* MMC_STAT */
394 omap_mmc_interrupts_update(s
);
397 case 0x14: /* MMC_IE */
399 omap_mmc_interrupts_update(s
);
402 case 0x18: /* MMC_CTO */
403 s
->cto
= value
& 0xff;
405 printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
408 case 0x1c: /* MMC_DTO */
409 s
->dto
= value
& 0xffff;
412 case 0x20: /* MMC_DATA */
413 /* TODO: support 8-bit access */
414 if (s
->fifo_len
== 32)
416 s
->fifo
[(s
->fifo_start
+ s
->fifo_len
) & 31] = value
;
418 omap_mmc_transfer(s
);
419 omap_mmc_fifolevel_update(s
);
420 omap_mmc_interrupts_update(s
);
423 case 0x24: /* MMC_BLEN */
424 s
->blen
= (value
& 0x07ff) + 1;
425 s
->blen_counter
= s
->blen
;
428 case 0x28: /* MMC_NBLK */
429 s
->nblk
= (value
& 0x07ff) + 1;
430 s
->nblk_counter
= s
->nblk
;
431 s
->blen_counter
= s
->blen
;
434 case 0x2c: /* MMC_BUF */
435 s
->rx_dma
= (value
>> 15) & 1;
436 s
->af_level
= (value
>> 8) & 0x1f;
437 s
->tx_dma
= (value
>> 7) & 1;
438 s
->ae_level
= value
& 0x1f;
444 omap_mmc_fifolevel_update(s
);
445 omap_mmc_interrupts_update(s
);
448 /* SPI, SDIO and TEST modes unimplemented */
449 case 0x30: /* MMC_SPI */
451 case 0x34: /* MMC_SDIO */
452 s
->sdio
= value
& 0x2020;
454 case 0x38: /* MMC_SYST */
457 case 0x3c: /* MMC_REV */
458 case 0x40: /* MMC_RSP0 */
459 case 0x44: /* MMC_RSP1 */
460 case 0x48: /* MMC_RSP2 */
461 case 0x4c: /* MMC_RSP3 */
462 case 0x50: /* MMC_RSP4 */
463 case 0x54: /* MMC_RSP5 */
464 case 0x58: /* MMC_RSP6 */
465 case 0x5c: /* MMC_RSP7 */
470 OMAP_BAD_REG(offset
);
474 static CPUReadMemoryFunc
*omap_mmc_readfn
[] = {
475 omap_badwidth_read16
,
477 omap_badwidth_read16
,
480 static CPUWriteMemoryFunc
*omap_mmc_writefn
[] = {
481 omap_badwidth_write16
,
483 omap_badwidth_write16
,
486 void omap_mmc_reset(struct omap_mmc_s
*host
)
489 memset(host
->rsp
, 0, sizeof(host
->rsp
));
500 host
->blen_counter
= 0;
502 host
->nblk_counter
= 0;
505 host
->ae_level
= 0x00;
506 host
->af_level
= 0x1f;
510 struct omap_mmc_s
*omap_mmc_init(target_phys_addr_t base
,
511 BlockDriverState
*bd
,
512 qemu_irq irq
, qemu_irq dma
[], omap_clk clk
)
515 struct omap_mmc_s
*s
= (struct omap_mmc_s
*)
516 qemu_mallocz(sizeof(struct omap_mmc_s
));
523 iomemtype
= cpu_register_io_memory(0, omap_mmc_readfn
,
524 omap_mmc_writefn
, s
);
525 cpu_register_physical_memory(s
->base
, 0x800, iomemtype
);
527 /* Instantiate the storage */
528 s
->card
= sd_init(bd
, 0);
533 void omap_mmc_handlers(struct omap_mmc_s
*s
, qemu_irq ro
, qemu_irq cover
)
535 sd_set_cb(s
->card
, ro
, cover
);