summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/export/config/gogearhdd1630.h5
-rw-r--r--firmware/export/config/ipod4g.h5
-rw-r--r--firmware/export/config/ipodcolor.h5
-rw-r--r--firmware/export/config/ipodmini1g.h5
-rw-r--r--firmware/export/config/ipodmini2g.h5
-rw-r--r--firmware/export/config/ipodnano1g.h5
-rw-r--r--firmware/export/config/ipodvideo.h4
-rw-r--r--firmware/export/config/iriverh10.h5
-rw-r--r--firmware/export/config/iriverh10_5gb.h5
-rw-r--r--firmware/export/config/mrobe100.h5
-rw-r--r--firmware/export/config/samsungyh820.h5
-rw-r--r--firmware/export/config/samsungyh920.h5
-rw-r--r--firmware/export/config/samsungyh925.h5
-rw-r--r--firmware/export/config/tatungtpj1022.h5
-rw-r--r--firmware/target/arm/ata-pp5020.c183
-rw-r--r--firmware/target/arm/ata-target.h34
16 files changed, 286 insertions, 0 deletions
diff --git a/firmware/export/config/gogearhdd1630.h b/firmware/export/config/gogearhdd1630.h
index 912ba42..8bb1480 100644
--- a/firmware/export/config/gogearhdd1630.h
+++ b/firmware/export/config/gogearhdd1630.h
@@ -200,3 +200,8 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipod4g.h b/firmware/export/config/ipod4g.h
index e6bdc35..cd71434 100644
--- a/firmware/export/config/ipod4g.h
+++ b/firmware/export/config/ipod4g.h
@@ -207,3 +207,8 @@
#define IRAM_LCDFRAMEBUFFER IBSS_ATTR /* put the lcd frame buffer in IRAM */
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipodcolor.h b/firmware/export/config/ipodcolor.h
index 0f1de4f..c0168d9 100644
--- a/firmware/export/config/ipodcolor.h
+++ b/firmware/export/config/ipodcolor.h
@@ -182,3 +182,8 @@
#define IPOD_ACCESSORY_PROTOCOL
#define HAVE_SERIAL
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipodmini1g.h b/firmware/export/config/ipodmini1g.h
index 129829f..3ab96e3 100644
--- a/firmware/export/config/ipodmini1g.h
+++ b/firmware/export/config/ipodmini1g.h
@@ -193,3 +193,8 @@
#define IRAM_LCDFRAMEBUFFER IBSS_ATTR /* put the lcd frame buffer in IRAM */
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipodmini2g.h b/firmware/export/config/ipodmini2g.h
index 8087269..72e04a3 100644
--- a/firmware/export/config/ipodmini2g.h
+++ b/firmware/export/config/ipodmini2g.h
@@ -203,3 +203,8 @@
#define IRAM_LCDFRAMEBUFFER IBSS_ATTR /* put the lcd frame buffer in IRAM */
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipodnano1g.h b/firmware/export/config/ipodnano1g.h
index 5f63c26..562c940 100644
--- a/firmware/export/config/ipodnano1g.h
+++ b/firmware/export/config/ipodnano1g.h
@@ -192,3 +192,8 @@
#define IPOD_ACCESSORY_PROTOCOL
#define HAVE_SERIAL
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipodvideo.h b/firmware/export/config/ipodvideo.h
index 9aa1d49..d188696 100644
--- a/firmware/export/config/ipodvideo.h
+++ b/firmware/export/config/ipodvideo.h
@@ -224,3 +224,7 @@
#define IPOD_ACCESSORY_PROTOCOL
#define HAVE_SERIAL
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/iriverh10.h b/firmware/export/config/iriverh10.h
index cde1b60..5365c83 100644
--- a/firmware/export/config/iriverh10.h
+++ b/firmware/export/config/iriverh10.h
@@ -186,3 +186,8 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/iriverh10_5gb.h b/firmware/export/config/iriverh10_5gb.h
index e69f6c2..bfc9b8a 100644
--- a/firmware/export/config/iriverh10_5gb.h
+++ b/firmware/export/config/iriverh10_5gb.h
@@ -169,3 +169,8 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
#endif
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/mrobe100.h b/firmware/export/config/mrobe100.h
index 9041991..2bbb039 100644
--- a/firmware/export/config/mrobe100.h
+++ b/firmware/export/config/mrobe100.h
@@ -200,3 +200,8 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/samsungyh820.h b/firmware/export/config/samsungyh820.h
index 4968960..0ca244a 100644
--- a/firmware/export/config/samsungyh820.h
+++ b/firmware/export/config/samsungyh820.h
@@ -181,3 +181,8 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/samsungyh920.h b/firmware/export/config/samsungyh920.h
index 310fa13..a6a57f7 100644
--- a/firmware/export/config/samsungyh920.h
+++ b/firmware/export/config/samsungyh920.h
@@ -187,3 +187,8 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/samsungyh925.h b/firmware/export/config/samsungyh925.h
index 55d46ae..c19901c 100644
--- a/firmware/export/config/samsungyh925.h
+++ b/firmware/export/config/samsungyh925.h
@@ -185,3 +185,8 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/export/config/tatungtpj1022.h b/firmware/export/config/tatungtpj1022.h
index 079be73..aca131d 100644
--- a/firmware/export/config/tatungtpj1022.h
+++ b/firmware/export/config/tatungtpj1022.h
@@ -137,3 +137,8 @@
#define BOOTFILE "rockbox." BOOTFILE_EXT
#define BOOTDIR "/.rockbox"
+
+/* DMA is used only for reading on PP502x because although reads are ~8x faster
+ * writes appear to be ~25% slower.
+ */
+#define HAVE_ATA_DMA
diff --git a/firmware/target/arm/ata-pp5020.c b/firmware/target/arm/ata-pp5020.c
index 8e2200c..c8ce148 100644
--- a/firmware/target/arm/ata-pp5020.c
+++ b/firmware/target/arm/ata-pp5020.c
@@ -48,6 +48,12 @@ void ata_device_init()
#ifdef SAMSUNG_YH920
CPU_INT_DIS = (1<<IDE_IRQ);
#endif
+#ifdef HAVE_ATA_DMA
+ IDE_DMA_CONTROL |= 2;
+ IDE_DMA_CONTROL &= ~1;
+ IDE0_CFG &= ~0x8010;
+ IDE0_CFG |= 0x20;
+#else
/* From ipod-ide.c:ipod_ide_register() */
IDE0_CFG |= (1<<5);
@@ -56,7 +62,184 @@ void ata_device_init()
#else
IDE0_CFG &=~(0x10000000); /* cpu < 65MHz */
#endif
+#endif
IDE0_PRI_TIMING0 = 0x10;
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
+};
+*/
+
+#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
+};
+
+static const unsigned long tm_udma[] = {
+ 0x800037C1, 0x80003491, 0x80003371,
+#if ATA_MAX_UDMA > 2
+ 0x80003271, 0x80003071
+#endif
+};
+
+#if ATA_MAX_UDMA > 2
+static bool dma_boosted = false;
+static bool dma_needs_boost;
+#endif
+
+/* This function sets up registers for 80 Mhz.
+ Ultra DMA mode 2 works at 30 Mhz.
+ */
+void ata_dma_set_mode(unsigned char mode) {
+ int modeidx;
+
+ (*(volatile unsigned long *)(0x600060C4)) = 0xC0000000; /* 80 Mhz */
+ IDE0_CFG &= ~0x10000000;
+
+ modeidx = mode & 7;
+ mode &= 0xF8;
+ if (mode == 0x40 && modeidx <= ATA_MAX_UDMA) {
+ IDE0_PRI_TIMING1 = tm_udma[modeidx];
+#if ATA_MAX_UDMA > 2
+ if (modeidx > 2)
+ dma_needs_boost = true;
+ else
+ dma_needs_boost = false;
+#endif
+ } else if (mode == 0x20 && modeidx <= ATA_MAX_MWDMA)
+ IDE0_PRI_TIMING1 = tm_mwdma[modeidx];
+
+ IDE0_CFG |= 0x20000000; /* >= 50 Mhz */
+}
+
+#define IDE_CFG_INTRQ 8
+#define IDE_DMA_CONTROL_READ 8
+
+/* This waits for an ATA interrupt using polling.
+ In ATA_CONTROL, CONTROL_nIEN must be cleared.
+ */
+STATICIRAM ICODE_ATTR int ata_wait_intrq(void)
+{
+ long timeout = current_tick + HZ*10;
+
+ do
+ {
+ if (IDE0_CFG & IDE_CFG_INTRQ)
+ return 1;
+ ata_keep_active();
+ yield();
+ } while (TIME_BEFORE(current_tick, timeout));
+
+ return 0; /* timeout */
+}
+
+/* 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().
+ */
+bool ata_dma_setup(void *addr, unsigned long bytes, bool write) {
+ /* Require cacheline alignment for reads to prevent interference. */
+ if (!write && ((unsigned long)addr & 15))
+ return false;
+
+ /* Writes only need to be word-aligned, but by default DMA
+ * is not used for writing as it appears to be slower.
+ */
+#ifdef ATA_DMA_WRITES
+ if (write && ((unsigned long)addr & 3))
+ return false;
+#else
+ if (write)
+ return false;
+#endif
+
+#if ATA_MAX_UDMA > 2
+ if (dma_needs_boost && !dma_boosted) {
+ cpu_boost(true);
+ dma_boosted = true;
+ }
+#endif
+
+ if (write) {
+ /* If unflushed, old data may be written to disk */
+ cpucache_flush();
+ }
+ else {
+ /* Invalidate cache because new data may be present in RAM */
+ cpucache_invalidate();
+ }
+
+ /* Clear pending interrupts so ata_dma_finish() can wait for an
+ interrupt from this transfer
+ */
+ IDE0_CFG |= IDE_CFG_INTRQ;
+
+ IDE_DMA_CONTROL |= 2;
+ IDE_DMA_LENGTH = bytes - 4;
+
+#ifndef BOOTLOADER
+ if ((unsigned long)addr < DRAM_START)
+ /* Rockbox remaps DRAM to start at 0 */
+ IDE_DMA_ADDR = (unsigned long)addr + DRAM_START;
+ else
+#endif
+ IDE_DMA_ADDR = (unsigned long)addr;
+
+ if (write)
+ IDE_DMA_CONTROL &= ~IDE_DMA_CONTROL_READ;
+ else
+ IDE_DMA_CONTROL |= IDE_DMA_CONTROL_READ;
+
+ IDE0_CFG |= 0x8000;
+
+ return true;
+}
+
+/* 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
+ failures and hangs. Because of that, another wait is used.
+ */
+ res = ata_wait_intrq();
+
+ IDE0_CFG &= ~0x8000;
+ IDE_DMA_CONTROL &= ~0x80000001;
+
+#if ATA_MAX_UDMA > 2
+ if (dma_boosted) {
+ cpu_boost(false);
+ dma_boosted = false;
+ }
+#endif
+
+ return res;
+}
+
+#endif /* HAVE_ATA_DMA */
diff --git a/firmware/target/arm/ata-target.h b/firmware/target/arm/ata-target.h
index 0881aae..82c5a5f 100644
--- a/firmware/target/arm/ata-target.h
+++ b/firmware/target/arm/ata-target.h
@@ -81,3 +81,37 @@ void copy_write_sectors(const unsigned char* buf, int wordcount);
void ata_reset(void);
bool ata_is_coldstart(void);
void ata_device_init(void);
+
+#ifdef HAVE_ATA_DMA
+
+/* IDE DMA controller registers */
+#define IDE_DMA_CONTROL (*(volatile unsigned long *)(0xc3000400))
+#define IDE_DMA_LENGTH (*(volatile unsigned long *)(0xc3000408))
+#define IDE_DMA_ADDR (*(volatile unsigned long *)(0xc300040C))
+
+/* Maximum multi-word DMA mode supported by the controller */
+#define ATA_MAX_MWDMA 2
+
+#ifndef BOOTLOADER
+/* The PP5020 supports UDMA 4, but it needs cpu boosting and only
+ * improves performance by ~10% with a stock disk.
+ * UDMA 2 is stable at 30 Mhz.
+ * UDMA 1 is stable at 24 Mhz.
+ */
+#if CPUFREQ_NORMAL >= 30000000
+#define ATA_MAX_UDMA 2
+#elif CPUFREQ_NORMAL >= 24000000
+#define ATA_MAX_UDMA 1
+#else
+#error "CPU speeds under 24Mhz have not been tested with DMA"
+#endif
+#else
+/* The bootloader runs at 24 Mhz and needs a slower mode */
+#define ATA_MAX_UDMA 1
+#endif
+
+void ata_dma_set_mode(unsigned char mode);
+bool ata_dma_setup(void *addr, unsigned long bytes, bool write);
+bool ata_dma_finish(void);
+
+#endif /* HAVE_ATA_DMA */