summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/ata.c52
-rw-r--r--firmware/export/ata.h6
-rw-r--r--firmware/export/storage.h2
-rw-r--r--firmware/storage.c2
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c103
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
104static bool lba48 = false; /* set for 48 bit addressing */ 104static bool lba48 = false; /* set for 48 bit addressing */
105#endif 105#endif
106static bool canflush = true;
106 107
107static long last_disk_activity = -1; 108static 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
144static inline void schedule_ata_sleep(long from_now)
145{
146 last_disk_activity = current_tick - sleep_timeout + from_now;
147}
148
149static inline bool ata_sleep_timed_out(void) 145static 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)
223static int ata_perform_sleep(void) 219static 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
290int 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
289static ICODE_ATTR int wait_for_start_of_transfer(void) 300static 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
845bool ata_disk_is_active(void) 856bool 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
850void ata_sleepnow(void) 861void 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
1328error: 1350error:
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 */
212static inline int ata_disk_can_poweroff(void) 212static 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
220int ata_flush(void);
221
220#ifdef HAVE_ATA_DMA 222#ifdef HAVE_ATA_DMA
221/* Returns current DMA mode */ 223/* Returns current DMA mode */
222int ata_get_dma_mode(void); 224int 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;
83static long ata_last_activity_value = -1; 83static long ata_last_activity_value = -1;
84static long ata_sleep_timeout = 7 * HZ; 84static long ata_sleep_timeout = 7 * HZ;
85static bool ata_powered; 85static bool ata_powered;
86static bool canflush = true;
86static struct semaphore mmc_wakeup; 87static struct semaphore mmc_wakeup;
87static struct semaphore mmc_comp_wakeup; 88static struct semaphore mmc_comp_wakeup;
88static int spinup_time = 0; 89static int spinup_time = 0;
@@ -578,7 +579,7 @@ static void ata_set_active(void)
578 579
579bool ata_disk_is_active(void) 580bool ata_disk_is_active(void)
580{ 581{
581 return ata_disk_can_poweroff() ? ata_powered : 0; 582 return ata_powered;
582} 583}
583 584
584static int ata_set_feature(uint32_t feature, uint32_t param) 585static 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
1095int 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
1110void ata_sleepnow(void) 1105void 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}