diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2009-03-12 02:01:25 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2009-03-12 02:01:25 +0000 |
commit | bc8cab4c24a0891182ac9711c67165a9e3373b1c (patch) | |
tree | f164876bee0344f051d50c36195404d28b50907f | |
parent | 01c390d5c5fce784883054a650b6c8ebaba8b186 (diff) | |
download | rockbox-bc8cab4c24a0891182ac9711c67165a9e3373b1c.tar.gz rockbox-bc8cab4c24a0891182ac9711c67165a9e3373b1c.zip |
Commit the common portion of FS#9708: ATA (IDE) DMA by Boris Gjenero with a couple cosmetic tweaks and without the inclusion of 'FS#9721: No error check after writes in ata.c'changes (which can be done separately). No code is changed for targets without HAVE_ATA_DMA defined other than to not display DMA modes in the View Disk Info debug screen if not using DMA (Gigabeat F/X/S were). No target uses the code yet but Gigabeat S use will follow shortly.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20298 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/debug_menu.c | 27 | ||||
-rw-r--r-- | firmware/drivers/ata.c | 245 | ||||
-rw-r--r-- | firmware/export/ata.h | 14 |
3 files changed, 228 insertions, 58 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 561be7c947..2912129a1a 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c | |||
@@ -2029,7 +2029,7 @@ static int disk_callback(int btn, struct gui_synclist *lists) | |||
2029 | simplelist_addline(SIMPLELIST_ADD_LINE, | 2029 | simplelist_addline(SIMPLELIST_ADD_LINE, |
2030 | "No timing info"); | 2030 | "No timing info"); |
2031 | } | 2031 | } |
2032 | #if defined (TOSHIBA_GIGABEAT_F) || defined (TOSHIBA_GIGABEAT_S) | 2032 | #ifdef HAVE_ATA_DMA |
2033 | if (identify_info[63] & (1<<0)) { | 2033 | if (identify_info[63] & (1<<0)) { |
2034 | char mdma0[2], mdma1[2], mdma2[2]; | 2034 | char mdma0[2], mdma1[2], mdma2[2]; |
2035 | mdma0[1] = mdma1[1] = mdma2[1] = 0; | 2035 | mdma0[1] = mdma1[1] = mdma2[1] = 0; |
@@ -2047,24 +2047,25 @@ static int disk_callback(int btn, struct gui_synclist *lists) | |||
2047 | simplelist_addline(SIMPLELIST_ADD_LINE, | 2047 | simplelist_addline(SIMPLELIST_ADD_LINE, |
2048 | "No MDMA mode info"); | 2048 | "No MDMA mode info"); |
2049 | } | 2049 | } |
2050 | if (identify_info[88] & (1<<0)) { | 2050 | if (identify_info[53] & (1<<2)) { |
2051 | char udma0[2], udma1[2], udma2[2], udma3[2], udma4[2], udma5[2]; | 2051 | char udma0[2], udma1[2], udma2[2], udma3[2], udma4[2], udma5[2], udma6[2]; |
2052 | udma0[1] = udma1[1] = udma2[1] = udma3[1] = udma4[1] = udma5[1] = 0; | 2052 | udma0[1] = udma1[1] = udma2[1] = udma3[1] = udma4[1] = udma5[1] = udma6[1] = 0; |
2053 | udma0[0] = (identify_info[88] & (1<<0)) ? '0' : 0; | 2053 | udma0[0] = (identify_info[88] & (1<<0)) ? '0' : 0; |
2054 | udma1[0] = (identify_info[88] & (1<<1)) ? '1' : 0; | 2054 | udma1[0] = (identify_info[88] & (1<<1)) ? '1' : 0; |
2055 | udma2[0] = (identify_info[88] & (1<<2)) ? '2' : 0; | 2055 | udma2[0] = (identify_info[88] & (1<<2)) ? '2' : 0; |
2056 | udma3[0] = (identify_info[88] & (1<<3)) ? '3' : 0; | 2056 | udma3[0] = (identify_info[88] & (1<<3)) ? '3' : 0; |
2057 | udma4[0] = (identify_info[88] & (1<<4)) ? '4' : 0; | 2057 | udma4[0] = (identify_info[88] & (1<<4)) ? '4' : 0; |
2058 | udma5[0] = (identify_info[88] & (1<<5)) ? '5' : 0; | 2058 | udma5[0] = (identify_info[88] & (1<<5)) ? '5' : 0; |
2059 | udma6[0] = (identify_info[88] & (1<<6)) ? '6' : 0; | ||
2059 | simplelist_addline(SIMPLELIST_ADD_LINE, | 2060 | simplelist_addline(SIMPLELIST_ADD_LINE, |
2060 | "UDMA modes: %s %s %s %s %s %s", udma0, udma1, udma2, | 2061 | "UDMA modes: %s %s %s %s %s %s %s", udma0, udma1, udma2, |
2061 | udma3, udma4, udma5); | 2062 | udma3, udma4, udma5, udma6); |
2062 | } | 2063 | } |
2063 | else { | 2064 | else { |
2064 | simplelist_addline(SIMPLELIST_ADD_LINE, | 2065 | simplelist_addline(SIMPLELIST_ADD_LINE, |
2065 | "No UDMA mode info"); | 2066 | "No UDMA mode info"); |
2066 | } | 2067 | } |
2067 | #endif /* defined (TOSHIBA_GIGABEAT_F) || defined (TOSHIBA_GIGABEAT_S) */ | 2068 | #endif /* HAVE_ATA_DMA */ |
2068 | timing_info_present = identify_info[53] & (1<<1); | 2069 | timing_info_present = identify_info[53] & (1<<1); |
2069 | if(timing_info_present) { | 2070 | if(timing_info_present) { |
2070 | i = identify_info[49] & (1<<11); | 2071 | i = identify_info[49] & (1<<11); |
@@ -2079,6 +2080,18 @@ static int disk_callback(int btn, struct gui_synclist *lists) | |||
2079 | } | 2080 | } |
2080 | simplelist_addline(SIMPLELIST_ADD_LINE, | 2081 | simplelist_addline(SIMPLELIST_ADD_LINE, |
2081 | "Cluster size: %d bytes", fat_get_cluster_size(IF_MV(0))); | 2082 | "Cluster size: %d bytes", fat_get_cluster_size(IF_MV(0))); |
2083 | #ifdef HAVE_ATA_DMA | ||
2084 | i = ata_get_dma_mode(); | ||
2085 | if (i == 0) { | ||
2086 | simplelist_addline(SIMPLELIST_ADD_LINE, | ||
2087 | "DMA not enabled"); | ||
2088 | } else { | ||
2089 | simplelist_addline(SIMPLELIST_ADD_LINE, | ||
2090 | "DMA mode: %s %c", | ||
2091 | (i & 0x40) ? "UDMA" : "MDMA", | ||
2092 | '0' + (i & 7)); | ||
2093 | } | ||
2094 | #endif /* HAVE_ATA_DMA */ | ||
2082 | return btn; | 2095 | return btn; |
2083 | } | 2096 | } |
2084 | #else /* No SD, MMC or ATA */ | 2097 | #else /* No SD, MMC or ATA */ |
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 23f65b35c5..88633f0ec9 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -60,6 +60,12 @@ | |||
60 | #define CMD_SLEEP 0xE6 | 60 | #define CMD_SLEEP 0xE6 |
61 | #define CMD_SET_FEATURES 0xEF | 61 | #define CMD_SET_FEATURES 0xEF |
62 | #define CMD_SECURITY_FREEZE_LOCK 0xF5 | 62 | #define CMD_SECURITY_FREEZE_LOCK 0xF5 |
63 | #ifdef HAVE_ATA_DMA | ||
64 | #define CMD_READ_DMA 0xC8 | ||
65 | #define CMD_READ_DMA_EXT 0x25 | ||
66 | #define CMD_WRITE_DMA 0xCA | ||
67 | #define CMD_WRITE_DMA_EXT 0x35 | ||
68 | #endif | ||
63 | 69 | ||
64 | /* Should all be < 0x100 (which are reserved for control messages) */ | 70 | /* Should all be < 0x100 (which are reserved for control messages) */ |
65 | #define Q_SLEEP 0 | 71 | #define Q_SLEEP 0 |
@@ -188,6 +194,10 @@ static struct sector_cache_entry sector_cache; | |||
188 | static int phys_sector_mult = 1; | 194 | static int phys_sector_mult = 1; |
189 | #endif | 195 | #endif |
190 | 196 | ||
197 | #ifdef HAVE_ATA_DMA | ||
198 | static int dma_mode = 0; | ||
199 | #endif | ||
200 | |||
191 | static int ata_power_on(void); | 201 | static int ata_power_on(void); |
192 | static int perform_soft_reset(void); | 202 | static int perform_soft_reset(void); |
193 | static int set_multiple_mode(int sectors); | 203 | static int set_multiple_mode(int sectors); |
@@ -308,6 +318,9 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
308 | int count; | 318 | int count; |
309 | void* buf; | 319 | void* buf; |
310 | long spinup_start; | 320 | long spinup_start; |
321 | #ifdef HAVE_ATA_DMA | ||
322 | bool usedma = false; | ||
323 | #endif | ||
311 | 324 | ||
312 | #ifndef MAX_PHYS_SECTOR_SIZE | 325 | #ifndef MAX_PHYS_SECTOR_SIZE |
313 | #ifdef HAVE_MULTIVOLUME | 326 | #ifdef HAVE_MULTIVOLUME |
@@ -358,6 +371,12 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
358 | ret = 0; | 371 | ret = 0; |
359 | last_disk_activity = current_tick; | 372 | last_disk_activity = current_tick; |
360 | 373 | ||
374 | #ifdef HAVE_ATA_DMA | ||
375 | /* If DMA is supported and parameters are ok for DMA, use it */ | ||
376 | if (dma_mode && ata_dma_setup(inbuf, incount * SECTOR_SIZE, false)) | ||
377 | usedma = true; | ||
378 | #endif | ||
379 | |||
361 | #ifdef HAVE_LBA48 | 380 | #ifdef HAVE_LBA48 |
362 | if (lba48) | 381 | if (lba48) |
363 | { | 382 | { |
@@ -370,7 +389,11 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
370 | SET_REG(ATA_HCYL, 0); /* 47:40 */ | 389 | SET_REG(ATA_HCYL, 0); /* 47:40 */ |
371 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */ | 390 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */ |
372 | SET_REG(ATA_SELECT, SELECT_LBA | ata_device); | 391 | SET_REG(ATA_SELECT, SELECT_LBA | ata_device); |
392 | #ifdef HAVE_ATA_DMA | ||
393 | SET_REG(ATA_COMMAND, usedma ? CMD_READ_DMA_EXT : CMD_READ_MULTIPLE_EXT); | ||
394 | #else | ||
373 | SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE_EXT); | 395 | SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE_EXT); |
396 | #endif | ||
374 | } | 397 | } |
375 | else | 398 | else |
376 | #endif | 399 | #endif |
@@ -380,7 +403,11 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
380 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); | 403 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); |
381 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); | 404 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); |
382 | SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device); | 405 | SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device); |
406 | #ifdef HAVE_ATA_DMA | ||
407 | SET_REG(ATA_COMMAND, usedma ? CMD_READ_DMA : CMD_READ_MULTIPLE); | ||
408 | #else | ||
383 | SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE); | 409 | SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE); |
410 | #endif | ||
384 | } | 411 | } |
385 | 412 | ||
386 | /* wait at least 400ns between writing command and reading status */ | 413 | /* wait at least 400ns between writing command and reading status */ |
@@ -390,22 +417,13 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
390 | __asm__ volatile ("nop"); | 417 | __asm__ volatile ("nop"); |
391 | __asm__ volatile ("nop"); | 418 | __asm__ volatile ("nop"); |
392 | 419 | ||
393 | while (count) { | 420 | #ifdef HAVE_ATA_DMA |
394 | int sectors; | 421 | if (usedma) { |
395 | int wordcount; | 422 | if (!ata_dma_finish()) |
396 | int status; | 423 | ret = -7; |
397 | 424 | ||
398 | if (!wait_for_start_of_transfer()) { | 425 | if (ret != 0) { |
399 | /* We have timed out waiting for RDY and/or DRQ, possibly | ||
400 | because the hard drive is shaking and has problems reading | ||
401 | the data. We have two options: | ||
402 | 1) Wait some more | ||
403 | 2) Perform a soft reset and try again. | ||
404 | |||
405 | We choose alternative 2. | ||
406 | */ | ||
407 | perform_soft_reset(); | 426 | perform_soft_reset(); |
408 | ret = -5; | ||
409 | goto retry; | 427 | goto retry; |
410 | } | 428 | } |
411 | 429 | ||
@@ -415,36 +433,67 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
415 | sleeping = false; | 433 | sleeping = false; |
416 | poweroff = false; | 434 | poweroff = false; |
417 | } | 435 | } |
436 | } | ||
437 | else | ||
438 | #endif /* HAVE_ATA_DMA */ | ||
439 | { | ||
440 | while (count) { | ||
441 | int sectors; | ||
442 | int wordcount; | ||
443 | int status; | ||
444 | |||
445 | if (!wait_for_start_of_transfer()) { | ||
446 | /* We have timed out waiting for RDY and/or DRQ, possibly | ||
447 | because the hard drive is shaking and has problems | ||
448 | reading the data. We have two options: | ||
449 | 1) Wait some more | ||
450 | 2) Perform a soft reset and try again. | ||
451 | |||
452 | We choose alternative 2. | ||
453 | */ | ||
454 | perform_soft_reset(); | ||
455 | ret = -5; | ||
456 | goto retry; | ||
457 | } | ||
418 | 458 | ||
419 | /* read the status register exactly once per loop */ | 459 | if (spinup) { |
420 | status = ATA_STATUS; | 460 | spinup_time = current_tick - spinup_start; |
461 | spinup = false; | ||
462 | sleeping = false; | ||
463 | poweroff = false; | ||
464 | } | ||
421 | 465 | ||
422 | if (count >= multisectors ) | 466 | /* read the status register exactly once per loop */ |
423 | sectors = multisectors; | 467 | status = ATA_STATUS; |
424 | else | ||
425 | sectors = count; | ||
426 | 468 | ||
427 | wordcount = sectors * SECTOR_SIZE / 2; | 469 | if (count >= multisectors ) |
470 | sectors = multisectors; | ||
471 | else | ||
472 | sectors = count; | ||
428 | 473 | ||
429 | copy_read_sectors(buf, wordcount); | 474 | wordcount = sectors * SECTOR_SIZE / 2; |
430 | 475 | ||
431 | /* | 476 | copy_read_sectors(buf, wordcount); |
432 | "Device errors encountered during READ MULTIPLE commands are | ||
433 | posted at the beginning of the block or partial block transfer, | ||
434 | but the DRQ bit is still set to one and the data transfer shall | ||
435 | take place, including transfer of corrupted data, if any." | ||
436 | -- ATA specification | ||
437 | */ | ||
438 | if ( status & (STATUS_BSY | STATUS_ERR | STATUS_DF) ) { | ||
439 | perform_soft_reset(); | ||
440 | ret = -6; | ||
441 | goto retry; | ||
442 | } | ||
443 | 477 | ||
444 | buf += sectors * SECTOR_SIZE; /* Advance one chunk of sectors */ | 478 | /* |
445 | count -= sectors; | 479 | "Device errors encountered during READ MULTIPLE commands |
480 | are posted at the beginning of the block or partial block | ||
481 | transfer, but the DRQ bit is still set to one and the data | ||
482 | transfer shall take place, including transfer of corrupted | ||
483 | data, if any." | ||
484 | -- ATA specification | ||
485 | */ | ||
486 | if ( status & (STATUS_BSY | STATUS_ERR | STATUS_DF) ) { | ||
487 | perform_soft_reset(); | ||
488 | ret = -6; | ||
489 | goto retry; | ||
490 | } | ||
446 | 491 | ||
447 | last_disk_activity = current_tick; | 492 | buf += sectors * SECTOR_SIZE; /* Advance one chunk of sectors */ |
493 | count -= sectors; | ||
494 | |||
495 | last_disk_activity = current_tick; | ||
496 | } | ||
448 | } | 497 | } |
449 | 498 | ||
450 | if(!ret && !wait_for_end_of_transfer()) { | 499 | if(!ret && !wait_for_end_of_transfer()) { |
@@ -515,6 +564,9 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
515 | int i; | 564 | int i; |
516 | int ret = 0; | 565 | int ret = 0; |
517 | long spinup_start; | 566 | long spinup_start; |
567 | #ifdef HAVE_ATA_DMA | ||
568 | bool usedma = false; | ||
569 | #endif | ||
518 | 570 | ||
519 | #ifndef MAX_PHYS_SECTOR_SIZE | 571 | #ifndef MAX_PHYS_SECTOR_SIZE |
520 | #ifdef HAVE_MULTIVOLUME | 572 | #ifdef HAVE_MULTIVOLUME |
@@ -554,6 +606,12 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
554 | goto error; | 606 | goto error; |
555 | } | 607 | } |
556 | 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 | |||
557 | #ifdef HAVE_LBA48 | 615 | #ifdef HAVE_LBA48 |
558 | if (lba48) | 616 | if (lba48) |
559 | { | 617 | { |
@@ -566,7 +624,11 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
566 | SET_REG(ATA_HCYL, 0); /* 47:40 */ | 624 | SET_REG(ATA_HCYL, 0); /* 47:40 */ |
567 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */ | 625 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */ |
568 | SET_REG(ATA_SELECT, SELECT_LBA | ata_device); | 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 | ||
569 | SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS_EXT); | 630 | SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS_EXT); |
631 | #endif | ||
570 | } | 632 | } |
571 | else | 633 | else |
572 | #endif | 634 | #endif |
@@ -576,32 +638,51 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
576 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); | 638 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); |
577 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); | 639 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); |
578 | SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device); | 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 | ||
579 | SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS); | 644 | SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS); |
645 | #endif | ||
580 | } | 646 | } |
581 | 647 | ||
582 | for (i=0; i<count; i++) { | 648 | #ifdef HAVE_ATA_DMA |
583 | 649 | if (usedma) { | |
584 | if (!wait_for_start_of_transfer()) { | 650 | if (!ata_dma_finish()) |
585 | ret = -3; | 651 | ret = -7; |
586 | break; | 652 | else if (spinup) { |
587 | } | ||
588 | |||
589 | if (spinup) { | ||
590 | spinup_time = current_tick - spinup_start; | 653 | spinup_time = current_tick - spinup_start; |
591 | spinup = false; | 654 | spinup = false; |
592 | sleeping = false; | 655 | sleeping = false; |
593 | poweroff = false; | 656 | poweroff = false; |
594 | } | 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 | } | ||
595 | 675 | ||
596 | copy_write_sectors(buf, SECTOR_SIZE/2); | 676 | copy_write_sectors(buf, SECTOR_SIZE/2); |
597 | 677 | ||
598 | #ifdef USE_INTERRUPT | 678 | #ifdef USE_INTERRUPT |
599 | /* reading the status register clears the interrupt */ | 679 | /* reading the status register clears the interrupt */ |
600 | j = ATA_STATUS; | 680 | j = ATA_STATUS; |
601 | #endif | 681 | #endif |
602 | buf += SECTOR_SIZE; | 682 | buf += SECTOR_SIZE; |
603 | 683 | ||
604 | last_disk_activity = current_tick; | 684 | last_disk_activity = current_tick; |
685 | } | ||
605 | } | 686 | } |
606 | 687 | ||
607 | if(!ret && !wait_for_end_of_transfer()) { | 688 | if(!ret && !wait_for_end_of_transfer()) { |
@@ -1039,7 +1120,12 @@ static int perform_soft_reset(void) | |||
1039 | SET_REG(ATA_CONTROL, CONTROL_nIEN|CONTROL_SRST ); | 1120 | SET_REG(ATA_CONTROL, CONTROL_nIEN|CONTROL_SRST ); |
1040 | sleep(1); /* >= 5us */ | 1121 | sleep(1); /* >= 5us */ |
1041 | 1122 | ||
1123 | #ifdef HAVE_ATA_DMA | ||
1124 | /* DMA requires INTRQ be enabled */ | ||
1125 | SET_REG(ATA_CONTROL, 0); | ||
1126 | #else | ||
1042 | SET_REG(ATA_CONTROL, CONTROL_nIEN); | 1127 | SET_REG(ATA_CONTROL, CONTROL_nIEN); |
1128 | #endif | ||
1043 | sleep(1); /* >2ms */ | 1129 | sleep(1); /* >2ms */ |
1044 | 1130 | ||
1045 | /* This little sucker can take up to 30 seconds */ | 1131 | /* This little sucker can take up to 30 seconds */ |
@@ -1179,6 +1265,22 @@ static int set_multiple_mode(int sectors) | |||
1179 | return 0; | 1265 | return 0; |
1180 | } | 1266 | } |
1181 | 1267 | ||
1268 | #ifdef HAVE_ATA_DMA | ||
1269 | static int get_best_mode(unsigned short identword, int max, int modetype) | ||
1270 | { | ||
1271 | unsigned short testbit = 1u << max; | ||
1272 | |||
1273 | while (1) { | ||
1274 | if (identword & testbit) | ||
1275 | return max | modetype; | ||
1276 | testbit >>= 1; | ||
1277 | if (!testbit) | ||
1278 | return 0; | ||
1279 | max--; | ||
1280 | } | ||
1281 | } | ||
1282 | #endif | ||
1283 | |||
1182 | static int set_features(void) | 1284 | static int set_features(void) |
1183 | { | 1285 | { |
1184 | static struct { | 1286 | static struct { |
@@ -1191,6 +1293,9 @@ static int set_features(void) | |||
1191 | { 83, 3, 0x05, 0x80 }, /* adv. power management: lowest w/o standby */ | 1293 | { 83, 3, 0x05, 0x80 }, /* adv. power management: lowest w/o standby */ |
1192 | { 83, 9, 0x42, 0x80 }, /* acoustic management: lowest noise */ | 1294 | { 83, 9, 0x42, 0x80 }, /* acoustic management: lowest noise */ |
1193 | { 82, 6, 0xaa, 0 }, /* enable read look-ahead */ | 1295 | { 82, 6, 0xaa, 0 }, /* enable read look-ahead */ |
1296 | #ifdef HAVE_ATA_DMA | ||
1297 | { 0, 0, 0x03, 0 }, /* DMA mode */ | ||
1298 | #endif | ||
1194 | }; | 1299 | }; |
1195 | int i; | 1300 | int i; |
1196 | int pio_mode = 2; | 1301 | int pio_mode = 2; |
@@ -1204,6 +1309,23 @@ static int set_features(void) | |||
1204 | 1309 | ||
1205 | /* Update the table: set highest supported pio mode that we also support */ | 1310 | /* Update the table: set highest supported pio mode that we also support */ |
1206 | features[0].parameter = 8 + pio_mode; | 1311 | features[0].parameter = 8 + pio_mode; |
1312 | |||
1313 | #ifdef HAVE_ATA_DMA | ||
1314 | if (identify_info[53] & (1<<2)) | ||
1315 | /* Ultra DMA mode info present, find a mode */ | ||
1316 | dma_mode = get_best_mode(identify_info[88], ATA_MAX_UDMA, 0x40); | ||
1317 | |||
1318 | if (!dma_mode) { | ||
1319 | /* No UDMA mode found, try to find a multi-word DMA mode */ | ||
1320 | dma_mode = get_best_mode(identify_info[63], ATA_MAX_MWDMA, 0x20); | ||
1321 | features[4].id_word = 63; | ||
1322 | } | ||
1323 | else | ||
1324 | features[4].id_word = 88; | ||
1325 | |||
1326 | features[4].id_bit = dma_mode & 7; | ||
1327 | features[4].parameter = dma_mode; | ||
1328 | #endif /* HAVE_ATA_DMA */ | ||
1207 | 1329 | ||
1208 | SET_REG(ATA_SELECT, ata_device); | 1330 | SET_REG(ATA_SELECT, ata_device); |
1209 | 1331 | ||
@@ -1237,6 +1359,10 @@ static int set_features(void) | |||
1237 | ata_set_pio_timings(pio_mode); | 1359 | ata_set_pio_timings(pio_mode); |
1238 | #endif | 1360 | #endif |
1239 | 1361 | ||
1362 | #ifdef HAVE_ATA_DMA | ||
1363 | ata_dma_set_mode(dma_mode); | ||
1364 | #endif | ||
1365 | |||
1240 | return 0; | 1366 | return 0; |
1241 | } | 1367 | } |
1242 | 1368 | ||
@@ -1305,6 +1431,11 @@ int ata_init(void) | |||
1305 | sleep(HZ/4); /* allow voltage to build up */ | 1431 | sleep(HZ/4); /* allow voltage to build up */ |
1306 | } | 1432 | } |
1307 | 1433 | ||
1434 | #ifdef HAVE_ATA_DMA | ||
1435 | /* DMA requires INTRQ be enabled */ | ||
1436 | SET_REG(ATA_CONTROL, 0); | ||
1437 | #endif | ||
1438 | |||
1308 | /* first try, hard reset at cold start only */ | 1439 | /* first try, hard reset at cold start only */ |
1309 | rc = init_and_check(coldstart); | 1440 | rc = init_and_check(coldstart); |
1310 | 1441 | ||
@@ -1450,3 +1581,17 @@ void ata_get_info(struct storage_info *info) | |||
1450 | info->revision=revision; | 1581 | info->revision=revision; |
1451 | } | 1582 | } |
1452 | #endif | 1583 | #endif |
1584 | |||
1585 | #ifdef HAVE_ATA_DMA | ||
1586 | /* Returns last DMA mode as set by set_features() */ | ||
1587 | int ata_get_dma_mode(void) | ||
1588 | { | ||
1589 | return dma_mode; | ||
1590 | } | ||
1591 | |||
1592 | /* Needed to allow updating while waiting for DMA to complete */ | ||
1593 | void ata_keep_active(void) | ||
1594 | { | ||
1595 | last_disk_activity = current_tick; | ||
1596 | } | ||
1597 | #endif | ||
diff --git a/firmware/export/ata.h b/firmware/export/ata.h index f491e525e6..b5e39de3aa 100644 --- a/firmware/export/ata.h +++ b/firmware/export/ata.h | |||
@@ -60,5 +60,17 @@ bool ata_present(IF_MV_NONVOID(int drive)); | |||
60 | long ata_last_disk_activity(void); | 60 | long ata_last_disk_activity(void); |
61 | int ata_spinup_time(void); /* ticks */ | 61 | int ata_spinup_time(void); /* ticks */ |
62 | 62 | ||
63 | #ifdef HAVE_ATA_DMA | ||
64 | /* Needed to allow updating while waiting for DMA to complete */ | ||
65 | void ata_keep_active(void); | ||
66 | /* Returns current DMA mode */ | ||
67 | int ata_get_dma_mode(void); | ||
68 | /* Set DMA mode for ATA interface */ | ||
69 | void ata_dma_set_mode(unsigned char mode); | ||
70 | /* Sets up DMA transfer */ | ||
71 | bool ata_dma_setup(void *addr, unsigned long bytes, bool write); | ||
72 | /* Waits for DMA transfer completion */ | ||
73 | bool ata_dma_finish(void); | ||
74 | #endif /* HAVE_ATA_DMA */ | ||
63 | 75 | ||
64 | #endif | 76 | #endif /* __ATA_H__ */ |