diff options
Diffstat (limited to 'firmware/drivers/ata.c')
-rw-r--r-- | firmware/drivers/ata.c | 46 |
1 files changed, 42 insertions, 4 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index d2e1ad4a22..3514511270 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -18,6 +18,9 @@ | |||
18 | * KIND, either express or implied. | 18 | * KIND, either express or implied. |
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | |||
22 | //#define LOGF_ENABLE | ||
23 | |||
21 | #include <stdbool.h> | 24 | #include <stdbool.h> |
22 | #include <inttypes.h> | 25 | #include <inttypes.h> |
23 | #include "led.h" | 26 | #include "led.h" |
@@ -31,6 +34,15 @@ | |||
31 | #include "ata-defines.h" | 34 | #include "ata-defines.h" |
32 | #include "fs_defines.h" | 35 | #include "fs_defines.h" |
33 | #include "storage.h" | 36 | #include "storage.h" |
37 | #include "logf.h" | ||
38 | |||
39 | /* The FC1307A ATA->SD chipset (used by the common iFlash adapters) | ||
40 | doesn't support mandatory ATA power management commands. Unfortunately | ||
41 | simply gating off the SLEEP command isn't sufficient; we need to | ||
42 | disable advanced powersaving entirely because otherwise we might | ||
43 | kill power before the device has finished flusing writes. | ||
44 | */ | ||
45 | //#define FC1307A_WORKAROUND | ||
34 | 46 | ||
35 | #define SELECT_DEVICE1 0x10 | 47 | #define SELECT_DEVICE1 0x10 |
36 | #define SELECT_LBA 0x40 | 48 | #define SELECT_LBA 0x40 |
@@ -63,6 +75,7 @@ | |||
63 | 75 | ||
64 | #ifdef HAVE_ATA_POWER_OFF | 76 | #ifdef HAVE_ATA_POWER_OFF |
65 | #define ATA_POWER_OFF_TIMEOUT 2*HZ | 77 | #define ATA_POWER_OFF_TIMEOUT 2*HZ |
78 | #define ATA_POWER_OFF_TIMEOUT_NOPM 5*HZ | ||
66 | #endif | 79 | #endif |
67 | 80 | ||
68 | #if defined(HAVE_USBSTACK) | 81 | #if defined(HAVE_USBSTACK) |
@@ -147,7 +160,12 @@ static inline bool ata_sleep_timed_out(void) | |||
147 | static inline void schedule_ata_power_off(void) | 160 | static inline void schedule_ata_power_off(void) |
148 | { | 161 | { |
149 | #ifdef HAVE_ATA_POWER_OFF | 162 | #ifdef HAVE_ATA_POWER_OFF |
150 | power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT; | 163 | power_off_tick = current_tick; |
164 | /* If our device doesn't support SLEEP give a bit more time to flush */ | ||
165 | if (!(identify_info[82] & (1 << 3))) | ||
166 | power_off_tick += ATA_POWER_OFF_TIMEOUT_NOPM; | ||
167 | else | ||
168 | power_off_tick += ATA_POWER_OFF_TIMEOUT; | ||
151 | #endif | 169 | #endif |
152 | } | 170 | } |
153 | 171 | ||
@@ -202,6 +220,7 @@ static ICODE_ATTR int wait_for_rdy(void) | |||
202 | 220 | ||
203 | static int ata_perform_wakeup(int state) | 221 | static int ata_perform_wakeup(int state) |
204 | { | 222 | { |
223 | logf("ata WAKE %ld", current_tick); | ||
205 | if (state > ATA_OFF) { | 224 | if (state > ATA_OFF) { |
206 | if (perform_soft_reset()) { | 225 | if (perform_soft_reset()) { |
207 | return -1; | 226 | return -1; |
@@ -222,13 +241,12 @@ static int ata_perform_sleep(void) | |||
222 | { | 241 | { |
223 | /* Don't issue the sleep command if the device | 242 | /* Don't issue the sleep command if the device |
224 | doesn't support (mandatory!) ATA power management commands! | 243 | doesn't support (mandatory!) ATA power management commands! |
225 | |||
226 | The FC1307A ATA->SD chipset (used by the common iFlash adapters) | ||
227 | is the only known offender, and will eat your data if told to sleep. | ||
228 | */ | 244 | */ |
229 | if (!(identify_info[82] & (1 << 3))) | 245 | if (!(identify_info[82] & (1 << 3))) |
230 | return 0; | 246 | return 0; |
231 | 247 | ||
248 | logf("ata SLEEP %ld", current_tick); | ||
249 | |||
232 | ATA_OUT8(ATA_SELECT, ata_device); | 250 | ATA_OUT8(ATA_SELECT, ata_device); |
233 | 251 | ||
234 | if(!wait_for_rdy()) { | 252 | if(!wait_for_rdy()) { |
@@ -818,12 +836,26 @@ void ata_spindown(int seconds) | |||
818 | 836 | ||
819 | bool ata_disk_is_active(void) | 837 | bool ata_disk_is_active(void) |
820 | { | 838 | { |
839 | #ifdef FC1307A_WORKAROUND | ||
840 | /* "active" == "spinning" in this context. | ||
841 | without power management this becomes moot */ | ||
842 | if (!(identify_info[82] & (1 << 3))) | ||
843 | return false; | ||
844 | #endif | ||
845 | |||
821 | return ata_state >= ATA_SPINUP; | 846 | return ata_state >= ATA_SPINUP; |
822 | } | 847 | } |
823 | 848 | ||
824 | void ata_sleepnow(void) | 849 | void ata_sleepnow(void) |
825 | { | 850 | { |
851 | #ifdef FC1307A_WORKAROUND | ||
852 | /* Completely disable all power management */ | ||
853 | if (!(identify_info[82] & (1 << 3))) | ||
854 | return; | ||
855 | #endif | ||
856 | |||
826 | if (ata_state >= ATA_SPINUP) { | 857 | if (ata_state >= ATA_SPINUP) { |
858 | logf("ata SLEEPNOW %ld", current_tick); | ||
827 | mutex_lock(&ata_mtx); | 859 | mutex_lock(&ata_mtx); |
828 | if (ata_state == ATA_ON) { | 860 | if (ata_state == ATA_ON) { |
829 | if (!ata_perform_sleep()) { | 861 | if (!ata_perform_sleep()) { |
@@ -904,6 +936,8 @@ static int perform_soft_reset(void) | |||
904 | int ret; | 936 | int ret; |
905 | int retry_count; | 937 | int retry_count; |
906 | 938 | ||
939 | logf("ata SOFT RESET %ld", current_tick); | ||
940 | |||
907 | ATA_OUT8(ATA_SELECT, SELECT_LBA | ata_device ); | 941 | ATA_OUT8(ATA_SELECT, SELECT_LBA | ata_device ); |
908 | ATA_OUT8(ATA_CONTROL, CONTROL_nIEN|CONTROL_SRST ); | 942 | ATA_OUT8(ATA_CONTROL, CONTROL_nIEN|CONTROL_SRST ); |
909 | sleep(1); /* >= 5us */ | 943 | sleep(1); /* >= 5us */ |
@@ -960,6 +994,8 @@ static int ata_power_on(void) | |||
960 | { | 994 | { |
961 | int rc; | 995 | int rc; |
962 | 996 | ||
997 | logf("ata ON %ld", current_tick); | ||
998 | |||
963 | ide_power_enable(true); | 999 | ide_power_enable(true); |
964 | sleep(HZ/4); /* allow voltage to build up */ | 1000 | sleep(HZ/4); /* allow voltage to build up */ |
965 | 1001 | ||
@@ -1381,6 +1417,7 @@ int ata_event(long id, intptr_t data) | |||
1381 | if (state == ATA_SLEEPING && ata_power_off_timed_out()) { | 1417 | if (state == ATA_SLEEPING && ata_power_off_timed_out()) { |
1382 | mutex_lock(&ata_mtx); | 1418 | mutex_lock(&ata_mtx); |
1383 | if (ata_state == ATA_SLEEPING) { | 1419 | if (ata_state == ATA_SLEEPING) { |
1420 | logf("ata OFF %ld", current_tick); | ||
1384 | ide_power_enable(false); | 1421 | ide_power_enable(false); |
1385 | ata_state = ATA_OFF; | 1422 | ata_state = ATA_OFF; |
1386 | } | 1423 | } |
@@ -1397,6 +1434,7 @@ int ata_event(long id, intptr_t data) | |||
1397 | } | 1434 | } |
1398 | #ifndef USB_NONE | 1435 | #ifndef USB_NONE |
1399 | else if (id == SYS_USB_CONNECTED) { | 1436 | else if (id == SYS_USB_CONNECTED) { |
1437 | logf("deq USB %ld", current_tick); | ||
1400 | if (ATA_ACTIVE_IN_USB) { | 1438 | if (ATA_ACTIVE_IN_USB) { |
1401 | /* There is no need to force ATA power on */ | 1439 | /* There is no need to force ATA power on */ |
1402 | STG_EVENT_ASSERT_ACTIVE(STORAGE_ATA); | 1440 | STG_EVENT_ASSERT_ACTIVE(STORAGE_ATA); |