diff options
-rw-r--r-- | apps/debug_menu.c | 4 | ||||
-rw-r--r-- | firmware/drivers/ata_mmc.c | 510 | ||||
-rw-r--r-- | firmware/export/ata_mmc.h | 13 |
3 files changed, 359 insertions, 168 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index f1402950a9..92fe0be63c 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c | |||
@@ -1678,8 +1678,10 @@ bool dbg_mmc_info(void) | |||
1678 | (int) mmc_extract_bits(card->cid, 0, 8), | 1678 | (int) mmc_extract_bits(card->cid, 0, 8), |
1679 | (int) mmc_extract_bits(card->cid, 8, 16)); | 1679 | (int) mmc_extract_bits(card->cid, 8, 16)); |
1680 | lcd_puts(0, 4, pbuf); | 1680 | lcd_puts(0, 4, pbuf); |
1681 | snprintf(pbuf, sizeof(pbuf), "Sectors: %08x", card->numsectors); | 1681 | snprintf(pbuf, sizeof(pbuf), "Blocks: %08lx", card->numblocks); |
1682 | lcd_puts(0, 5, pbuf); | 1682 | lcd_puts(0, 5, pbuf); |
1683 | snprintf(pbuf, sizeof(pbuf), "Blocksize: %d", card->blocksize); | ||
1684 | lcd_puts(0, 6, pbuf); | ||
1683 | } | 1685 | } |
1684 | else /* Technical details */ | 1686 | else /* Technical details */ |
1685 | { | 1687 | { |
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c index 7204a7eff5..3c242878e4 100644 --- a/firmware/drivers/ata_mmc.c +++ b/firmware/drivers/ata_mmc.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "disk.h" /* for mount/unmount */ | 35 | #include "disk.h" /* for mount/unmount */ |
36 | 36 | ||
37 | #define SECTOR_SIZE 512 | 37 | #define SECTOR_SIZE 512 |
38 | #define MAX_BLOCK_SIZE 2048 | ||
38 | 39 | ||
39 | /* Command definitions */ | 40 | /* Command definitions */ |
40 | #define CMD_GO_IDLE_STATE 0x40 /* R1 */ | 41 | #define CMD_GO_IDLE_STATE 0x40 /* R1 */ |
@@ -43,6 +44,7 @@ | |||
43 | #define CMD_SEND_CID 0x4a /* R1 */ | 44 | #define CMD_SEND_CID 0x4a /* R1 */ |
44 | #define CMD_STOP_TRANSMISSION 0x4c /* R1 */ | 45 | #define CMD_STOP_TRANSMISSION 0x4c /* R1 */ |
45 | #define CMD_SEND_STATUS 0x4d /* R2 */ | 46 | #define CMD_SEND_STATUS 0x4d /* R2 */ |
47 | #define CMD_SET_BLOCKLEN 0x50 /* R1 */ | ||
46 | #define CMD_READ_SINGLE_BLOCK 0x51 /* R1 */ | 48 | #define CMD_READ_SINGLE_BLOCK 0x51 /* R1 */ |
47 | #define CMD_READ_MULTIPLE_BLOCK 0x52 /* R1 */ | 49 | #define CMD_READ_MULTIPLE_BLOCK 0x52 /* R1 */ |
48 | #define CMD_WRITE_BLOCK 0x58 /* R1b */ | 50 | #define CMD_WRITE_BLOCK 0x58 /* R1b */ |
@@ -75,15 +77,13 @@ | |||
75 | 77 | ||
76 | /* Data start tokens */ | 78 | /* Data start tokens */ |
77 | 79 | ||
78 | #define DT_START_BLOCK 0xfe | 80 | #define DT_START_BLOCK 0xfe |
79 | #define DT_START_WRITE_MULTIPLE 0xfc | 81 | #define DT_START_WRITE_MULTIPLE 0xfc |
80 | #define DT_STOP_TRAN 0xfd | 82 | #define DT_STOP_TRAN 0xfd |
81 | 83 | ||
82 | /* for compatibility */ | 84 | /* for compatibility */ |
83 | bool old_recorder = false; /* FIXME: get rid of this cross-dependency */ | 85 | bool old_recorder = false; /* FIXME: get rid of this cross-dependency */ |
84 | int ata_spinup_time = 0; | 86 | int ata_spinup_time = 0; |
85 | char ata_device = 0; /* device 0 (master) or 1 (slave) */ | ||
86 | int ata_io_address = 0; /* 0x300 or 0x200, only valid on recorder */ | ||
87 | long last_disk_activity = -1; | 87 | long last_disk_activity = -1; |
88 | 88 | ||
89 | /* private variables */ | 89 | /* private variables */ |
@@ -91,7 +91,7 @@ long last_disk_activity = -1; | |||
91 | static struct mutex mmc_mutex; | 91 | static struct mutex mmc_mutex; |
92 | 92 | ||
93 | #ifdef HAVE_HOTSWAP | 93 | #ifdef HAVE_HOTSWAP |
94 | static long mmc_stack[DEFAULT_STACK_SIZE/sizeof(long)]; | 94 | static long mmc_stack[(DEFAULT_STACK_SIZE + 0x800)/sizeof(long)]; |
95 | static const char mmc_thread_name[] = "mmc"; | 95 | static const char mmc_thread_name[] = "mmc"; |
96 | static struct event_queue mmc_queue; | 96 | static struct event_queue mmc_queue; |
97 | #endif | 97 | #endif |
@@ -111,10 +111,22 @@ static const unsigned char dummy[] = { | |||
111 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF | 111 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF |
112 | }; | 112 | }; |
113 | 113 | ||
114 | /* 2 buffers for writing, include start token and dummy crc and an extra | 114 | struct block_cache_entry { |
115 | * byte to keep word alignment */ | 115 | bool inuse; |
116 | static unsigned char sector_buffer[2][(SECTOR_SIZE+4)]; | 116 | #ifdef HAVE_MULTIVOLUME |
117 | static int current_buffer = 0; | 117 | int drive; |
118 | #endif | ||
119 | unsigned long blocknum; | ||
120 | unsigned char data[MAX_BLOCK_SIZE+4]; | ||
121 | /* include start token, dummy crc, and an extra byte at the start | ||
122 | * to keep the data word aligned. */ | ||
123 | }; | ||
124 | |||
125 | /* 2 buffers used alternatively for writing, and also for reading | ||
126 | * and sub-block writing if block size > sector size */ | ||
127 | #define NUMCACHES 2 | ||
128 | static struct block_cache_entry block_cache[NUMCACHES]; | ||
129 | static int current_cache = 0; | ||
118 | 130 | ||
119 | static tCardInfo card_info[2]; | 131 | static tCardInfo card_info[2]; |
120 | #ifndef HAVE_MULTIVOLUME | 132 | #ifndef HAVE_MULTIVOLUME |
@@ -135,17 +147,19 @@ static void write_transfer(const unsigned char *buf, int len) | |||
135 | __attribute__ ((section(".icode"))); | 147 | __attribute__ ((section(".icode"))); |
136 | static void read_transfer(unsigned char *buf, int len) | 148 | static void read_transfer(unsigned char *buf, int len) |
137 | __attribute__ ((section(".icode"))); | 149 | __attribute__ ((section(".icode"))); |
138 | static unsigned char poll_byte(int timeout); | 150 | static unsigned char poll_byte(long timeout); |
139 | static unsigned char poll_busy(int timeout); | 151 | static unsigned char poll_busy(long timeout); |
140 | static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); | 152 | static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); |
141 | static int receive_cxd(unsigned char *buf); | 153 | static int receive_cxd(unsigned char *buf); |
142 | static int initialize_card(int card_no); | 154 | static int initialize_card(int card_no); |
143 | static int receive_sector(unsigned char *inbuf, unsigned char *swapbuf, | 155 | static void swapcopy(void *dst, const void *src, unsigned long size); |
144 | int timeout); | 156 | static int receive_block(unsigned char *inbuf, unsigned char *swapbuf, |
145 | static void swapcopy_sector(const unsigned char *buf); | 157 | int size, long timeout); |
146 | static int send_sector(const unsigned char *nextbuf, int timeout); | 158 | static void swapcopy_block(const unsigned char *buf, int size); |
147 | static int send_single_sector(const unsigned char *buf, int timeout); | 159 | static int send_block(const unsigned char *nextbuf, int size, |
148 | 160 | unsigned char start_token, long timeout); | |
161 | static int cache_block(IF_MV2(int drive,) unsigned long blocknum, | ||
162 | int size, long timeout); | ||
149 | static void mmc_tick(void); | 163 | static void mmc_tick(void); |
150 | 164 | ||
151 | /* implementation */ | 165 | /* implementation */ |
@@ -227,9 +241,9 @@ static void write_transfer(const unsigned char *buf, int len) | |||
227 | if (serial_mode != SER_POLL_WRITE) | 241 | if (serial_mode != SER_POLL_WRITE) |
228 | { | 242 | { |
229 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | 243 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ |
230 | SCR1 = 0; /* disable transmitter & receiver */ | 244 | SCR1 = 0; /* disable transmitter & receiver */ |
231 | SSR1 = 0; /* clear all flags */ | 245 | SSR1 = 0; /* clear all flags */ |
232 | SCR1 = SCI_TE; /* enable transmitter only */ | 246 | SCR1 = SCI_TE; /* enable transmitter only */ |
233 | serial_mode = SER_POLL_WRITE; | 247 | serial_mode = SER_POLL_WRITE; |
234 | } | 248 | } |
235 | 249 | ||
@@ -264,9 +278,9 @@ static void read_transfer(unsigned char *buf, int len) | |||
264 | } | 278 | } |
265 | 279 | ||
266 | /* returns 0xFF on timeout, timeout is in bytes */ | 280 | /* returns 0xFF on timeout, timeout is in bytes */ |
267 | static unsigned char poll_byte(int timeout) | 281 | static unsigned char poll_byte(long timeout) |
268 | { | 282 | { |
269 | int i; | 283 | long i; |
270 | unsigned char data = 0; /* stop the compiler complaining */ | 284 | unsigned char data = 0; /* stop the compiler complaining */ |
271 | 285 | ||
272 | if (serial_mode != SER_POLL_READ) | 286 | if (serial_mode != SER_POLL_READ) |
@@ -283,9 +297,9 @@ static unsigned char poll_byte(int timeout) | |||
283 | } | 297 | } |
284 | 298 | ||
285 | /* returns 0 on timeout, timeout is in bytes */ | 299 | /* returns 0 on timeout, timeout is in bytes */ |
286 | static unsigned char poll_busy(int timeout) | 300 | static unsigned char poll_busy(long timeout) |
287 | { | 301 | { |
288 | int i; | 302 | long i; |
289 | unsigned char data, dummy; | 303 | unsigned char data, dummy; |
290 | 304 | ||
291 | if (serial_mode != SER_POLL_READ) | 305 | if (serial_mode != SER_POLL_READ) |
@@ -329,7 +343,7 @@ static int send_cmd(int cmd, unsigned long parameter, unsigned char *response) | |||
329 | if (response[0] != 0x00) | 343 | if (response[0] != 0x00) |
330 | { | 344 | { |
331 | write_transfer(dummy, 1); | 345 | write_transfer(dummy, 1); |
332 | return -10; | 346 | return -1; |
333 | } | 347 | } |
334 | 348 | ||
335 | switch (cmd) | 349 | switch (cmd) |
@@ -364,7 +378,7 @@ static int receive_cxd(unsigned char *buf) | |||
364 | if (poll_byte(20) != DT_START_BLOCK) | 378 | if (poll_byte(20) != DT_START_BLOCK) |
365 | { | 379 | { |
366 | write_transfer(dummy, 1); | 380 | write_transfer(dummy, 1); |
367 | return -11; /* not start of data */ | 381 | return -1; /* not start of data */ |
368 | } | 382 | } |
369 | 383 | ||
370 | read_transfer(buf, 16); | 384 | read_transfer(buf, 16); |
@@ -408,7 +422,7 @@ unsigned long mmc_extract_bits( | |||
408 | 422 | ||
409 | static int initialize_card(int card_no) | 423 | static int initialize_card(int card_no) |
410 | { | 424 | { |
411 | int i, temp; | 425 | int rc, i, temp; |
412 | unsigned char response[5]; | 426 | unsigned char response[5]; |
413 | tCardInfo *card = &card_info[card_no]; | 427 | tCardInfo *card = &card_info[card_no]; |
414 | 428 | ||
@@ -437,24 +451,39 @@ static int initialize_card(int card_no) | |||
437 | return -2; /* not ready */ | 451 | return -2; /* not ready */ |
438 | 452 | ||
439 | /* get OCR register */ | 453 | /* get OCR register */ |
440 | if (send_cmd(CMD_READ_OCR, 0, response)) | 454 | rc = send_cmd(CMD_READ_OCR, 0, response); |
441 | return -3; | 455 | if (rc) |
442 | card->ocr = (response[1] << 24) + (response[2] << 16) | 456 | return rc * 10 - 3; |
443 | + (response[3] << 8) + response[4]; | 457 | card->ocr = (response[1] << 24) | (response[2] << 16) |
458 | | (response[3] << 8) | response[4]; | ||
444 | 459 | ||
445 | /* check voltage */ | 460 | /* check voltage */ |
446 | if (!(card->ocr & 0x00100000)) /* 3.2 .. 3.3 V */ | 461 | if (!(card->ocr & 0x00100000)) /* 3.2 .. 3.3 V */ |
447 | return -4; | 462 | return -4; |
448 | 463 | ||
449 | /* get CSD register */ | 464 | /* get CSD register */ |
450 | if (send_cmd(CMD_SEND_CSD, 0, response)) | 465 | rc = send_cmd(CMD_SEND_CSD, 0, response); |
451 | return -5; | 466 | if (rc) |
452 | if (receive_cxd((unsigned char*)card->csd)) | 467 | return rc * 10 - 5; |
453 | return -6; | 468 | rc = receive_cxd((unsigned char*)card->csd); |
454 | 469 | if (rc) | |
455 | /* check block size */ | 470 | return rc * 10 - 6; |
456 | if ((1 << mmc_extract_bits(card->csd, 44, 4)) != SECTOR_SIZE) | 471 | |
472 | /* check block sizes */ | ||
473 | card->block_exp = mmc_extract_bits(card->csd, 44, 4); | ||
474 | card->blocksize = 1 << card->block_exp; | ||
475 | if ((mmc_extract_bits(card->csd, 102, 4) != card->block_exp) | ||
476 | || card->blocksize > MAX_BLOCK_SIZE) | ||
477 | { | ||
457 | return -7; | 478 | return -7; |
479 | } | ||
480 | |||
481 | if (card->blocksize != SECTOR_SIZE) | ||
482 | { | ||
483 | rc = send_cmd(CMD_SET_BLOCKLEN, card->blocksize, response); | ||
484 | if (rc) | ||
485 | return rc * 10 - 8; | ||
486 | } | ||
458 | 487 | ||
459 | /* max transmission speed, clock divider */ | 488 | /* max transmission speed, clock divider */ |
460 | temp = mmc_extract_bits(card->csd, 29, 3); | 489 | temp = mmc_extract_bits(card->csd, 29, 3); |
@@ -474,23 +503,30 @@ static int initialize_card(int card_no) | |||
474 | card->tsac = card->tsac * exponent[temp] / 10; | 503 | card->tsac = card->tsac * exponent[temp] / 10; |
475 | 504 | ||
476 | /* r2w_factor, write timeout */ | 505 | /* r2w_factor, write timeout */ |
477 | temp = mmc_extract_bits(card->csd, 99, 3); | 506 | card->r2w_factor = 1 << mmc_extract_bits(card->csd, 99, 3); |
478 | temp = (temp > 5) ? 5 : temp; | 507 | if (card->r2w_factor > 32) /* dirty MMC spec violation */ |
479 | card->r2w_factor = 1 << temp; | 508 | { |
480 | card->write_timeout = card->read_timeout * card->r2w_factor; | 509 | card->read_timeout *= 4; /* add safety factor */ |
510 | card->write_timeout = card->read_timeout * 8; | ||
511 | } | ||
512 | else | ||
513 | card->write_timeout = card->read_timeout * card->r2w_factor; | ||
481 | 514 | ||
482 | /* card size */ | 515 | /* card size */ |
483 | card->numsectors = (mmc_extract_bits(card->csd, 54, 12) + 1) | 516 | card->numblocks = (mmc_extract_bits(card->csd, 54, 12) + 1) |
484 | * (1 << (mmc_extract_bits(card->csd, 78, 3)+2)); | 517 | * (1 << (mmc_extract_bits(card->csd, 78, 3) + 2)); |
518 | card->size = card->numblocks * card->blocksize; | ||
485 | 519 | ||
486 | /* switch to full speed */ | 520 | /* switch to full speed */ |
487 | setup_sci1(card->bitrate_register); | 521 | setup_sci1(card->bitrate_register); |
488 | 522 | ||
489 | /* get CID register */ | 523 | /* get CID register */ |
490 | if (send_cmd(CMD_SEND_CID, 0, response)) | 524 | rc = send_cmd(CMD_SEND_CID, 0, response); |
491 | return -8; | 525 | if (rc) |
492 | if (receive_cxd((unsigned char*)card->cid)) | 526 | return rc * 10 - 9; |
493 | return -9; | 527 | rc = receive_cxd((unsigned char*)card->cid); |
528 | if (rc) | ||
529 | return rc * 10 - 9; | ||
494 | 530 | ||
495 | card->initialized = true; | 531 | card->initialized = true; |
496 | return 0; | 532 | return 0; |
@@ -510,17 +546,23 @@ tCardInfo *mmc_card_info(int card_no) | |||
510 | return card; | 546 | return card; |
511 | } | 547 | } |
512 | 548 | ||
513 | /* Receive one sector with dma, possibly swapping the previously received | 549 | static void swapcopy(void *dst, const void *src, unsigned long size) |
514 | * sector in the background */ | 550 | { |
515 | static int receive_sector(unsigned char *inbuf, unsigned char *swapbuf, | 551 | memcpy(dst, src, size); |
516 | int timeout) | 552 | bitswap(dst, size); |
553 | } | ||
554 | |||
555 | /* Receive one block with dma, possibly swapping the previously received | ||
556 | * block in the background */ | ||
557 | static int receive_block(unsigned char *inbuf, unsigned char *swapbuf, | ||
558 | int size, long timeout) | ||
517 | { | 559 | { |
518 | if (poll_byte(timeout) != DT_START_BLOCK) | 560 | if (poll_byte(timeout) != DT_START_BLOCK) |
519 | { | 561 | { |
520 | write_transfer(dummy, 1); | 562 | write_transfer(dummy, 1); |
521 | return -12; /* not start of data */ | 563 | return -1; /* not start of data */ |
522 | } | 564 | } |
523 | 565 | ||
524 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | 566 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ |
525 | 567 | ||
526 | SCR1 = 0; /* disable serial */ | 568 | SCR1 = 0; /* disable serial */ |
@@ -530,7 +572,7 @@ static int receive_sector(unsigned char *inbuf, unsigned char *swapbuf, | |||
530 | CHCR2 = 0; /* disable */ | 572 | CHCR2 = 0; /* disable */ |
531 | SAR2 = RDR1_ADDR; | 573 | SAR2 = RDR1_ADDR; |
532 | DAR2 = (unsigned long) inbuf; | 574 | DAR2 = (unsigned long) inbuf; |
533 | DTCR2 = SECTOR_SIZE; | 575 | DTCR2 = size; |
534 | CHCR2 = 0x4601; /* fixed source address, RXI1, enable */ | 576 | CHCR2 = 0x4601; /* fixed source address, RXI1, enable */ |
535 | DMAOR = 0x0001; | 577 | DMAOR = 0x0001; |
536 | SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */ | 578 | SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */ |
@@ -540,8 +582,8 @@ static int receive_sector(unsigned char *inbuf, unsigned char *swapbuf, | |||
540 | * the second one is lost because of the SCI overrun. However, this | 582 | * the second one is lost because of the SCI overrun. However, this |
541 | * behaviour conveniently discards the crc. */ | 583 | * behaviour conveniently discards the crc. */ |
542 | 584 | ||
543 | if (swapbuf != NULL) /* bitswap previous sector */ | 585 | if (swapbuf != NULL) /* bitswap previous block */ |
544 | bitswap(swapbuf, SECTOR_SIZE); | 586 | bitswap(swapbuf, size); |
545 | yield(); /* be nice */ | 587 | yield(); /* be nice */ |
546 | 588 | ||
547 | while (!(CHCR2 & 0x0002)); /* wait for end of DMA */ | 589 | while (!(CHCR2 & 0x0002)); /* wait for end of DMA */ |
@@ -553,26 +595,25 @@ static int receive_sector(unsigned char *inbuf, unsigned char *swapbuf, | |||
553 | return 0; | 595 | return 0; |
554 | } | 596 | } |
555 | 597 | ||
556 | /* copies one sector into the next-current write buffer, then bitswaps */ | 598 | /* copies one block into the next-current block cache, then bitswaps */ |
557 | static void swapcopy_sector(const unsigned char *buf) | 599 | static void swapcopy_block(const unsigned char *buf, int size) |
558 | { | 600 | { |
559 | unsigned char *curbuf; | 601 | current_cache = (current_cache + 1) % NUMCACHES; /* next cache */ |
560 | 602 | ||
561 | current_buffer ^= 1; /* toggles between 0 and 1 */ | 603 | block_cache[current_cache].inuse = false; |
562 | 604 | swapcopy(block_cache[current_cache].data + 2, buf, size); | |
563 | curbuf = sector_buffer[current_buffer]; | ||
564 | curbuf[1] = DT_START_WRITE_MULTIPLE; | ||
565 | curbuf[(SECTOR_SIZE+2)] = curbuf[(SECTOR_SIZE+3)] = 0xFF; /* dummy crc */ | ||
566 | memcpy(curbuf + 2, buf, SECTOR_SIZE); | ||
567 | bitswap(curbuf + 1, (SECTOR_SIZE+1)); | ||
568 | } | 605 | } |
569 | 606 | ||
570 | /* Send one sector with dma from the current sector buffer, possibly preparing | 607 | /* Send one block with dma from the current block cache, possibly preparing |
571 | * the next sector within the other sector buffer in the background. Use | 608 | * the next block within the next block cache in the background. */ |
572 | * for multisector transfer only */ | 609 | static int send_block(const unsigned char *nextbuf, int size, |
573 | static int send_sector(const unsigned char *nextbuf, int timeout) | 610 | unsigned char start_token, long timeout) |
574 | { | 611 | { |
575 | int ret = 0; | 612 | int rc = 0; |
613 | unsigned char *curbuf = block_cache[current_cache].data; | ||
614 | |||
615 | curbuf[1] = fliptable[(signed char)start_token]; | ||
616 | *(unsigned short *)(curbuf + size + 2) = 0xFFFF; | ||
576 | 617 | ||
577 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | 618 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ |
578 | 619 | ||
@@ -581,15 +622,15 @@ static int send_sector(const unsigned char *nextbuf, int timeout) | |||
581 | 622 | ||
582 | /* setup DMA channel 2 */ | 623 | /* setup DMA channel 2 */ |
583 | CHCR2 = 0; /* disable */ | 624 | CHCR2 = 0; /* disable */ |
584 | SAR2 = (unsigned long)(sector_buffer[current_buffer] + 1); | 625 | SAR2 = (unsigned long)(curbuf + 1); |
585 | DAR2 = TDR1_ADDR; | 626 | DAR2 = TDR1_ADDR; |
586 | DTCR2 = (SECTOR_SIZE+3); | 627 | DTCR2 = size + 3; /* start token + block + dummy crc */ |
587 | CHCR2 = 0x1701; /* fixed dest. address, TXI1, enable */ | 628 | CHCR2 = 0x1701; /* fixed dest. address, TXI1, enable */ |
588 | DMAOR = 0x0001; | 629 | DMAOR = 0x0001; |
589 | SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */ | 630 | SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */ |
590 | 631 | ||
591 | if (nextbuf != NULL) /* prepare next sector */ | 632 | if (nextbuf != NULL) /* prepare next sector */ |
592 | swapcopy_sector(nextbuf); | 633 | swapcopy_block(nextbuf, size); |
593 | yield(); /* be nice */ | 634 | yield(); /* be nice */ |
594 | 635 | ||
595 | while (!(CHCR2 & 0x0002)); /* wait for end of DMA */ | 636 | while (!(CHCR2 & 0x0002)); /* wait for end of DMA */ |
@@ -598,29 +639,52 @@ static int send_sector(const unsigned char *nextbuf, int timeout) | |||
598 | serial_mode = SER_DISABLED; | 639 | serial_mode = SER_DISABLED; |
599 | 640 | ||
600 | if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */ | 641 | if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */ |
601 | ret = -13; | 642 | rc = -1; |
602 | 643 | ||
603 | write_transfer(dummy, 1); | 644 | write_transfer(dummy, 1); |
604 | 645 | ||
605 | return ret; | 646 | return rc; |
606 | } | 647 | } |
607 | 648 | ||
608 | /* Send one sector with polled i/o. Use for single sector transfers only. */ | 649 | static int cache_block(IF_MV2(int drive,) unsigned long blocknum, |
609 | static int send_single_sector(const unsigned char *buf, int timeout) | 650 | int size, long timeout) |
610 | { | 651 | { |
611 | int ret = 0; | 652 | int rc, i; |
612 | unsigned char start_token = DT_START_BLOCK; | 653 | unsigned char response; |
613 | 654 | ||
614 | write_transfer(&start_token, 1); | 655 | /* check whether the block is already cached */ |
615 | write_transfer(buf, SECTOR_SIZE); | 656 | for (i = 0; i < NUMCACHES; i++) |
616 | write_transfer(dummy, 2); /* crc - dontcare */ | 657 | { |
617 | 658 | if (block_cache[i].inuse && (block_cache[i].blocknum == blocknum) | |
618 | if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */ | 659 | #ifdef HAVE_MULTIVOLUME |
619 | ret = -14; | 660 | && (block_cache[i].drive == drive) |
661 | #endif | ||
662 | ) | ||
663 | { | ||
664 | current_cache = i; | ||
665 | return 0; | ||
666 | } | ||
667 | } | ||
668 | /* not found: read the block */ | ||
669 | current_cache = (current_cache + 1) % NUMCACHES; | ||
670 | rc = send_cmd(CMD_READ_SINGLE_BLOCK, blocknum * size, &response); | ||
671 | if (rc) | ||
672 | return rc * 10 - 1; | ||
673 | |||
674 | block_cache[current_cache].inuse = false; | ||
675 | rc = receive_block(block_cache[current_cache].data + 2, NULL, | ||
676 | size, timeout); | ||
677 | if (rc) | ||
678 | return rc * 10 - 2; | ||
620 | 679 | ||
621 | write_transfer(dummy, 1); | 680 | #ifdef HAVE_MULTIVOLUME |
681 | block_cache[current_cache].drive = drive; | ||
682 | #endif | ||
683 | block_cache[current_cache].blocknum = blocknum; | ||
684 | block_cache[current_cache].inuse = true; | ||
685 | last_disk_activity = current_tick; | ||
622 | 686 | ||
623 | return ret; | 687 | return 0; |
624 | } | 688 | } |
625 | 689 | ||
626 | int ata_read_sectors(IF_MV2(int drive,) | 690 | int ata_read_sectors(IF_MV2(int drive,) |
@@ -628,75 +692,120 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
628 | int incount, | 692 | int incount, |
629 | void* inbuf) | 693 | void* inbuf) |
630 | { | 694 | { |
631 | int ret = 0; | 695 | int rc = 0; |
632 | int last_sector; | 696 | unsigned int blocksize, offset; |
633 | unsigned long addr; | 697 | unsigned long c_addr, c_end_addr; |
698 | unsigned long c_block, c_end_block; | ||
634 | unsigned char response; | 699 | unsigned char response; |
635 | void *inbuf_prev = NULL; | 700 | void *inbuf_prev = NULL; |
636 | tCardInfo *card; | 701 | tCardInfo *card; |
637 | 702 | ||
638 | addr = start * SECTOR_SIZE; | 703 | c_addr = start * SECTOR_SIZE; |
639 | 704 | c_end_addr = c_addr + incount * SECTOR_SIZE; | |
705 | |||
640 | mutex_lock(&mmc_mutex); | 706 | mutex_lock(&mmc_mutex); |
641 | led(true); | 707 | led(true); |
642 | #ifdef HAVE_MULTIVOLUME | 708 | #ifdef HAVE_MULTIVOLUME |
643 | card = &card_info[drive]; | 709 | card = &card_info[drive]; |
644 | ret = select_card(drive); | 710 | rc = select_card(drive); |
645 | #else | 711 | #else |
646 | card = &card_info[current_card]; | 712 | card = &card_info[current_card]; |
647 | ret = select_card(current_card); | 713 | rc = select_card(current_card); |
648 | #endif | 714 | #endif |
649 | if (start + incount > card->numsectors) | 715 | if (rc) |
716 | { | ||
717 | rc = rc * 10 - 1; | ||
718 | goto error; | ||
719 | } | ||
720 | if (c_end_addr > card->size) | ||
650 | { | 721 | { |
651 | ret = -15; | 722 | rc = -2; |
652 | /* panicf("Reading %d@%d, past end of card %d\n", | 723 | goto error; |
653 | incount, start, card->numsectors); */ | ||
654 | } | 724 | } |
655 | 725 | ||
726 | blocksize = card->blocksize; | ||
727 | offset = c_addr & (blocksize - 1); | ||
728 | c_block = c_addr >> card->block_exp; | ||
729 | c_end_block = c_end_addr >> card->block_exp; | ||
730 | |||
731 | if (offset) /* first partial block */ | ||
732 | { | ||
733 | unsigned long len = MIN(c_end_addr - c_addr, blocksize - offset); | ||
734 | |||
735 | rc = cache_block(IF_MV2(drive,) c_block, blocksize, | ||
736 | card->read_timeout); | ||
737 | if (rc) | ||
738 | { | ||
739 | rc = rc * 10 - 3; | ||
740 | goto error; | ||
741 | } | ||
742 | swapcopy(inbuf, block_cache[current_cache].data + 2 + offset, len); | ||
743 | inbuf += len; | ||
744 | c_addr += len; | ||
745 | c_block++; | ||
746 | } | ||
656 | /* some cards don't like reading the very last sector with | 747 | /* some cards don't like reading the very last sector with |
657 | * CMD_READ_MULTIPLE_BLOCK, so make sure this sector is always | 748 | * CMD_READ_MULTIPLE_BLOCK, so make sure this sector is always |
658 | * read with CMD_READ_SINGLE_BLOCK. */ | 749 | * read with CMD_READ_SINGLE_BLOCK. This is caught by the 'last |
659 | last_sector = (start + incount == card->numsectors) ? 1 : 0; | 750 | * partial block' read. */ |
751 | if (c_end_block == card->numblocks) | ||
752 | c_end_block--; | ||
660 | 753 | ||
661 | if (ret == 0) | 754 | if (c_block < c_end_block) |
662 | { | 755 | { |
663 | if (incount > 1) | 756 | rc = send_cmd(CMD_READ_MULTIPLE_BLOCK, c_addr, &response); |
757 | if (rc) | ||
664 | { | 758 | { |
665 | ret = send_cmd(CMD_READ_MULTIPLE_BLOCK, addr, &response); | 759 | rc = rc * 10 - 4; |
666 | for (; (incount > last_sector) && (ret == 0); incount--) | 760 | goto error; |
667 | { | ||
668 | ret = receive_sector(inbuf, inbuf_prev, card->read_timeout); | ||
669 | inbuf_prev = inbuf; | ||
670 | inbuf += SECTOR_SIZE; | ||
671 | last_disk_activity = current_tick; | ||
672 | } | ||
673 | if (ret == 0) | ||
674 | ret = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); | ||
675 | } | 761 | } |
676 | if (incount && (ret == 0)) | 762 | while (c_block < c_end_block) |
677 | { | 763 | { |
678 | ret = send_cmd(CMD_READ_SINGLE_BLOCK, addr, &response); | 764 | rc = receive_block(inbuf, inbuf_prev, blocksize, |
679 | if (ret == 0) | 765 | card->read_timeout); |
766 | if (rc) | ||
680 | { | 767 | { |
681 | ret = receive_sector(inbuf, inbuf_prev, card->read_timeout); | 768 | rc = rc * 10 - 5; |
682 | inbuf_prev = inbuf; | 769 | goto error; |
683 | last_disk_activity = current_tick; | ||
684 | } | 770 | } |
771 | last_disk_activity = current_tick; | ||
772 | inbuf_prev = inbuf; | ||
773 | inbuf += blocksize; | ||
774 | c_addr += blocksize; | ||
775 | c_block++; | ||
685 | } | 776 | } |
686 | 777 | rc = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); | |
687 | if (ret == 0) | 778 | if (rc) |
688 | bitswap(inbuf_prev, SECTOR_SIZE); | 779 | { |
780 | rc = rc * 10 - 6; | ||
781 | goto error; | ||
782 | } | ||
783 | bitswap(inbuf_prev, blocksize); | ||
784 | } | ||
785 | if (c_addr < c_end_addr) /* last partial block */ | ||
786 | { | ||
787 | rc = cache_block(IF_MV2(drive,) c_block, blocksize, | ||
788 | card->read_timeout); | ||
789 | if (rc) | ||
790 | { | ||
791 | rc = rc * 10 - 7; | ||
792 | goto error; | ||
793 | } | ||
794 | swapcopy(inbuf, block_cache[current_cache].data + 2, | ||
795 | c_end_addr - c_addr); | ||
689 | } | 796 | } |
690 | 797 | ||
798 | error: | ||
799 | |||
691 | deselect_card(); | 800 | deselect_card(); |
692 | led(false); | 801 | led(false); |
693 | mutex_unlock(&mmc_mutex); | 802 | mutex_unlock(&mmc_mutex); |
694 | 803 | ||
695 | /* only flush if reading went ok */ | 804 | /* only flush if reading went ok */ |
696 | if ( (ret == 0) && delayed_write ) | 805 | if ( (rc == 0) && delayed_write ) |
697 | ata_flush(); | 806 | ata_flush(); |
698 | 807 | ||
699 | return ret; | 808 | return rc; |
700 | } | 809 | } |
701 | 810 | ||
702 | int ata_write_sectors(IF_MV2(int drive,) | 811 | int ata_write_sectors(IF_MV2(int drive,) |
@@ -704,70 +813,145 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
704 | int count, | 813 | int count, |
705 | const void* buf) | 814 | const void* buf) |
706 | { | 815 | { |
707 | int ret = 0; | 816 | int rc = 0; |
708 | unsigned long addr; | 817 | unsigned int blocksize, offset; |
818 | unsigned long c_addr, c_end_addr; | ||
819 | unsigned long c_block, c_end_block; | ||
709 | unsigned char response; | 820 | unsigned char response; |
710 | tCardInfo *card; | 821 | tCardInfo *card; |
711 | 822 | ||
712 | if (start == 0) | 823 | if (start == 0) |
713 | panicf("Writing on sector 0\n"); | 824 | panicf("Writing on sector 0\n"); |
714 | 825 | ||
715 | addr = start * SECTOR_SIZE; | 826 | c_addr = start * SECTOR_SIZE; |
716 | 827 | c_end_addr = c_addr + count * SECTOR_SIZE; | |
828 | |||
717 | mutex_lock(&mmc_mutex); | 829 | mutex_lock(&mmc_mutex); |
718 | led(true); | 830 | led(true); |
719 | #ifdef HAVE_MULTIVOLUME | 831 | #ifdef HAVE_MULTIVOLUME |
720 | card = &card_info[drive]; | 832 | card = &card_info[drive]; |
721 | ret = select_card(drive); | 833 | rc = select_card(drive); |
722 | #else | 834 | #else |
723 | card = &card_info[current_card]; | 835 | card = &card_info[current_card]; |
724 | ret = select_card(current_card); | 836 | rc = select_card(current_card); |
725 | #endif | 837 | #endif |
726 | if (start + count > card->numsectors) | 838 | if (rc) |
839 | { | ||
840 | rc = rc * 10 - 1; | ||
841 | goto error; | ||
842 | } | ||
843 | |||
844 | if (c_end_addr > card->size) | ||
727 | panicf("Writing past end of card\n"); | 845 | panicf("Writing past end of card\n"); |
728 | 846 | ||
729 | if (ret == 0) | 847 | blocksize = card->blocksize; |
848 | offset = c_addr & (blocksize - 1); | ||
849 | c_block = c_addr >> card->block_exp; | ||
850 | c_end_block = c_end_addr >> card->block_exp; | ||
851 | |||
852 | if (offset) /* first partial block */ | ||
730 | { | 853 | { |
731 | if (count == 1) | 854 | unsigned long len = MIN(c_end_addr - c_addr, blocksize - offset); |
855 | |||
856 | rc = cache_block(IF_MV2(drive,) c_block, blocksize, | ||
857 | card->read_timeout); | ||
858 | if (rc) | ||
732 | { | 859 | { |
733 | ret = send_cmd(CMD_WRITE_BLOCK, addr, &response); | 860 | rc = rc * 10 - 2; |
734 | if (ret == 0) | 861 | goto error; |
735 | ret = send_single_sector(buf, card->write_timeout); | ||
736 | last_disk_activity = current_tick; | ||
737 | } | 862 | } |
738 | else | 863 | swapcopy(block_cache[current_cache].data + 2 + offset, buf, len); |
864 | rc = send_cmd(CMD_WRITE_BLOCK, c_addr - offset, &response); | ||
865 | if (rc) | ||
739 | { | 866 | { |
740 | swapcopy_sector(buf); /* prepare first sector */ | 867 | rc = rc * 10 - 3; |
741 | ret = send_cmd(CMD_WRITE_MULTIPLE_BLOCK, addr, &response); | 868 | goto error; |
742 | for (; (count > 1) && (ret == 0); count--) | 869 | } |
743 | { | 870 | buf += len; |
744 | buf += SECTOR_SIZE; | 871 | rc = send_block(NULL, blocksize, DT_START_BLOCK, card->write_timeout); |
745 | ret = send_sector(buf, card->write_timeout); | 872 | if (rc) |
746 | last_disk_activity = current_tick; | 873 | { |
747 | } | 874 | rc = rc * 10 - 4; |
748 | if (ret == 0) | 875 | goto error; |
876 | } | ||
877 | c_addr += len; | ||
878 | c_block++; | ||
879 | } | ||
880 | if (c_block < c_end_block) | ||
881 | { | ||
882 | swapcopy_block(buf, blocksize); | ||
883 | rc = send_cmd(CMD_WRITE_MULTIPLE_BLOCK, c_addr, &response); | ||
884 | if (rc) | ||
885 | { | ||
886 | rc = rc * 10 - 5; | ||
887 | goto error; | ||
888 | } | ||
889 | while (c_block < c_end_block - 1) | ||
890 | { | ||
891 | buf += blocksize; | ||
892 | rc = send_block(buf, blocksize, DT_START_WRITE_MULTIPLE, | ||
893 | card->write_timeout); | ||
894 | if (rc) | ||
749 | { | 895 | { |
750 | ret = send_sector(NULL, card->write_timeout); | 896 | rc = rc * 10 - 6; |
751 | if (ret == 0) | 897 | goto error; |
752 | { | ||
753 | response = DT_STOP_TRAN; | ||
754 | write_transfer(&response, 1); | ||
755 | poll_busy(card->write_timeout); | ||
756 | } | ||
757 | last_disk_activity = current_tick; | ||
758 | } | 898 | } |
899 | last_disk_activity = current_tick; | ||
900 | c_addr += blocksize; | ||
901 | c_block++; | ||
902 | } | ||
903 | buf += blocksize; | ||
904 | rc = send_block(NULL, blocksize, DT_START_WRITE_MULTIPLE, | ||
905 | card->write_timeout); | ||
906 | if (rc) | ||
907 | { | ||
908 | rc = rc * 10 - 7; | ||
909 | goto error; | ||
910 | } | ||
911 | last_disk_activity = current_tick; | ||
912 | c_addr += blocksize; | ||
913 | c_block++; | ||
914 | |||
915 | response = DT_STOP_TRAN; | ||
916 | write_transfer(&response, 1); | ||
917 | poll_busy(card->write_timeout); | ||
918 | } | ||
919 | if (c_addr < c_end_addr) /* last partial block */ | ||
920 | { | ||
921 | rc = cache_block(IF_MV2(drive,) c_block, blocksize, | ||
922 | card->read_timeout); | ||
923 | if (rc) | ||
924 | { | ||
925 | rc = rc * 10 - 8; | ||
926 | goto error; | ||
927 | } | ||
928 | swapcopy(block_cache[current_cache].data + 2, buf, | ||
929 | c_end_addr - c_addr); | ||
930 | rc = send_cmd(CMD_WRITE_BLOCK, c_addr, &response); | ||
931 | if (rc) | ||
932 | { | ||
933 | rc = rc * 10 - 9; | ||
934 | goto error; | ||
935 | } | ||
936 | rc = send_block(NULL, blocksize, DT_START_BLOCK, card->write_timeout); | ||
937 | if (rc) | ||
938 | { | ||
939 | rc = rc * 10 - 9; | ||
940 | goto error; | ||
759 | } | 941 | } |
760 | } | 942 | } |
761 | 943 | ||
944 | error: | ||
945 | |||
762 | deselect_card(); | 946 | deselect_card(); |
763 | led(false); | 947 | led(false); |
764 | mutex_unlock(&mmc_mutex); | 948 | mutex_unlock(&mmc_mutex); |
765 | 949 | ||
766 | /* only flush if writing went ok */ | 950 | /* only flush if writing went ok */ |
767 | if ( (ret == 0) && delayed_write ) | 951 | if ( (rc == 0) && delayed_write ) |
768 | ata_flush(); | 952 | ata_flush(); |
769 | 953 | ||
770 | return ret; | 954 | return rc; |
771 | } | 955 | } |
772 | 956 | ||
773 | /* While there is no spinup, the delayed write is still here to avoid | 957 | /* While there is no spinup, the delayed write is still here to avoid |
@@ -782,7 +966,8 @@ extern void ata_delayed_write(unsigned long sector, const void* buf) | |||
782 | /* write the delayed sector to volume 0 */ | 966 | /* write the delayed sector to volume 0 */ |
783 | extern void ata_flush(void) | 967 | extern void ata_flush(void) |
784 | { | 968 | { |
785 | if ( delayed_write ) { | 969 | if ( delayed_write ) |
970 | { | ||
786 | DEBUGF("ata_flush()\n"); | 971 | DEBUGF("ata_flush()\n"); |
787 | delayed_write = false; | 972 | delayed_write = false; |
788 | ata_write_sectors(IF_MV2(0,) delayed_sector_num, 1, delayed_sector); | 973 | ata_write_sectors(IF_MV2(0,) delayed_sector_num, 1, delayed_sector); |
@@ -823,7 +1008,8 @@ static void mmc_thread(void) | |||
823 | 1008 | ||
824 | while (1) { | 1009 | while (1) { |
825 | queue_wait(&mmc_queue, &ev); | 1010 | queue_wait(&mmc_queue, &ev); |
826 | switch ( ev.id ) { | 1011 | switch ( ev.id ) |
1012 | { | ||
827 | case SYS_USB_CONNECTED: | 1013 | case SYS_USB_CONNECTED: |
828 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | 1014 | usb_acknowledge(SYS_USB_CONNECTED_ACK); |
829 | /* Wait until the USB cable is extracted again */ | 1015 | /* Wait until the USB cable is extracted again */ |
diff --git a/firmware/export/ata_mmc.h b/firmware/export/ata_mmc.h index 6c5141dd05..8b5056bbd8 100644 --- a/firmware/export/ata_mmc.h +++ b/firmware/export/ata_mmc.h | |||
@@ -23,17 +23,20 @@ typedef struct | |||
23 | { | 23 | { |
24 | bool initialized; | 24 | bool initialized; |
25 | unsigned char bitrate_register; | 25 | unsigned char bitrate_register; |
26 | unsigned int read_timeout; /* n * 8 clock cycles */ | 26 | unsigned long read_timeout; /* n * 8 clock cycles */ |
27 | unsigned int write_timeout; /* n * 8 clock cycles */ | 27 | unsigned long write_timeout; /* n * 8 clock cycles */ |
28 | 28 | ||
29 | unsigned long ocr; /* OCR register */ | 29 | unsigned long ocr; /* OCR register */ |
30 | unsigned long csd[4]; /* CSD register, 16 bytes */ | 30 | unsigned long csd[4]; /* CSD register, 16 bytes */ |
31 | unsigned long cid[4]; /* CID register, 16 bytes */ | 31 | unsigned long cid[4]; /* CID register, 16 bytes */ |
32 | unsigned int speed; /* bit/s */ | 32 | unsigned long speed; /* bit/s */ |
33 | unsigned int nsac; /* clock cycles */ | 33 | unsigned int nsac; /* clock cycles */ |
34 | unsigned int tsac; /* n * 0.1 ns */ | 34 | unsigned long tsac; /* n * 0.1 ns */ |
35 | unsigned int r2w_factor; | 35 | unsigned int r2w_factor; |
36 | unsigned int numsectors; /* size in sectors */ | 36 | unsigned long size; /* size in bytes */ |
37 | unsigned long numblocks; /* size in flash blocks */ | ||
38 | unsigned int blocksize; /* block size in bytes */ | ||
39 | unsigned int block_exp; /* block size exponent */ | ||
37 | } tCardInfo; | 40 | } tCardInfo; |
38 | 41 | ||
39 | void mmc_select_clock(int card_no); | 42 | void mmc_select_clock(int card_no); |