summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/ata.c269
1 files changed, 74 insertions, 195 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 3c37077fd3..b00f67f5ec 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -71,7 +71,7 @@
71#define Q_SLEEP 0 71#define Q_SLEEP 0
72#define Q_CLOSE 1 72#define Q_CLOSE 1
73 73
74#define READ_TIMEOUT 5*HZ 74#define READWRITE_TIMEOUT 5*HZ
75 75
76#ifdef HAVE_ATA_POWER_OFF 76#ifdef HAVE_ATA_POWER_OFF
77#define ATA_POWER_OFF_TIMEOUT 2*HZ 77#define ATA_POWER_OFF_TIMEOUT 2*HZ
@@ -302,16 +302,47 @@ STATICIRAM ICODE_ATTR void copy_read_sectors(unsigned char* buf, int wordcount)
302} 302}
303#endif /* !ATA_OPTIMIZED_READING */ 303#endif /* !ATA_OPTIMIZED_READING */
304 304
305#ifdef MAX_PHYS_SECTOR_SIZE 305#ifndef ATA_OPTIMIZED_WRITING
306static int _read_sectors(unsigned long start, 306STATICIRAM ICODE_ATTR void copy_write_sectors(const unsigned char* buf,
307 int incount, 307 int wordcount)
308 void* inbuf) 308{
309 if ( (unsigned long)buf & 1)
310 { /* not 16-bit aligned, copy byte by byte */
311 unsigned short tmp = 0;
312 const unsigned char* bufend = buf + wordcount*2;
313 do
314 {
315#if defined(SWAP_WORDS) || defined(ROCKBOX_LITTLE_ENDIAN)
316 tmp = (unsigned short) *buf++;
317 tmp |= (unsigned short) *buf++ << 8;
318 SET_16BITREG(ATA_DATA, tmp);
309#else 319#else
310int ata_read_sectors(IF_MD2(int drive,) 320 tmp = (unsigned short) *buf++ << 8;
311 unsigned long start, 321 tmp |= (unsigned short) *buf++;
312 int incount, 322 SET_16BITREG(ATA_DATA, tmp);
313 void* inbuf)
314#endif 323#endif
324 } while (buf < bufend); /* tail loop is faster */
325 }
326 else
327 { /* 16-bit aligned, can do faster copy */
328 unsigned short* wbuf = (unsigned short*)buf;
329 unsigned short* wbufend = wbuf + wordcount;
330 do
331 {
332#ifdef SWAP_WORDS
333 SET_16BITREG(ATA_DATA, swap16(*wbuf));
334#else
335 SET_16BITREG(ATA_DATA, *wbuf);
336#endif
337 } while (++wbuf < wbufend); /* tail loop is faster */
338 }
339}
340#endif /* !ATA_OPTIMIZED_WRITING */
341
342static int ata_transfer_sectors(unsigned long start,
343 int incount,
344 void* inbuf,
345 int write)
315{ 346{
316 int ret = 0; 347 int ret = 0;
317 long timeout; 348 long timeout;
@@ -323,9 +354,6 @@ int ata_read_sectors(IF_MD2(int drive,)
323#endif 354#endif
324 355
325#ifndef MAX_PHYS_SECTOR_SIZE 356#ifndef MAX_PHYS_SECTOR_SIZE
326#ifdef HAVE_MULTIDRIVE
327 (void)drive; /* unused for now */
328#endif
329 mutex_lock(&ata_mtx); 357 mutex_lock(&ata_mtx);
330#endif 358#endif
331 359
@@ -355,7 +383,7 @@ int ata_read_sectors(IF_MD2(int drive,)
355 } 383 }
356 } 384 }
357 385
358 timeout = current_tick + READ_TIMEOUT; 386 timeout = current_tick + READWRITE_TIMEOUT;
359 387
360 SET_REG(ATA_SELECT, ata_device); 388 SET_REG(ATA_SELECT, ata_device);
361 if (!wait_for_rdy()) 389 if (!wait_for_rdy())
@@ -373,7 +401,7 @@ int ata_read_sectors(IF_MD2(int drive,)
373 401
374#ifdef HAVE_ATA_DMA 402#ifdef HAVE_ATA_DMA
375 /* If DMA is supported and parameters are ok for DMA, use it */ 403 /* If DMA is supported and parameters are ok for DMA, use it */
376 if (dma_mode && ata_dma_setup(inbuf, incount * SECTOR_SIZE, false)) 404 if (dma_mode && ata_dma_setup(inbuf, incount * SECTOR_SIZE, write))
377 usedma = true; 405 usedma = true;
378#endif 406#endif
379 407
@@ -390,9 +418,12 @@ int ata_read_sectors(IF_MD2(int drive,)
390 SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */ 418 SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */
391 SET_REG(ATA_SELECT, SELECT_LBA | ata_device); 419 SET_REG(ATA_SELECT, SELECT_LBA | ata_device);
392#ifdef HAVE_ATA_DMA 420#ifdef HAVE_ATA_DMA
393 SET_REG(ATA_COMMAND, usedma ? CMD_READ_DMA_EXT : CMD_READ_MULTIPLE_EXT); 421 if (write)
422 SET_REG(ATA_COMMAND, usedma ? CMD_WRITE_DMA_EXT : CMD_WRITE_MULTIPLE_EXT);
423 else
424 SET_REG(ATA_COMMAND, usedma ? CMD_READ_DMA_EXT : CMD_READ_MULTIPLE_EXT);
394#else 425#else
395 SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE_EXT); 426 SET_REG(ATA_COMMAND, write ? CMD_WRITE_MULTIPLE_EXT : CMD_READ_MULTIPLE_EXT);
396#endif 427#endif
397 } 428 }
398 else 429 else
@@ -404,9 +435,12 @@ int ata_read_sectors(IF_MD2(int drive,)
404 SET_REG(ATA_HCYL, (start >> 16) & 0xff); 435 SET_REG(ATA_HCYL, (start >> 16) & 0xff);
405 SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device); 436 SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device);
406#ifdef HAVE_ATA_DMA 437#ifdef HAVE_ATA_DMA
407 SET_REG(ATA_COMMAND, usedma ? CMD_READ_DMA : CMD_READ_MULTIPLE); 438 if (write)
439 SET_REG(ATA_COMMAND, usedma ? CMD_WRITE_DMA : CMD_WRITE_MULTIPLE);
440 else
441 SET_REG(ATA_COMMAND, usedma ? CMD_READ_DMA : CMD_READ_MULTIPLE);
408#else 442#else
409 SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE); 443 SET_REG(ATA_COMMAND, write ? CMD_WRITE_MULTIPLE : CMD_READ_MULTIPLE);
410#endif 444#endif
411 } 445 }
412 446
@@ -473,7 +507,10 @@ int ata_read_sectors(IF_MD2(int drive,)
473 507
474 wordcount = sectors * SECTOR_SIZE / 2; 508 wordcount = sectors * SECTOR_SIZE / 2;
475 509
476 copy_read_sectors(buf, wordcount); 510 if (write)
511 copy_write_sectors(buf, wordcount);
512 else
513 copy_read_sectors(buf, wordcount);
477 514
478 /* 515 /*
479 "Device errors encountered during READ MULTIPLE commands 516 "Device errors encountered during READ MULTIPLE commands
@@ -513,191 +550,33 @@ int ata_read_sectors(IF_MD2(int drive,)
513 return ret; 550 return ret;
514} 551}
515 552
516#ifndef ATA_OPTIMIZED_WRITING 553#ifndef MAX_PHYS_SECTOR_SIZE
517STATICIRAM ICODE_ATTR void copy_write_sectors(const unsigned char* buf, 554int ata_read_sectors(IF_MD2(int drive,)
518 int wordcount) 555 unsigned long start,
556 int incount,
557 void* inbuf)
519{ 558{
520 if ( (unsigned long)buf & 1) 559#ifdef HAVE_MULTIDRIVE
521 { /* not 16-bit aligned, copy byte by byte */ 560 (void)drive; /* unused for now */
522 unsigned short tmp = 0;
523 const unsigned char* bufend = buf + wordcount*2;
524 do
525 {
526#if defined(SWAP_WORDS) || defined(ROCKBOX_LITTLE_ENDIAN)
527 tmp = (unsigned short) *buf++;
528 tmp |= (unsigned short) *buf++ << 8;
529 SET_16BITREG(ATA_DATA, tmp);
530#else
531 tmp = (unsigned short) *buf++ << 8;
532 tmp |= (unsigned short) *buf++;
533 SET_16BITREG(ATA_DATA, tmp);
534#endif
535 } while (buf < bufend); /* tail loop is faster */
536 }
537 else
538 { /* 16-bit aligned, can do faster copy */
539 unsigned short* wbuf = (unsigned short*)buf;
540 unsigned short* wbufend = wbuf + wordcount;
541 do
542 {
543#ifdef SWAP_WORDS
544 SET_16BITREG(ATA_DATA, swap16(*wbuf));
545#else
546 SET_16BITREG(ATA_DATA, *wbuf);
547#endif 561#endif
548 } while (++wbuf < wbufend); /* tail loop is faster */ 562
549 } 563 return ata_transfer_sectors(start, incount, inbuf, false);
550} 564}
551#endif /* !ATA_OPTIMIZED_WRITING */ 565#endif
552 566
553#ifdef MAX_PHYS_SECTOR_SIZE 567#ifndef MAX_PHYS_SECTOR_SIZE
554static int _write_sectors(unsigned long start,
555 int count,
556 const void* buf)
557#else
558int ata_write_sectors(IF_MD2(int drive,) 568int ata_write_sectors(IF_MD2(int drive,)
559 unsigned long start, 569 unsigned long start,
560 int count, 570 int count,
561 const void* buf) 571 const void* buf)
562#endif
563{ 572{
564 int i;
565 int ret = 0;
566 long spinup_start;
567#ifdef HAVE_ATA_DMA
568 bool usedma = false;
569#endif
570
571#ifndef MAX_PHYS_SECTOR_SIZE
572#ifdef HAVE_MULTIDRIVE 573#ifdef HAVE_MULTIDRIVE
573 (void)drive; /* unused for now */ 574 (void)drive; /* unused for now */
574#endif 575#endif
575 mutex_lock(&ata_mtx);
576#endif
577
578 if (start + count > total_sectors)
579 panicf("Writing past end of disk");
580 576
581 last_disk_activity = current_tick; 577 return ata_transfer_sectors(start, count, (void*)buf, true);
582 spinup_start = current_tick;
583
584 ata_led(true);
585
586 if ( sleeping ) {
587 spinup = true;
588 if (poweroff) {
589 if (ata_power_on()) {
590 ret = -1;
591 goto error;
592 }
593 }
594 else {
595 if (perform_soft_reset()) {
596 ret = -1;
597 goto error;
598 }
599 }
600 }
601
602 SET_REG(ATA_SELECT, ata_device);
603 if (!wait_for_rdy())
604 {
605 ret = -2;
606 goto error;
607 }
608
609#ifdef HAVE_ATA_DMA
610 /* If DMA is supported and parameters are ok for DMA, use it */
611 if (dma_mode && ata_dma_setup((void *)buf, count * SECTOR_SIZE, true))
612 usedma = true;
613#endif
614
615#ifdef HAVE_LBA48
616 if (lba48)
617 {
618 SET_REG(ATA_NSECTOR, count >> 8);
619 SET_REG(ATA_NSECTOR, count & 0xff);
620 SET_REG(ATA_SECTOR, (start >> 24) & 0xff); /* 31:24 */
621 SET_REG(ATA_SECTOR, start & 0xff); /* 7:0 */
622 SET_REG(ATA_LCYL, 0); /* 39:32 */
623 SET_REG(ATA_LCYL, (start >> 8) & 0xff); /* 15:8 */
624 SET_REG(ATA_HCYL, 0); /* 47:40 */
625 SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */
626 SET_REG(ATA_SELECT, SELECT_LBA | ata_device);
627#ifdef HAVE_ATA_DMA
628 SET_REG(ATA_COMMAND, usedma ? CMD_WRITE_DMA_EXT : CMD_WRITE_SECTORS_EXT);
629#else
630 SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS_EXT);
631#endif
632 }
633 else
634#endif
635 {
636 SET_REG(ATA_NSECTOR, count & 0xff); /* 0 means 256 sectors */
637 SET_REG(ATA_SECTOR, start & 0xff);
638 SET_REG(ATA_LCYL, (start >> 8) & 0xff);
639 SET_REG(ATA_HCYL, (start >> 16) & 0xff);
640 SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device);
641#ifdef HAVE_ATA_DMA
642 SET_REG(ATA_COMMAND, usedma ? CMD_WRITE_DMA : CMD_WRITE_SECTORS);
643#else
644 SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS);
645#endif
646 }
647
648#ifdef HAVE_ATA_DMA
649 if (usedma) {
650 if (!ata_dma_finish())
651 ret = -7;
652 else if (spinup) {
653 spinup_time = current_tick - spinup_start;
654 spinup = false;
655 sleeping = false;
656 poweroff = false;
657 }
658 }
659 else
660#endif /* HAVE_ATA_DMA */
661 {
662 for (i=0; i<count; i++) {
663
664 if (!wait_for_start_of_transfer()) {
665 ret = -3;
666 break;
667 }
668
669 if (spinup) {
670 spinup_time = current_tick - spinup_start;
671 spinup = false;
672 sleeping = false;
673 poweroff = false;
674 }
675
676 copy_write_sectors(buf, SECTOR_SIZE/2);
677
678#ifdef USE_INTERRUPT
679 /* reading the status register clears the interrupt */
680 j = ATA_STATUS;
681#endif
682 buf += SECTOR_SIZE;
683
684 last_disk_activity = current_tick;
685 }
686 }
687
688 if(!ret && !wait_for_end_of_transfer()) {
689 DEBUGF("End on transfer failed. -- jyp");
690 ret = -4;
691 }
692
693 error:
694 ata_led(false);
695#ifndef MAX_PHYS_SECTOR_SIZE
696 mutex_unlock(&ata_mtx);
697#endif
698
699 return ret;
700} 578}
579#endif
701 580
702#ifdef MAX_PHYS_SECTOR_SIZE 581#ifdef MAX_PHYS_SECTOR_SIZE
703static int cache_sector(unsigned long sector) 582static int cache_sector(unsigned long sector)
@@ -713,7 +592,7 @@ static int cache_sector(unsigned long sector)
713 592
714 /* not found: read the sector */ 593 /* not found: read the sector */
715 sector_cache.inuse = false; 594 sector_cache.inuse = false;
716 rc = _read_sectors(sector, phys_sector_mult, sector_cache.data); 595 rc = ata_transfer_sectors(sector, phys_sector_mult, sector_cache.data, false);
717 if (!rc) 596 if (!rc)
718 { 597 {
719 sector_cache.sectornum = sector; 598 sector_cache.sectornum = sector;
@@ -724,8 +603,8 @@ static int cache_sector(unsigned long sector)
724 603
725static inline int flush_current_sector(void) 604static inline int flush_current_sector(void)
726{ 605{
727 return _write_sectors(sector_cache.sectornum, phys_sector_mult, 606 return ata_transfer_sectors(sector_cache.sectornum, phys_sector_mult,
728 sector_cache.data); 607 sector_cache.data, true);
729} 608}
730 609
731int ata_read_sectors(IF_MD2(int drive,) 610int ata_read_sectors(IF_MD2(int drive,)
@@ -767,7 +646,7 @@ int ata_read_sectors(IF_MD2(int drive,)
767 646
768 if (incount) 647 if (incount)
769 { 648 {
770 rc = _read_sectors(start, incount, inbuf); 649 rc = ata_transfer_sectors(start, incount, inbuf, false);
771 if (rc) 650 if (rc)
772 { 651 {
773 rc = rc * 10 - 2; 652 rc = rc * 10 - 2;
@@ -838,7 +717,7 @@ int ata_write_sectors(IF_MD2(int drive,)
838 717
839 if (count) 718 if (count)
840 { 719 {
841 rc = _write_sectors(start, count, buf); 720 rc = ata_transfer_sectors(start, count, (void*)buf, true);
842 if (rc) 721 if (rc)
843 { 722 {
844 rc = rc * 10 - 3; 723 rc = rc * 10 - 3;