diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2024-10-23 14:16:15 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2024-10-31 12:51:54 -0400 |
commit | e829ea9a5ea05c6dedd91f741f91cb8723e50b19 (patch) | |
tree | bb554a4ec31b3b5501189993de990d2419306c2f /firmware/target | |
parent | 825e4069655065ffd49bcc9ec64b53f1225e8186 (diff) | |
download | rockbox-e829ea9a5ea05c6dedd91f741f91cb8723e50b19.tar.gz rockbox-e829ea9a5ea05c6dedd91f741f91cb8723e50b19.zip |
ata: Rework how flushing, sleeping, and power off interacts
* FLUSH_EXT is used if featureflag is set and we are using LBA48
(unconditionally used for CE-ATA on ipod6g)
* FLUSH is used if featureflag is set (ATA6+) or if device claims to be ATA5+
* Rename ata_disk_can_power_off() to ata_disk_can_sleep() as that is
what it actually tests for. Only use it to gate issuing the
STANDBY IMMEDIATE command.
* Restore behavior of ata_disk_is_active() to return 1 if drive is
"spinning" or powered up.
* Allow poweroff if drive claims PM support OR we are able to issue
FLUSH/FLUSH_EXT commands.
* Added ata_flush() to explicitly trigger a flush operation, and hook it
up to storage_flush() in the device shutdown path. (Flushes were
only previously used in the storage device power management path)
* After issuing all settings, re-issue IDENTIFY_DEVICE to make sure
it reflects everything we've enabled.
* Update manual section on Flash/SSD mods.
Change-Id: I6770a54ef3a87f4c47120bcb96c944a6652f1bf4
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c | 103 |
1 files changed, 60 insertions, 43 deletions
diff --git a/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c b/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c index 87450aca73..21c6f3f7c0 100644 --- a/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c | |||
@@ -83,6 +83,7 @@ static uint32_t ata_dma_flags; | |||
83 | static long ata_last_activity_value = -1; | 83 | static long ata_last_activity_value = -1; |
84 | static long ata_sleep_timeout = 7 * HZ; | 84 | static long ata_sleep_timeout = 7 * HZ; |
85 | static bool ata_powered; | 85 | static bool ata_powered; |
86 | static bool canflush = true; | ||
86 | static struct semaphore mmc_wakeup; | 87 | static struct semaphore mmc_wakeup; |
87 | static struct semaphore mmc_comp_wakeup; | 88 | static struct semaphore mmc_comp_wakeup; |
88 | static int spinup_time = 0; | 89 | static int spinup_time = 0; |
@@ -578,7 +579,7 @@ static void ata_set_active(void) | |||
578 | 579 | ||
579 | bool ata_disk_is_active(void) | 580 | bool ata_disk_is_active(void) |
580 | { | 581 | { |
581 | return ata_disk_can_poweroff() ? ata_powered : 0; | 582 | return ata_powered; |
582 | } | 583 | } |
583 | 584 | ||
584 | static int ata_set_feature(uint32_t feature, uint32_t param) | 585 | static int ata_set_feature(uint32_t feature, uint32_t param) |
@@ -745,6 +746,8 @@ static int ata_power_up(void) | |||
745 | ata_dma = param ? true : false; | 746 | ata_dma = param ? true : false; |
746 | dma_mode = param; | 747 | dma_mode = param; |
747 | PASS_RC(ata_set_feature(0x03, param), 3, 4); /* Transfer mode */ | 748 | PASS_RC(ata_set_feature(0x03, param), 3, 4); /* Transfer mode */ |
749 | |||
750 | /* SET_FEATURE only supported on PATA, not CE-ATA */ | ||
748 | if (ata_identify_data[82] & BIT(5)) | 751 | if (ata_identify_data[82] & BIT(5)) |
749 | PASS_RC(ata_set_feature(0x02, 0), 3, 5); /* Enable volatile write cache */ | 752 | PASS_RC(ata_set_feature(0x02, 0), 3, 5); /* Enable volatile write cache */ |
750 | if (ata_identify_data[82] & BIT(6)) | 753 | if (ata_identify_data[82] & BIT(6)) |
@@ -753,7 +756,10 @@ static int ata_power_up(void) | |||
753 | PASS_RC(ata_set_feature(0x05, 0x80), 3, 7); /* Enable lowest power mode w/o standby */ | 756 | PASS_RC(ata_set_feature(0x05, 0x80), 3, 7); /* Enable lowest power mode w/o standby */ |
754 | if (ata_identify_data[83] & BIT(9)) | 757 | if (ata_identify_data[83] & BIT(9)) |
755 | PASS_RC(ata_set_feature(0x42, 0x80), 3, 8); /* Enable lowest noise mode */ | 758 | PASS_RC(ata_set_feature(0x42, 0x80), 3, 8); /* Enable lowest noise mode */ |
759 | |||
760 | PASS_RC(ata_identify(ata_identify_data), 3, 9); /* Finally, re-read identify info */ | ||
756 | } | 761 | } |
762 | |||
757 | spinup_time = current_tick - spinup_start; | 763 | spinup_time = current_tick - spinup_start; |
758 | 764 | ||
759 | ata_total_sectors = (ata_identify_data[61] << 16) | ata_identify_data[60]; | 765 | ata_total_sectors = (ata_identify_data[61] << 16) | ata_identify_data[60]; |
@@ -778,28 +784,6 @@ static void ata_power_down(void) | |||
778 | { | 784 | { |
779 | if (!ata_powered) | 785 | if (!ata_powered) |
780 | return; | 786 | return; |
781 | if (ceata) | ||
782 | { | ||
783 | memset(ceata_taskfile, 0, 16); | ||
784 | ceata_taskfile[0xf] = CMD_STANDBY_IMMEDIATE; | ||
785 | ceata_wait_idle(); | ||
786 | ceata_write_multiple_register(0, ceata_taskfile, 16); | ||
787 | ceata_wait_idle(); | ||
788 | sleep(HZ); | ||
789 | PWRCON(0) |= (1 << 9); | ||
790 | } | ||
791 | else | ||
792 | { | ||
793 | ata_wait_for_rdy(1000000); | ||
794 | ata_write_cbr(&ATA_PIO_DVR, 0); | ||
795 | ata_write_cbr(&ATA_PIO_CSD, CMD_STANDBY_IMMEDIATE); | ||
796 | ata_wait_for_rdy(1000000); | ||
797 | sleep(HZ / 30); | ||
798 | ATA_CONTROL = 0; | ||
799 | while (!(ATA_CONTROL & BIT(1))) | ||
800 | yield(); | ||
801 | PWRCON(0) |= (1 << 5); | ||
802 | } | ||
803 | PCON(7) = 0; | 787 | PCON(7) = 0; |
804 | PCON(8) = 0; | 788 | PCON(8) = 0; |
805 | PCON(9) = 0; | 789 | PCON(9) = 0; |
@@ -1080,26 +1064,27 @@ static void ata_flush_cache(void) | |||
1080 | { | 1064 | { |
1081 | uint8_t cmd; | 1065 | uint8_t cmd; |
1082 | 1066 | ||
1083 | if (ata_identify_data[83] & BIT(13)) { | 1067 | if (ceata) { |
1084 | cmd = CMD_FLUSH_CACHE_EXT; | ||
1085 | } else if (ata_identify_data[83] & BIT(12)) { | ||
1086 | cmd = CMD_FLUSH_CACHE; | ||
1087 | } else { | ||
1088 | /* If neither (mandatory!) command is supported | ||
1089 | then don't issue it. */ | ||
1090 | return; | ||
1091 | } | ||
1092 | |||
1093 | if (ceata) | ||
1094 | { | ||
1095 | memset(ceata_taskfile, 0, 16); | 1068 | memset(ceata_taskfile, 0, 16); |
1096 | ceata_taskfile[0xf] = cmd; | 1069 | ceata_taskfile[0xf] = CMD_FLUSH_CACHE_EXT; /* CE-ATA only supports EXT */ |
1097 | ceata_wait_idle(); | 1070 | ceata_wait_idle(); |
1098 | ceata_write_multiple_register(0, ceata_taskfile, 16); | 1071 | ceata_write_multiple_register(0, ceata_taskfile, 16); |
1099 | ceata_wait_idle(); | 1072 | ceata_wait_idle(); |
1100 | } | 1073 | } else { |
1101 | else | 1074 | if (!canflush) { |
1102 | { | 1075 | return; |
1076 | } else if (ata_lba48 && ata_identify_data[83] & BIT(13)) { | ||
1077 | cmd = CMD_FLUSH_CACHE_EXT; /* Flag, optional, ATA-6 and up, for use with LBA48 devices. Mandatory for CE-ATA */ | ||
1078 | } else if (ata_identify_data[83] & BIT(12)) { | ||
1079 | cmd = CMD_FLUSH_CACHE; /* Flag, mandatory, ATA-6 and up */ | ||
1080 | } else if (ata_identify_data[80] >= BIT(5)) { /* Use >= instead of '&' because bits lower than the latest standard we support don't have to be set */ | ||
1081 | cmd = CMD_FLUSH_CACHE; /* No flag, mandatory, ATA-5 (Optional for ATA-4) */ | ||
1082 | } else { | ||
1083 | /* If neither command is supported then don't issue it. */ | ||
1084 | canflush = 0; | ||
1085 | return; | ||
1086 | } | ||
1087 | |||
1103 | ata_wait_for_rdy(1000000); | 1088 | ata_wait_for_rdy(1000000); |
1104 | ata_write_cbr(&ATA_PIO_DVR, 0); | 1089 | ata_write_cbr(&ATA_PIO_DVR, 0); |
1105 | ata_write_cbr(&ATA_PIO_CSD, cmd); | 1090 | ata_write_cbr(&ATA_PIO_CSD, cmd); |
@@ -1107,14 +1092,46 @@ static void ata_flush_cache(void) | |||
1107 | } | 1092 | } |
1108 | } | 1093 | } |
1109 | 1094 | ||
1095 | int ata_flush(void) | ||
1096 | { | ||
1097 | if (ata_powered) { | ||
1098 | mutex_lock(&ata_mutex); | ||
1099 | ata_flush_cache(); | ||
1100 | mutex_unlock(&ata_mutex); | ||
1101 | } | ||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1110 | void ata_sleepnow(void) | 1105 | void ata_sleepnow(void) |
1111 | { | 1106 | { |
1112 | mutex_lock(&ata_mutex); | 1107 | mutex_lock(&ata_mutex); |
1113 | 1108 | ||
1114 | if (ata_disk_can_poweroff()) | 1109 | ata_flush_cache(); |
1115 | ata_power_down(); | 1110 | |
1116 | else | 1111 | if (ata_disk_can_sleep()) { |
1117 | ata_flush_cache(); | 1112 | if (ceata) { |
1113 | memset(ceata_taskfile, 0, 16); | ||
1114 | ceata_taskfile[0xf] = CMD_STANDBY_IMMEDIATE; | ||
1115 | ceata_wait_idle(); | ||
1116 | ceata_write_multiple_register(0, ceata_taskfile, 16); | ||
1117 | ceata_wait_idle(); | ||
1118 | sleep(HZ); | ||
1119 | PWRCON(0) |= (1 << 9); | ||
1120 | } else { | ||
1121 | ata_wait_for_rdy(1000000); | ||
1122 | ata_write_cbr(&ATA_PIO_DVR, 0); | ||
1123 | ata_write_cbr(&ATA_PIO_CSD, CMD_STANDBY_IMMEDIATE); | ||
1124 | ata_wait_for_rdy(1000000); | ||
1125 | sleep(HZ / 30); | ||
1126 | ATA_CONTROL = 0; | ||
1127 | while (!(ATA_CONTROL & BIT(1))) | ||
1128 | yield(); | ||
1129 | PWRCON(0) |= (1 << 5); | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | if (ata_disk_can_sleep() || canflush) | ||
1134 | ata_power_down(); // XXX add a powerdown delay similar to main ATA driver? | ||
1118 | 1135 | ||
1119 | mutex_unlock(&ata_mutex); | 1136 | mutex_unlock(&ata_mutex); |
1120 | } | 1137 | } |