diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/drivers/ata.c | 52 | ||||
-rw-r--r-- | firmware/export/ata.h | 6 | ||||
-rw-r--r-- | firmware/export/storage.h | 2 | ||||
-rw-r--r-- | firmware/storage.c | 2 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c | 103 |
5 files changed, 103 insertions, 62 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index c995f6de85..8df9acb9da 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -103,6 +103,7 @@ static long sleep_timeout = 5*HZ; | |||
103 | #ifdef HAVE_LBA48 | 103 | #ifdef HAVE_LBA48 |
104 | static bool lba48 = false; /* set for 48 bit addressing */ | 104 | static bool lba48 = false; /* set for 48 bit addressing */ |
105 | #endif | 105 | #endif |
106 | static bool canflush = true; | ||
106 | 107 | ||
107 | static long last_disk_activity = -1; | 108 | static long last_disk_activity = -1; |
108 | #ifdef HAVE_ATA_POWER_OFF | 109 | #ifdef HAVE_ATA_POWER_OFF |
@@ -141,11 +142,6 @@ static inline void keep_ata_active(void) | |||
141 | last_disk_activity = current_tick; | 142 | last_disk_activity = current_tick; |
142 | } | 143 | } |
143 | 144 | ||
144 | static inline void schedule_ata_sleep(long from_now) | ||
145 | { | ||
146 | last_disk_activity = current_tick - sleep_timeout + from_now; | ||
147 | } | ||
148 | |||
149 | static inline bool ata_sleep_timed_out(void) | 145 | static inline bool ata_sleep_timed_out(void) |
150 | { | 146 | { |
151 | return sleep_timeout && | 147 | return sleep_timeout && |
@@ -223,7 +219,7 @@ static int ata_perform_wakeup(int state) | |||
223 | static int ata_perform_sleep(void) | 219 | static int ata_perform_sleep(void) |
224 | { | 220 | { |
225 | /* If device doesn't support PM features, don't try to sleep. */ | 221 | /* If device doesn't support PM features, don't try to sleep. */ |
226 | if (!ata_disk_can_poweroff()) | 222 | if (!ata_disk_can_sleep()) |
227 | return 0; // XXX or return a failure? | 223 | return 0; // XXX or return a failure? |
228 | 224 | ||
229 | logf("ata SLEEP %ld", current_tick); | 225 | logf("ata SLEEP %ld", current_tick); |
@@ -257,13 +253,18 @@ static int ata_perform_flush_cache(void) | |||
257 | { | 253 | { |
258 | uint8_t cmd; | 254 | uint8_t cmd; |
259 | 255 | ||
260 | if (identify_info[83] & (1 << 13)) { | 256 | if (!canflush) { |
261 | cmd = CMD_FLUSH_CACHE_EXT; | 257 | return 0; |
258 | } else if (lba48 && identify_info[83] & (1 << 13)) { | ||
259 | cmd = CMD_FLUSH_CACHE_EXT; /* Flag, optional, ATA-6 and up, for use with LBA48 devices */ | ||
262 | } else if (identify_info[83] & (1 << 12)) { | 260 | } else if (identify_info[83] & (1 << 12)) { |
263 | cmd = CMD_FLUSH_CACHE; | 261 | cmd = CMD_FLUSH_CACHE; /* Flag, mandatory, ATA-6 and up */ |
262 | } else if (identify_info[80] >= (1 << 5)) { /* Use >= instead of '&' because bits lower than the latest standard we support don't have to be set */ | ||
263 | cmd = CMD_FLUSH_CACHE; /* No flag, mandatory, ATA-5 (Optional for ATA-4) */ | ||
264 | } else { | 264 | } else { |
265 | /* If neither (mandatory!) command is supported | 265 | /* If neither (mandatory!) command is supported |
266 | then don't issue it. */ | 266 | then don't issue it. */ |
267 | canflush = 0; | ||
267 | return 0; | 268 | return 0; |
268 | } | 269 | } |
269 | 270 | ||
@@ -286,6 +287,16 @@ static int ata_perform_flush_cache(void) | |||
286 | return 0; | 287 | return 0; |
287 | } | 288 | } |
288 | 289 | ||
290 | int ata_flush(void) | ||
291 | { | ||
292 | if (ata_state >= ATA_SPINUP) { | ||
293 | mutex_lock(&ata_mtx); | ||
294 | ata_perform_flush_cache(); | ||
295 | mutex_unlock(&ata_mtx); | ||
296 | } | ||
297 | return 0; | ||
298 | } | ||
299 | |||
289 | static ICODE_ATTR int wait_for_start_of_transfer(void) | 300 | static ICODE_ATTR int wait_for_start_of_transfer(void) |
290 | { | 301 | { |
291 | if (!wait_for_bsy()) | 302 | if (!wait_for_bsy()) |
@@ -844,7 +855,7 @@ void ata_spindown(int seconds) | |||
844 | 855 | ||
845 | bool ata_disk_is_active(void) | 856 | bool ata_disk_is_active(void) |
846 | { | 857 | { |
847 | return ata_disk_can_poweroff() ? (ata_state >= ATA_SPINUP) : 0; | 858 | return (ata_state >= ATA_SPINUP); |
848 | } | 859 | } |
849 | 860 | ||
850 | void ata_sleepnow(void) | 861 | void ata_sleepnow(void) |
@@ -856,8 +867,9 @@ void ata_sleepnow(void) | |||
856 | if (!ata_perform_flush_cache() && !ata_perform_sleep()) { | 867 | if (!ata_perform_flush_cache() && !ata_perform_sleep()) { |
857 | ata_state = ATA_SLEEPING; | 868 | ata_state = ATA_SLEEPING; |
858 | #ifdef HAVE_ATA_POWER_OFF | 869 | #ifdef HAVE_ATA_POWER_OFF |
859 | if (ata_disk_can_poweroff()) | 870 | if (ata_disk_can_sleep() || canflush) { |
860 | power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT; | 871 | power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT; |
872 | } | ||
861 | #endif | 873 | #endif |
862 | } | 874 | } |
863 | } | 875 | } |
@@ -967,6 +979,9 @@ static int perform_soft_reset(void) | |||
967 | if (set_multiple_mode(multisectors)) | 979 | if (set_multiple_mode(multisectors)) |
968 | return -3; | 980 | return -3; |
969 | 981 | ||
982 | if (identify()) | ||
983 | return -2; | ||
984 | |||
970 | if (freeze_lock()) | 985 | if (freeze_lock()) |
971 | return -4; | 986 | return -4; |
972 | 987 | ||
@@ -1017,6 +1032,9 @@ static int ata_power_on(void) | |||
1017 | if (set_multiple_mode(multisectors)) | 1032 | if (set_multiple_mode(multisectors)) |
1018 | return -3; | 1033 | return -3; |
1019 | 1034 | ||
1035 | if (identify()) | ||
1036 | return -2; | ||
1037 | |||
1020 | if (freeze_lock()) | 1038 | if (freeze_lock()) |
1021 | return -4; | 1039 | return -4; |
1022 | 1040 | ||
@@ -1255,7 +1273,6 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1255 | } | 1273 | } |
1256 | 1274 | ||
1257 | rc = identify(); | 1275 | rc = identify(); |
1258 | |||
1259 | if (rc) { | 1276 | if (rc) { |
1260 | rc = -40 + rc; | 1277 | rc = -40 + rc; |
1261 | goto error; | 1278 | goto error; |
@@ -1280,13 +1297,12 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1280 | #endif /* HAVE_LBA48 */ | 1297 | #endif /* HAVE_LBA48 */ |
1281 | 1298 | ||
1282 | rc = freeze_lock(); | 1299 | rc = freeze_lock(); |
1283 | |||
1284 | if (rc) { | 1300 | if (rc) { |
1285 | rc = -50 + rc; | 1301 | rc = -50 + rc; |
1286 | goto error; | 1302 | goto error; |
1287 | } | 1303 | } |
1288 | 1304 | ||
1289 | rc = set_features(); // rror codes are between -1 and -49 | 1305 | rc = set_features(); // error codes are between -1 and -49 |
1290 | if (rc) { | 1306 | if (rc) { |
1291 | rc = -60 + rc; | 1307 | rc = -60 + rc; |
1292 | goto error; | 1308 | goto error; |
@@ -1325,6 +1341,12 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1325 | if (rc) | 1341 | if (rc) |
1326 | rc = -100 + rc; | 1342 | rc = -100 + rc; |
1327 | 1343 | ||
1344 | rc = identify(); | ||
1345 | if (rc) { | ||
1346 | rc = -40 + rc; | ||
1347 | goto error; | ||
1348 | } | ||
1349 | |||
1328 | error: | 1350 | error: |
1329 | mutex_unlock(&ata_mtx); | 1351 | mutex_unlock(&ata_mtx); |
1330 | return rc; | 1352 | return rc; |
@@ -1440,7 +1462,7 @@ int ata_event(long id, intptr_t data) | |||
1440 | ata_sleepnow(); | 1462 | ata_sleepnow(); |
1441 | } | 1463 | } |
1442 | else if (id == Q_STORAGE_SLEEP) { | 1464 | else if (id == Q_STORAGE_SLEEP) { |
1443 | schedule_ata_sleep(HZ/5); | 1465 | last_disk_activity = current_tick - sleep_timeout + HZ / 5; |
1444 | } | 1466 | } |
1445 | #ifndef USB_NONE | 1467 | #ifndef USB_NONE |
1446 | else if (id == SYS_USB_CONNECTED) { | 1468 | else if (id == SYS_USB_CONNECTED) { |
diff --git a/firmware/export/ata.h b/firmware/export/ata.h index 0d84a91524..dfa73eebf5 100644 --- a/firmware/export/ata.h +++ b/firmware/export/ata.h | |||
@@ -208,8 +208,8 @@ static inline int ata_disk_isssd(void) | |||
208 | ); | 208 | ); |
209 | } | 209 | } |
210 | 210 | ||
211 | /* Returns 1 if the drive can be powered off safely */ | 211 | /* Returns 1 if the drive supports power management commands */ |
212 | static inline int ata_disk_can_poweroff(void) | 212 | static inline int ata_disk_can_sleep(void) |
213 | { | 213 | { |
214 | unsigned short *identify_info = ata_get_identify(); | 214 | unsigned short *identify_info = ata_get_identify(); |
215 | /* Only devices that claim to support PM can be safely powered off. | 215 | /* Only devices that claim to support PM can be safely powered off. |
@@ -217,6 +217,8 @@ static inline int ata_disk_can_poweroff(void) | |||
217 | return (identify_info[82] & (1<<3) && identify_info[85] & (1<<3)); | 217 | return (identify_info[82] & (1<<3) && identify_info[85] & (1<<3)); |
218 | } | 218 | } |
219 | 219 | ||
220 | int ata_flush(void); | ||
221 | |||
220 | #ifdef HAVE_ATA_DMA | 222 | #ifdef HAVE_ATA_DMA |
221 | /* Returns current DMA mode */ | 223 | /* Returns current DMA mode */ |
222 | int ata_get_dma_mode(void); | 224 | int ata_get_dma_mode(void); |
diff --git a/firmware/export/storage.h b/firmware/export/storage.h index e2ae4056be..f97cbf34d5 100644 --- a/firmware/export/storage.h +++ b/firmware/export/storage.h | |||
@@ -174,7 +174,7 @@ static inline void storage_sleep(void) {}; | |||
174 | #define storage_disk_is_active() ata_disk_is_active() | 174 | #define storage_disk_is_active() ata_disk_is_active() |
175 | #define storage_soft_reset() ata_soft_reset() | 175 | #define storage_soft_reset() ata_soft_reset() |
176 | #ifdef HAVE_STORAGE_FLUSH | 176 | #ifdef HAVE_STORAGE_FLUSH |
177 | #define storage_flush() (void)0 | 177 | #define storage_flush() ata_flush() |
178 | #endif | 178 | #endif |
179 | #define storage_last_disk_activity() ata_last_disk_activity() | 179 | #define storage_last_disk_activity() ata_last_disk_activity() |
180 | #define storage_spinup_time() ata_spinup_time() | 180 | #define storage_spinup_time() ata_spinup_time() |
diff --git a/firmware/storage.c b/firmware/storage.c index da3e06146d..2d4490369e 100644 --- a/firmware/storage.c +++ b/firmware/storage.c | |||
@@ -555,7 +555,7 @@ int storage_flush(void) | |||
555 | int rc=0; | 555 | int rc=0; |
556 | 556 | ||
557 | #if (CONFIG_STORAGE & STORAGE_ATA) | 557 | #if (CONFIG_STORAGE & STORAGE_ATA) |
558 | //if ((rc=ata_flush())) return rc; | 558 | if ((rc=ata_flush())) return rc; |
559 | #endif | 559 | #endif |
560 | 560 | ||
561 | #if (CONFIG_STORAGE & STORAGE_MMC) | 561 | #if (CONFIG_STORAGE & STORAGE_MMC) |
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 | } |