diff options
author | Jens Arnold <amiconn@rockbox.org> | 2004-10-09 01:14:55 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2004-10-09 01:14:55 +0000 |
commit | a450e347701d1558449f0afc446d1e425fbf5fd2 (patch) | |
tree | 12afed93ea23c71255a2ee3acff41b18eba81003 | |
parent | af2d88081a3981cb433ac373590fb055493962a5 (diff) | |
download | rockbox-a450e347701d1558449f0afc446d1e425fbf5fd2.tar.gz rockbox-a450e347701d1558449f0afc446d1e425fbf5fd2.zip |
Major MMC driver rework: DMA for sector transfers (except for single sector writes), bitswap while DMA transfer is running, optimized SCI handling (back-to-back transfer for polled writes), yield()s once per sector transfer. Speed is now close to the theoretical maximum
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5231 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | firmware/drivers/ata_mmc.c | 260 |
1 files changed, 192 insertions, 68 deletions
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c index ea7c5f1737..54cb275a0d 100644 --- a/firmware/drivers/ata_mmc.c +++ b/firmware/drivers/ata_mmc.c | |||
@@ -79,9 +79,6 @@ | |||
79 | #define DT_START_WRITE_MULTIPLE 0xfc | 79 | #define DT_START_WRITE_MULTIPLE 0xfc |
80 | #define DT_STOP_TRAN 0xfd | 80 | #define DT_STOP_TRAN 0xfd |
81 | 81 | ||
82 | // DEBUG | ||
83 | #include "../../apps/screens.h" | ||
84 | |||
85 | /* for compatibility */ | 82 | /* for compatibility */ |
86 | bool old_recorder = false; /* FIXME: get rid of this cross-dependency */ | 83 | bool old_recorder = false; /* FIXME: get rid of this cross-dependency */ |
87 | int ata_spinup_time = 0; | 84 | int ata_spinup_time = 0; |
@@ -101,19 +98,30 @@ static bool delayed_write = false; | |||
101 | static unsigned char delayed_sector[SECTOR_SIZE]; | 98 | static unsigned char delayed_sector[SECTOR_SIZE]; |
102 | static int delayed_sector_num; | 99 | static int delayed_sector_num; |
103 | 100 | ||
104 | static int current_card = 0; | 101 | static enum { |
102 | SER_POLL_WRITE, | ||
103 | SER_POLL_READ, | ||
104 | SER_DISABLED | ||
105 | } serial_mode; | ||
105 | 106 | ||
106 | static const unsigned char dummy[] = { | 107 | static const unsigned char dummy[] = { |
107 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF | 108 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF |
108 | }; | 109 | }; |
109 | 110 | ||
111 | /* 2 buffers for writing, include start token and dummy crc and an extra | ||
112 | * byte to keep word alignment */ | ||
113 | static unsigned char sector_buffer[2][(SECTOR_SIZE+4)]; | ||
114 | static int current_buffer = 0; | ||
115 | |||
110 | static tCardInfo card_info[2]; | 116 | static tCardInfo card_info[2]; |
117 | static int current_card = 0; | ||
111 | 118 | ||
112 | /* private function declarations */ | 119 | /* private function declarations */ |
113 | 120 | ||
114 | static int select_card(int card_no); | 121 | static int select_card(int card_no); |
115 | static void deselect_card(void); | 122 | static void deselect_card(void); |
116 | static void setup_sci1(int bitrate_register); | 123 | static void setup_sci1(int bitrate_register); |
124 | static void set_sci1_poll_read(void); | ||
117 | static void write_transfer(const unsigned char *buf, int len) | 125 | static void write_transfer(const unsigned char *buf, int len) |
118 | __attribute__ ((section(".icode"))); | 126 | __attribute__ ((section(".icode"))); |
119 | static void read_transfer(unsigned char *buf, int len) | 127 | static void read_transfer(unsigned char *buf, int len) |
@@ -121,10 +129,13 @@ static void read_transfer(unsigned char *buf, int len) | |||
121 | static unsigned char poll_byte(int timeout); | 129 | static unsigned char poll_byte(int timeout); |
122 | static unsigned char poll_busy(int timeout); | 130 | static unsigned char poll_busy(int timeout); |
123 | static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); | 131 | static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); |
124 | static int receive_data(unsigned char *buf, int len, int timeout); | 132 | static int receive_cxd(unsigned char *buf); |
125 | static int send_data(char start_token, const unsigned char *buf, int len, | ||
126 | int timeout); | ||
127 | static int initialize_card(int card_no); | 133 | static int initialize_card(int card_no); |
134 | static int receive_sector(unsigned char *inbuf, unsigned char *swapbuf, | ||
135 | int timeout); | ||
136 | static void swapcopy_sector(const unsigned char *buf); | ||
137 | static int send_sector(const unsigned char *nextbuf, int timeout); | ||
138 | static int send_single_sector(const unsigned char *buf, int timeout); | ||
128 | 139 | ||
129 | /* implementation */ | 140 | /* implementation */ |
130 | 141 | ||
@@ -170,19 +181,25 @@ static void deselect_card(void) | |||
170 | 181 | ||
171 | static void setup_sci1(int bitrate_register) | 182 | static void setup_sci1(int bitrate_register) |
172 | { | 183 | { |
173 | int i; | ||
174 | |||
175 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | 184 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ |
176 | 185 | ||
177 | SCR1 = 0; /* disable serial port */ | 186 | SCR1 = 0; /* disable serial port */ |
178 | SMR1 = SYNC_MODE; /* no prescale */ | 187 | SMR1 = SYNC_MODE; /* no prescale */ |
179 | BRR1 = bitrate_register; | 188 | BRR1 = bitrate_register; |
180 | SCR1 = SCI_CKE0; | ||
181 | SSR1 = 0; | 189 | SSR1 = 0; |
182 | 190 | ||
183 | for (i = 0; i <= bitrate_register; i++); /* wait at least one bit time */ | 191 | SCR1 = SCI_TE; /* enable transmitter */ |
184 | 192 | serial_mode = SER_POLL_WRITE; | |
185 | or_b((SCI_TE|SCI_RE), &SCR1); /* enable transmitter & receiver */ | 193 | } |
194 | |||
195 | static void set_sci1_poll_read(void) | ||
196 | { | ||
197 | while(!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | ||
198 | SCR1 = 0; /* disable transmitter (& receiver) */ | ||
199 | SCR1 = (SCI_TE|SCI_RE); /* re-enable transmitter & receiver */ | ||
200 | while(!(SSR1 & SCI_TEND)); /* wait for SCI init completion (!) */ | ||
201 | serial_mode = SER_POLL_READ; | ||
202 | TDR1 = 0xFF; /* send do-nothing while reading */ | ||
186 | } | 203 | } |
187 | 204 | ||
188 | static void write_transfer(const unsigned char *buf, int len) | 205 | static void write_transfer(const unsigned char *buf, int len) |
@@ -190,12 +207,19 @@ static void write_transfer(const unsigned char *buf, int len) | |||
190 | const unsigned char *buf_end = buf + len; | 207 | const unsigned char *buf_end = buf + len; |
191 | register unsigned char data; | 208 | register unsigned char data; |
192 | 209 | ||
193 | /* TODO: DMA */ | 210 | if (serial_mode != SER_POLL_WRITE) |
194 | 211 | { | |
212 | while(!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | ||
213 | SCR1 = 0; /* disable transmitter & receiver */ | ||
214 | SSR1 = 0; /* clear all flags */ | ||
215 | SCR1 = SCI_TE; /* enable transmitter only */ | ||
216 | serial_mode = SER_POLL_WRITE; | ||
217 | } | ||
218 | |||
195 | while (buf < buf_end) | 219 | while (buf < buf_end) |
196 | { | 220 | { |
197 | data = fliptable[(signed char)(*buf++)]; /* bitswap */ | 221 | data = fliptable[(signed char)(*buf++)]; /* bitswap */ |
198 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | 222 | while (!(SSR1 & SCI_TDRE)); /* wait for end of transfer */ |
199 | TDR1 = data; /* write byte */ | 223 | TDR1 = data; /* write byte */ |
200 | SSR1 = 0; /* start transmitting */ | 224 | SSR1 = 0; /* start transmitting */ |
201 | } | 225 | } |
@@ -207,11 +231,9 @@ static void read_transfer(unsigned char *buf, int len) | |||
207 | unsigned char *buf_end = buf + len - 1; | 231 | unsigned char *buf_end = buf + len - 1; |
208 | register signed char data; | 232 | register signed char data; |
209 | 233 | ||
210 | /* TODO: DMA */ | 234 | if (serial_mode != SER_POLL_READ) |
235 | set_sci1_poll_read(); | ||
211 | 236 | ||
212 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | ||
213 | TDR1 = 0xFF; /* send do-nothing data in parallel */ | ||
214 | |||
215 | SSR1 = 0; /* start receiving first byte */ | 237 | SSR1 = 0; /* start receiving first byte */ |
216 | while (buf < buf_end) | 238 | while (buf < buf_end) |
217 | { | 239 | { |
@@ -229,8 +251,8 @@ static unsigned char poll_byte(int timeout) /* timeout is in bytes */ | |||
229 | int i; | 251 | int i; |
230 | unsigned char data = 0; /* stop the compiler complaining */ | 252 | unsigned char data = 0; /* stop the compiler complaining */ |
231 | 253 | ||
232 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | 254 | if (serial_mode != SER_POLL_READ) |
233 | TDR1 = 0xFF; /* send do-nothing data in parallel */ | 255 | set_sci1_poll_read(); |
234 | 256 | ||
235 | i = 0; | 257 | i = 0; |
236 | do { | 258 | do { |
@@ -247,8 +269,8 @@ static unsigned char poll_busy(int timeout) /* timeout is in bytes */ | |||
247 | int i; | 269 | int i; |
248 | unsigned char data, dummy; | 270 | unsigned char data, dummy; |
249 | 271 | ||
250 | while (!(SSR1 &SCI_TEND)); /* wait for end of transfer */ | 272 | if (serial_mode != SER_POLL_READ) |
251 | TDR1 = 0xFF; /* send do-nothing data in parallel */ | 273 | set_sci1_poll_read(); |
252 | 274 | ||
253 | /* get data response */ | 275 | /* get data response */ |
254 | SSR1 = 0; /* start receiving */ | 276 | SSR1 = 0; /* start receiving */ |
@@ -266,6 +288,7 @@ static unsigned char poll_busy(int timeout) /* timeout is in bytes */ | |||
266 | return data; | 288 | return data; |
267 | } | 289 | } |
268 | 290 | ||
291 | /* Send MMC command and get response */ | ||
269 | static int send_cmd(int cmd, unsigned long parameter, unsigned char *response) | 292 | static int send_cmd(int cmd, unsigned long parameter, unsigned char *response) |
270 | { | 293 | { |
271 | unsigned char command[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 0xFF}; | 294 | unsigned char command[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 0xFF}; |
@@ -283,7 +306,7 @@ static int send_cmd(int cmd, unsigned long parameter, unsigned char *response) | |||
283 | write_transfer(command, 7); | 306 | write_transfer(command, 7); |
284 | 307 | ||
285 | response[0] = poll_byte(20); | 308 | response[0] = poll_byte(20); |
286 | 309 | ||
287 | if (response[0] != 0x00) | 310 | if (response[0] != 0x00) |
288 | { | 311 | { |
289 | write_transfer(dummy, 1); | 312 | write_transfer(dummy, 1); |
@@ -316,38 +339,18 @@ static int send_cmd(int cmd, unsigned long parameter, unsigned char *response) | |||
316 | return 0; | 339 | return 0; |
317 | } | 340 | } |
318 | 341 | ||
319 | static int receive_data(unsigned char *buf, int len, int timeout) | 342 | /* Receive CID/ CSD data (16 bytes) */ |
343 | static int receive_cxd(unsigned char *buf) | ||
320 | { | 344 | { |
321 | unsigned char crc[2]; /* unused */ | 345 | if (poll_byte(20) != DT_START_BLOCK) |
322 | |||
323 | if (poll_byte(timeout) != DT_START_BLOCK) | ||
324 | { | 346 | { |
325 | write_transfer(dummy, 1); | 347 | write_transfer(dummy, 1); |
326 | return -1; /* not start of data */ | 348 | return -1; /* not start of data */ |
327 | } | 349 | } |
328 | |||
329 | read_transfer(buf, len); | ||
330 | read_transfer(crc, 2); /* throw away */ | ||
331 | write_transfer(dummy, 1); | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int send_data(char start_token, const unsigned char *buf, int len, | ||
337 | int timeout) | ||
338 | { | ||
339 | int ret = 0; | ||
340 | |||
341 | write_transfer(&start_token, 1); | ||
342 | write_transfer(buf, len); | ||
343 | write_transfer(dummy, 2); /* crc - dontcare */ | ||
344 | |||
345 | if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */ | ||
346 | ret = -1; | ||
347 | |||
348 | write_transfer(dummy, 1); | ||
349 | 350 | ||
350 | return ret; | 351 | read_transfer(buf, 16); |
352 | write_transfer(dummy, 3); /* 2 bytes dontcare crc + 1 byte trailer */ | ||
353 | return 0; | ||
351 | } | 354 | } |
352 | 355 | ||
353 | /* helper function to extract n (<=32) bits from an arbitrary position. | 356 | /* helper function to extract n (<=32) bits from an arbitrary position. |
@@ -423,7 +426,7 @@ static int initialize_card(int card_no) | |||
423 | /* get CSD register */ | 426 | /* get CSD register */ |
424 | if (send_cmd(CMD_SEND_CSD, 0, response)) | 427 | if (send_cmd(CMD_SEND_CSD, 0, response)) |
425 | return -5; | 428 | return -5; |
426 | if (receive_data((unsigned char*)card->csd, 16, 20)) | 429 | if (receive_cxd((unsigned char*)card->csd)) |
427 | return -6; | 430 | return -6; |
428 | 431 | ||
429 | /* check block size */ | 432 | /* check block size */ |
@@ -459,7 +462,7 @@ static int initialize_card(int card_no) | |||
459 | /* get CID register */ | 462 | /* get CID register */ |
460 | if (send_cmd(CMD_SEND_CID, 0, response)) | 463 | if (send_cmd(CMD_SEND_CID, 0, response)) |
461 | return -8; | 464 | return -8; |
462 | if (receive_data((unsigned char*)card->cid, 16, 20)) | 465 | if (receive_cxd((unsigned char*)card->cid)) |
463 | return -9; | 466 | return -9; |
464 | 467 | ||
465 | card->initialized = true; | 468 | card->initialized = true; |
@@ -478,6 +481,119 @@ tCardInfo *mmc_card_info(int card_no) | |||
478 | return card; | 481 | return card; |
479 | } | 482 | } |
480 | 483 | ||
484 | /* Receive one sector with dma, possibly swapping the previously received | ||
485 | * sector in the background */ | ||
486 | static int receive_sector(unsigned char *inbuf, unsigned char *swapbuf, | ||
487 | int timeout) | ||
488 | { | ||
489 | if (poll_byte(timeout) != DT_START_BLOCK) | ||
490 | { | ||
491 | write_transfer(dummy, 1); | ||
492 | return -1; /* not start of data */ | ||
493 | } | ||
494 | |||
495 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | ||
496 | |||
497 | SCR1 = 0; /* disable serial */ | ||
498 | SSR1 = 0; /* clear all flags */ | ||
499 | |||
500 | /* setup DMA channel 2 */ | ||
501 | CHCR2 = 0; /* disable */ | ||
502 | SAR2 = RDR1_ADDR; | ||
503 | DAR2 = (unsigned long) inbuf; | ||
504 | DTCR2 = SECTOR_SIZE; | ||
505 | CHCR2 = 0x4601; /* fixed source address, RXI1, enable */ | ||
506 | DMAOR = 0x0001; | ||
507 | SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */ | ||
508 | |||
509 | /* dma receives 2 bytes more than DTCR2, but the last 2 bytes are not | ||
510 | * stored. The first extra byte is available from RDR1 after the DMA ends, | ||
511 | * the second one is lost because of the SCI overrun. However, this | ||
512 | * behaviour conveniently discards the crc. */ | ||
513 | |||
514 | if (swapbuf != NULL) /* bitswap previous sector */ | ||
515 | bitswap(swapbuf, SECTOR_SIZE); | ||
516 | yield(); /* be nice */ | ||
517 | |||
518 | while (!(CHCR2 & 0x0002)); /* wait for end of DMA */ | ||
519 | while (!(SSR1 & SCI_ORER)); /* wait for the trailing bytes */ | ||
520 | SCR1 = 0; | ||
521 | serial_mode = SER_DISABLED; | ||
522 | |||
523 | write_transfer(dummy, 1); /* send trailer */ | ||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | /* copies one sector into the next-current write buffer, then bitswaps */ | ||
528 | static void swapcopy_sector(const unsigned char *buf) | ||
529 | { | ||
530 | unsigned char *curbuf; | ||
531 | |||
532 | current_buffer ^= 1; /* toggles between 0 and 1 */ | ||
533 | |||
534 | curbuf = sector_buffer[current_buffer]; | ||
535 | curbuf[1] = DT_START_WRITE_MULTIPLE; | ||
536 | curbuf[(SECTOR_SIZE+2)] = curbuf[(SECTOR_SIZE+3)] = 0xFF; /* dummy crc */ | ||
537 | memcpy(curbuf + 2, buf, SECTOR_SIZE); | ||
538 | bitswap(curbuf + 1, (SECTOR_SIZE+1)); | ||
539 | } | ||
540 | |||
541 | /* Send one sector with dma from the current sector buffer, possibly preparing | ||
542 | * the next sector within the other sector buffer in the background. Use | ||
543 | * for multisector transfer only */ | ||
544 | static int send_sector(const unsigned char *nextbuf, int timeout) | ||
545 | { | ||
546 | int ret = 0; | ||
547 | |||
548 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | ||
549 | |||
550 | SCR1 = 0; /* disable serial */ | ||
551 | SSR1 = 0; /* clear all flags */ | ||
552 | |||
553 | /* setup DMA channel 2 */ | ||
554 | CHCR2 = 0; /* disable */ | ||
555 | SAR2 = (unsigned long)(sector_buffer[current_buffer] + 1); | ||
556 | DAR2 = TDR1_ADDR; | ||
557 | DTCR2 = (SECTOR_SIZE+3); | ||
558 | CHCR2 = 0x1701; /* fixed dest. address, TXI1, enable */ | ||
559 | DMAOR = 0x0001; | ||
560 | SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */ | ||
561 | |||
562 | if (nextbuf != NULL) /* prepare next sector */ | ||
563 | swapcopy_sector(nextbuf); | ||
564 | yield(); /* be nice */ | ||
565 | |||
566 | while (!(CHCR2 & 0x0002)); /* wait for end of DMA */ | ||
567 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | ||
568 | SCR1 = 0; | ||
569 | serial_mode = SER_DISABLED; | ||
570 | |||
571 | if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */ | ||
572 | ret = -1; | ||
573 | |||
574 | write_transfer(dummy, 1); | ||
575 | |||
576 | return ret; | ||
577 | } | ||
578 | |||
579 | /* Send one sector with polled i/o. Use for single sector transfers only. */ | ||
580 | static int send_single_sector(const unsigned char *buf, int timeout) | ||
581 | { | ||
582 | int ret = 0; | ||
583 | unsigned char start_token = DT_START_BLOCK; | ||
584 | |||
585 | write_transfer(&start_token, 1); | ||
586 | write_transfer(buf, SECTOR_SIZE); | ||
587 | write_transfer(dummy, 2); /* crc - dontcare */ | ||
588 | |||
589 | if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */ | ||
590 | ret = -1; | ||
591 | |||
592 | write_transfer(dummy, 1); | ||
593 | |||
594 | return ret; | ||
595 | } | ||
596 | |||
481 | int ata_read_sectors(unsigned long start, | 597 | int ata_read_sectors(unsigned long start, |
482 | int incount, | 598 | int incount, |
483 | void* inbuf) | 599 | void* inbuf) |
@@ -486,8 +602,9 @@ int ata_read_sectors(unsigned long start, | |||
486 | int i; | 602 | int i; |
487 | unsigned long addr; | 603 | unsigned long addr; |
488 | unsigned char response; | 604 | unsigned char response; |
605 | void *inbuf_prev = NULL; | ||
489 | tCardInfo *card = &card_info[current_card]; | 606 | tCardInfo *card = &card_info[current_card]; |
490 | 607 | ||
491 | addr = start * SECTOR_SIZE; | 608 | addr = start * SECTOR_SIZE; |
492 | 609 | ||
493 | mutex_lock(&mmc_mutex); | 610 | mutex_lock(&mmc_mutex); |
@@ -499,21 +616,27 @@ int ata_read_sectors(unsigned long start, | |||
499 | { | 616 | { |
500 | ret = send_cmd(CMD_READ_SINGLE_BLOCK, addr, &response); | 617 | ret = send_cmd(CMD_READ_SINGLE_BLOCK, addr, &response); |
501 | if (ret == 0) | 618 | if (ret == 0) |
502 | ret = receive_data(inbuf, SECTOR_SIZE, card->read_timeout); | 619 | { |
620 | ret = receive_sector(inbuf, inbuf_prev, card->read_timeout); | ||
621 | inbuf_prev = inbuf; | ||
503 | last_disk_activity = current_tick; | 622 | last_disk_activity = current_tick; |
623 | } | ||
504 | } | 624 | } |
505 | else | 625 | else |
506 | { | 626 | { |
507 | ret = send_cmd(CMD_READ_MULTIPLE_BLOCK, addr, &response); | 627 | ret = send_cmd(CMD_READ_MULTIPLE_BLOCK, addr, &response); |
508 | for (i = 0; (i < incount) && (ret == 0); i++) | 628 | for (i = 0; (i < incount) && (ret == 0); i++) |
509 | { | 629 | { |
510 | ret = receive_data(inbuf, SECTOR_SIZE, card->read_timeout); | 630 | ret = receive_sector(inbuf, inbuf_prev, card->read_timeout); |
631 | inbuf_prev = inbuf; | ||
511 | inbuf += SECTOR_SIZE; | 632 | inbuf += SECTOR_SIZE; |
512 | last_disk_activity = current_tick; | 633 | last_disk_activity = current_tick; |
513 | } | 634 | } |
514 | if (ret == 0) | 635 | if (ret == 0) |
515 | ret = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); | 636 | ret = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); |
516 | } | 637 | } |
638 | if (ret == 0) | ||
639 | bitswap(inbuf_prev, SECTOR_SIZE); | ||
517 | } | 640 | } |
518 | 641 | ||
519 | deselect_card(); | 642 | deselect_card(); |
@@ -550,25 +673,28 @@ int ata_write_sectors(unsigned long start, | |||
550 | { | 673 | { |
551 | ret = send_cmd(CMD_WRITE_BLOCK, addr, &response); | 674 | ret = send_cmd(CMD_WRITE_BLOCK, addr, &response); |
552 | if (ret == 0) | 675 | if (ret == 0) |
553 | ret = send_data(DT_START_BLOCK, buf, SECTOR_SIZE, | 676 | ret = send_single_sector(buf, card->write_timeout); |
554 | card->write_timeout); | ||
555 | last_disk_activity = current_tick; | 677 | last_disk_activity = current_tick; |
556 | } | 678 | } |
557 | else | 679 | else |
558 | { | 680 | { |
681 | swapcopy_sector(buf); /* prepare first sector */ | ||
559 | ret = send_cmd(CMD_WRITE_MULTIPLE_BLOCK, addr, &response); | 682 | ret = send_cmd(CMD_WRITE_MULTIPLE_BLOCK, addr, &response); |
560 | for (i = 0; (i < count) && (ret == 0); i++) | 683 | for (i = 1; (i < count) && (ret == 0); i++) |
561 | { | 684 | { |
562 | ret = send_data(DT_START_WRITE_MULTIPLE, buf, SECTOR_SIZE, | ||
563 | card->write_timeout); | ||
564 | buf += SECTOR_SIZE; | 685 | buf += SECTOR_SIZE; |
686 | ret = send_sector(buf, card->write_timeout); | ||
565 | last_disk_activity = current_tick; | 687 | last_disk_activity = current_tick; |
566 | } | 688 | } |
567 | if (ret == 0) | 689 | if (ret == 0) |
568 | { | 690 | { |
569 | response = DT_STOP_TRAN; | 691 | ret = send_sector(NULL, card->write_timeout); |
570 | write_transfer(&response, 1); | 692 | if (ret == 0) |
571 | poll_busy(card->write_timeout); | 693 | { |
694 | response = DT_STOP_TRAN; | ||
695 | write_transfer(&response, 1); | ||
696 | poll_busy(card->write_timeout); | ||
697 | } | ||
572 | last_disk_activity = current_tick; | 698 | last_disk_activity = current_tick; |
573 | } | 699 | } |
574 | } | 700 | } |
@@ -656,9 +782,7 @@ static void mmc_thread(void) | |||
656 | 782 | ||
657 | int ata_soft_reset(void) | 783 | int ata_soft_reset(void) |
658 | { | 784 | { |
659 | int ret = 0; | 785 | return 0; |
660 | |||
661 | return ret; | ||
662 | } | 786 | } |
663 | 787 | ||
664 | void ata_enable(bool on) | 788 | void ata_enable(bool on) |
@@ -706,7 +830,7 @@ int ata_init(void) | |||
706 | } | 830 | } |
707 | 831 | ||
708 | ata_enable(true); | 832 | ata_enable(true); |
709 | 833 | ||
710 | if ( !initialized ) { | 834 | if ( !initialized ) { |
711 | 835 | ||
712 | queue_init(&mmc_queue); | 836 | queue_init(&mmc_queue); |