summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/drivers/ata.c2
-rw-r--r--firmware/export/ata.h3
-rw-r--r--firmware/target/arm/pp/ata-pp5020.c64
-rw-r--r--firmware/target/arm/pp/ata-target.h2
4 files changed, 43 insertions, 28 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index db39255256..ba0d6d169e 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -332,7 +332,7 @@ static ICODE_ATTR void copy_write_sectors(const unsigned char* buf,
}
#endif /* !ATA_OPTIMIZED_WRITING */
-static inline int ata_disk_isssd(void)
+int ata_disk_isssd(void)
{
/* offset 217 is "Nominal Rotation rate"
0x0000 == Not reported
diff --git a/firmware/export/ata.h b/firmware/export/ata.h
index e6ca9422ea..7c5fd3a8d0 100644
--- a/firmware/export/ata.h
+++ b/firmware/export/ata.h
@@ -165,6 +165,9 @@ int ata_num_drives(int first_drive);
long ata_last_disk_activity(void);
int ata_spinup_time(void); /* ticks */
+/* Returns 1 if drive is solid-state */
+int ata_disk_isssd(void);
+
#ifdef HAVE_ATA_DMA
/* Returns current DMA mode */
int ata_get_dma_mode(void);
diff --git a/firmware/target/arm/pp/ata-pp5020.c b/firmware/target/arm/pp/ata-pp5020.c
index 9b3158ecc7..77e77cae92 100644
--- a/firmware/target/arm/pp/ata-pp5020.c
+++ b/firmware/target/arm/pp/ata-pp5020.c
@@ -25,8 +25,9 @@
#include "system.h"
#include "kernel.h"
#include "ata-driver.h"
+#include "ata.h"
-void ata_reset()
+void ata_reset()
{
}
@@ -43,6 +44,17 @@ bool ata_is_coldstart()
/* TODO: Implement coldstart variable */
}
+/* These are PIO timings for 80 Mhz. At 24 Mhz, the first value is 0 but the
+ rest are the same. They go in IDE0_PRI_TIMING0.
+
+ Rockbox used to use 0x10, and test_disk shows that leads to faster PIO.
+ However on some disks connected with mSATA adapters this causes corrupt data
+ so we now just use these timings from the OF.
+*/
+static const unsigned long pio80mhz[] = {
+ 0xC293, 0x43A2, 0x11A1, 0x7232, 0x3131
+};
+
void ata_device_init()
{
#ifdef SAMSUNG_YH920
@@ -52,7 +64,7 @@ void ata_device_init()
IDE_DMA_CONTROL |= 2;
IDE_DMA_CONTROL &= ~1;
IDE0_CFG &= ~0x8010;
- IDE0_CFG |= 0x20;
+ IDE0_CFG |= 0x20;
#else
/* From ipod-ide.c:ipod_ide_register() */
@@ -64,33 +76,31 @@ void ata_device_init()
#endif
#endif
- IDE0_PRI_TIMING0 = 0x10;
+ IDE0_PRI_TIMING0 = pio80mhz[0];
IDE0_PRI_TIMING1 = 0x80002150;
}
-/* These are PIO timings for 80 Mhz. At 24 Mhz,
- the first value is 0 but the rest are the same.
- They go in IDE0_PRI_TIMING0.
-
- Rockbox used 0x10, and test_disk shows that leads to faster PIO.
- If 0x10 is incorrect, these timings may be needed with some devices.
-static const unsigned long pio80mhz[] = {
- 0xC293, 0x43A2, 0x11A1, 0x7232, 0x3131
-};
-*/
+/* Setup the timing for PIO mode */
+void ata_set_pio_timings(int mode)
+{
+ if (ata_disk_isssd())
+ IDE0_PRI_TIMING0 = pio80mhz[mode];
+ else
+ IDE0_PRI_TIMING0 = 0x10;
+}
#ifdef HAVE_ATA_DMA
/* Timings for multi-word and ultra DMA modes.
These go in IDE0_PRI_TIMING1
*/
static const unsigned long tm_mwdma[] = {
- 0xF9F92, 0x56562, 0x45451
+ 0xF9F92, 0x56562, 0x45451
};
-static const unsigned long tm_udma[] = {
- 0x800037C1, 0x80003491, 0x80003371,
-#if ATA_MAX_UDMA > 2
- 0x80003271, 0x80003071
+static const unsigned long tm_udma[] = {
+ 0x800037C1, 0x80003491, 0x80003371,
+#if ATA_MAX_UDMA > 2
+ 0x80003271, 0x80003071
#endif
};
@@ -126,7 +136,7 @@ void ata_dma_set_mode(unsigned char mode) {
#if !defined(IPOD_NANO)
IDE0_CFG |= 0x20000000; /* >= 50 Mhz */
#endif
-}
+}
#define IDE_CFG_INTRQ 8
#define IDE_DMA_CONTROL_READ 8
@@ -137,8 +147,8 @@ void ata_dma_set_mode(unsigned char mode) {
static ICODE_ATTR int ata_wait_intrq(void)
{
long timeout = current_tick + HZ*10;
-
- do
+
+ do
{
if (IDE0_CFG & IDE_CFG_INTRQ)
return 1;
@@ -149,11 +159,11 @@ static ICODE_ATTR int ata_wait_intrq(void)
return 0; /* timeout */
}
-/* This function checks if parameters are appropriate for DMA,
+/* This function checks if parameters are appropriate for DMA,
and if they are, it sets up for DMA.
-
+
If return value is false, caller may use PIO for this transfer.
-
+
If return value is true, caller must issue a DMA ATA command
and then call ata_dma_finish().
*/
@@ -217,18 +227,18 @@ bool ata_dma_setup(void *addr, unsigned long bytes, bool write) {
/* This function waits for a DMA transfer to end.
It must be called to finish what ata_dma_setup started.
-
+
Return value is true if DMA completed before the timeout, and false
if a timeout happened.
*/
bool ata_dma_finish(void) {
bool res;
-
+
/* It may be okay to put this at the end of setup */
IDE_DMA_CONTROL |= 1;
/* Wait for end of transfer.
- Reading standard ATA status while DMA is in progress causes
+ Reading standard ATA status while DMA is in progress causes
failures and hangs. Because of that, another wait is used.
*/
res = ata_wait_intrq();
diff --git a/firmware/target/arm/pp/ata-target.h b/firmware/target/arm/pp/ata-target.h
index a11aeda36d..75570bf3cd 100644
--- a/firmware/target/arm/pp/ata-target.h
+++ b/firmware/target/arm/pp/ata-target.h
@@ -49,6 +49,8 @@
#define ATA_OPTIMIZED_READING
#define ATA_OPTIMIZED_WRITING
+#define ATA_SET_PIO_TIMING
+
#endif /* CONFIG_CPU */
#ifdef HAVE_ATA_DMA