summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorne Wuff <torne@wolfpuppy.org.uk>2010-01-31 11:07:29 +0000
committerTorne Wuff <torne@wolfpuppy.org.uk>2010-01-31 11:07:29 +0000
commit533cf7737bae4363edefbfb202cb44e9eb30cd3f (patch)
treeabfb69b76b46fc8d22c14023969ba3fcaad4809d
parentc0e2d9fe1bb87730d9a8a7cac3cb8f6cd39ce630 (diff)
downloadrockbox-533cf7737bae4363edefbfb202cb44e9eb30cd3f.tar.gz
rockbox-533cf7737bae4363edefbfb202cb44e9eb30cd3f.zip
Enable ATA DMA on pp5020 based players with ATA drives.
DMA is only used for reading because writing seems to be slower with DMA. Only requests which are cacheline aligned (16 bytes) will use DMA, so many requests will still use PIO at this point; a later change will align more reads. Part of FS#9708, original DMA code by Boris Gjenero (dreamlayers). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24405 a1c6a512-1295-4272-9138-f99709370657
-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 912ba427c0..8bb14801b0 100644
--- a/firmware/export/config/gogearhdd1630.h
+++ b/firmware/export/config/gogearhdd1630.h
@@ -200,3 +200,8 @@
200 200
201#define ICODE_ATTR_TREMOR_NOT_MDCT 201#define ICODE_ATTR_TREMOR_NOT_MDCT
202 202
203
204/* DMA is used only for reading on PP502x because although reads are ~8x faster
205 * writes appear to be ~25% slower.
206 */
207#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipod4g.h b/firmware/export/config/ipod4g.h
index e6bdc35bd8..cd71434c10 100644
--- a/firmware/export/config/ipod4g.h
+++ b/firmware/export/config/ipod4g.h
@@ -207,3 +207,8 @@
207 207
208#define IRAM_LCDFRAMEBUFFER IBSS_ATTR /* put the lcd frame buffer in IRAM */ 208#define IRAM_LCDFRAMEBUFFER IBSS_ATTR /* put the lcd frame buffer in IRAM */
209 209
210
211/* DMA is used only for reading on PP502x because although reads are ~8x faster
212 * writes appear to be ~25% slower.
213 */
214#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipodcolor.h b/firmware/export/config/ipodcolor.h
index 0f1de4fdba..c0168d9886 100644
--- a/firmware/export/config/ipodcolor.h
+++ b/firmware/export/config/ipodcolor.h
@@ -182,3 +182,8 @@
182#define IPOD_ACCESSORY_PROTOCOL 182#define IPOD_ACCESSORY_PROTOCOL
183#define HAVE_SERIAL 183#define HAVE_SERIAL
184 184
185
186/* DMA is used only for reading on PP502x because although reads are ~8x faster
187 * writes appear to be ~25% slower.
188 */
189#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipodmini1g.h b/firmware/export/config/ipodmini1g.h
index 129829ffbb..3ab96e3a62 100644
--- a/firmware/export/config/ipodmini1g.h
+++ b/firmware/export/config/ipodmini1g.h
@@ -193,3 +193,8 @@
193 193
194#define IRAM_LCDFRAMEBUFFER IBSS_ATTR /* put the lcd frame buffer in IRAM */ 194#define IRAM_LCDFRAMEBUFFER IBSS_ATTR /* put the lcd frame buffer in IRAM */
195 195
196
197/* DMA is used only for reading on PP502x because although reads are ~8x faster
198 * writes appear to be ~25% slower.
199 */
200#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipodmini2g.h b/firmware/export/config/ipodmini2g.h
index 8087269485..72e04a30db 100644
--- a/firmware/export/config/ipodmini2g.h
+++ b/firmware/export/config/ipodmini2g.h
@@ -203,3 +203,8 @@
203 203
204#define IRAM_LCDFRAMEBUFFER IBSS_ATTR /* put the lcd frame buffer in IRAM */ 204#define IRAM_LCDFRAMEBUFFER IBSS_ATTR /* put the lcd frame buffer in IRAM */
205 205
206
207/* DMA is used only for reading on PP502x because although reads are ~8x faster
208 * writes appear to be ~25% slower.
209 */
210#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipodnano1g.h b/firmware/export/config/ipodnano1g.h
index 5f63c269ed..562c940df4 100644
--- a/firmware/export/config/ipodnano1g.h
+++ b/firmware/export/config/ipodnano1g.h
@@ -192,3 +192,8 @@
192#define IPOD_ACCESSORY_PROTOCOL 192#define IPOD_ACCESSORY_PROTOCOL
193#define HAVE_SERIAL 193#define HAVE_SERIAL
194 194
195
196/* DMA is used only for reading on PP502x because although reads are ~8x faster
197 * writes appear to be ~25% slower.
198 */
199#define HAVE_ATA_DMA
diff --git a/firmware/export/config/ipodvideo.h b/firmware/export/config/ipodvideo.h
index 9aa1d49547..d188696e64 100644
--- a/firmware/export/config/ipodvideo.h
+++ b/firmware/export/config/ipodvideo.h
@@ -224,3 +224,7 @@
224#define IPOD_ACCESSORY_PROTOCOL 224#define IPOD_ACCESSORY_PROTOCOL
225#define HAVE_SERIAL 225#define HAVE_SERIAL
226 226
227/* DMA is used only for reading on PP502x because although reads are ~8x faster
228 * writes appear to be ~25% slower.
229 */
230#define HAVE_ATA_DMA
diff --git a/firmware/export/config/iriverh10.h b/firmware/export/config/iriverh10.h
index cde1b6075e..5365c83239 100644
--- a/firmware/export/config/iriverh10.h
+++ b/firmware/export/config/iriverh10.h
@@ -186,3 +186,8 @@
186 186
187#define ICODE_ATTR_TREMOR_NOT_MDCT 187#define ICODE_ATTR_TREMOR_NOT_MDCT
188 188
189
190/* DMA is used only for reading on PP502x because although reads are ~8x faster
191 * writes appear to be ~25% slower.
192 */
193#define HAVE_ATA_DMA
diff --git a/firmware/export/config/iriverh10_5gb.h b/firmware/export/config/iriverh10_5gb.h
index e69f6c2b20..bfc9b8ac2e 100644
--- a/firmware/export/config/iriverh10_5gb.h
+++ b/firmware/export/config/iriverh10_5gb.h
@@ -169,3 +169,8 @@
169#define ICODE_ATTR_TREMOR_NOT_MDCT 169#define ICODE_ATTR_TREMOR_NOT_MDCT
170 170
171#endif 171#endif
172
173/* DMA is used only for reading on PP502x because although reads are ~8x faster
174 * writes appear to be ~25% slower.
175 */
176#define HAVE_ATA_DMA
diff --git a/firmware/export/config/mrobe100.h b/firmware/export/config/mrobe100.h
index 90419914b2..2bbb03919d 100644
--- a/firmware/export/config/mrobe100.h
+++ b/firmware/export/config/mrobe100.h
@@ -200,3 +200,8 @@
200 200
201#define ICODE_ATTR_TREMOR_NOT_MDCT 201#define ICODE_ATTR_TREMOR_NOT_MDCT
202 202
203
204/* DMA is used only for reading on PP502x because although reads are ~8x faster
205 * writes appear to be ~25% slower.
206 */
207#define HAVE_ATA_DMA
diff --git a/firmware/export/config/samsungyh820.h b/firmware/export/config/samsungyh820.h
index 4968960803..0ca244ae39 100644
--- a/firmware/export/config/samsungyh820.h
+++ b/firmware/export/config/samsungyh820.h
@@ -181,3 +181,8 @@
181 181
182#define ICODE_ATTR_TREMOR_NOT_MDCT 182#define ICODE_ATTR_TREMOR_NOT_MDCT
183 183
184
185/* DMA is used only for reading on PP502x because although reads are ~8x faster
186 * writes appear to be ~25% slower.
187 */
188#define HAVE_ATA_DMA
diff --git a/firmware/export/config/samsungyh920.h b/firmware/export/config/samsungyh920.h
index 310fa1374c..a6a57f7227 100644
--- a/firmware/export/config/samsungyh920.h
+++ b/firmware/export/config/samsungyh920.h
@@ -187,3 +187,8 @@
187 187
188#define ICODE_ATTR_TREMOR_NOT_MDCT 188#define ICODE_ATTR_TREMOR_NOT_MDCT
189 189
190
191/* DMA is used only for reading on PP502x because although reads are ~8x faster
192 * writes appear to be ~25% slower.
193 */
194#define HAVE_ATA_DMA
diff --git a/firmware/export/config/samsungyh925.h b/firmware/export/config/samsungyh925.h
index 55d46ae1e1..c19901c019 100644
--- a/firmware/export/config/samsungyh925.h
+++ b/firmware/export/config/samsungyh925.h
@@ -185,3 +185,8 @@
185 185
186#define ICODE_ATTR_TREMOR_NOT_MDCT 186#define ICODE_ATTR_TREMOR_NOT_MDCT
187 187
188
189/* DMA is used only for reading on PP502x because although reads are ~8x faster
190 * writes appear to be ~25% slower.
191 */
192#define HAVE_ATA_DMA
diff --git a/firmware/export/config/tatungtpj1022.h b/firmware/export/config/tatungtpj1022.h
index 079be73c86..aca131df8b 100644
--- a/firmware/export/config/tatungtpj1022.h
+++ b/firmware/export/config/tatungtpj1022.h
@@ -137,3 +137,8 @@
137#define BOOTFILE "rockbox." BOOTFILE_EXT 137#define BOOTFILE "rockbox." BOOTFILE_EXT
138#define BOOTDIR "/.rockbox" 138#define BOOTDIR "/.rockbox"
139 139
140
141/* DMA is used only for reading on PP502x because although reads are ~8x faster
142 * writes appear to be ~25% slower.
143 */
144#define HAVE_ATA_DMA
diff --git a/firmware/target/arm/ata-pp5020.c b/firmware/target/arm/ata-pp5020.c
index 8e2200c901..c8ce148dd7 100644
--- a/firmware/target/arm/ata-pp5020.c
+++ b/firmware/target/arm/ata-pp5020.c
@@ -48,6 +48,12 @@ void ata_device_init()
48#ifdef SAMSUNG_YH920 48#ifdef SAMSUNG_YH920
49 CPU_INT_DIS = (1<<IDE_IRQ); 49 CPU_INT_DIS = (1<<IDE_IRQ);
50#endif 50#endif
51#ifdef HAVE_ATA_DMA
52 IDE_DMA_CONTROL |= 2;
53 IDE_DMA_CONTROL &= ~1;
54 IDE0_CFG &= ~0x8010;
55 IDE0_CFG |= 0x20;
56#else
51 57
52 /* From ipod-ide.c:ipod_ide_register() */ 58 /* From ipod-ide.c:ipod_ide_register() */
53 IDE0_CFG |= (1<<5); 59 IDE0_CFG |= (1<<5);
@@ -56,7 +62,184 @@ void ata_device_init()
56#else 62#else
57 IDE0_CFG &=~(0x10000000); /* cpu < 65MHz */ 63 IDE0_CFG &=~(0x10000000); /* cpu < 65MHz */
58#endif 64#endif
65#endif
59 66
60 IDE0_PRI_TIMING0 = 0x10; 67 IDE0_PRI_TIMING0 = 0x10;
61 IDE0_PRI_TIMING1 = 0x80002150; 68 IDE0_PRI_TIMING1 = 0x80002150;
62} 69}
70
71/* These are PIO timings for 80 Mhz. At 24 Mhz,
72 the first value is 0 but the rest are the same.
73 They go in IDE0_PRI_TIMING0.
74
75 Rockbox used 0x10, and test_disk shows that leads to faster PIO.
76 If 0x10 is incorrect, these timings may be needed with some devices.
77static const unsigned long pio80mhz[] = {
78 0xC293, 0x43A2, 0x11A1, 0x7232, 0x3131
79};
80*/
81
82#ifdef HAVE_ATA_DMA
83/* Timings for multi-word and ultra DMA modes.
84 These go in IDE0_PRI_TIMING1
85 */
86static const unsigned long tm_mwdma[] = {
87 0xF9F92, 0x56562, 0x45451
88};
89
90static const unsigned long tm_udma[] = {
91 0x800037C1, 0x80003491, 0x80003371,
92#if ATA_MAX_UDMA > 2
93 0x80003271, 0x80003071
94#endif
95};
96
97#if ATA_MAX_UDMA > 2
98static bool dma_boosted = false;
99static bool dma_needs_boost;
100#endif
101
102/* This function sets up registers for 80 Mhz.
103 Ultra DMA mode 2 works at 30 Mhz.
104 */
105void ata_dma_set_mode(unsigned char mode) {
106 int modeidx;
107
108 (*(volatile unsigned long *)(0x600060C4)) = 0xC0000000; /* 80 Mhz */
109 IDE0_CFG &= ~0x10000000;
110
111 modeidx = mode & 7;
112 mode &= 0xF8;
113 if (mode == 0x40 && modeidx <= ATA_MAX_UDMA) {
114 IDE0_PRI_TIMING1 = tm_udma[modeidx];
115#if ATA_MAX_UDMA > 2
116 if (modeidx > 2)
117 dma_needs_boost = true;
118 else
119 dma_needs_boost = false;
120#endif
121 } else if (mode == 0x20 && modeidx <= ATA_MAX_MWDMA)
122 IDE0_PRI_TIMING1 = tm_mwdma[modeidx];
123
124 IDE0_CFG |= 0x20000000; /* >= 50 Mhz */
125}
126
127#define IDE_CFG_INTRQ 8
128#define IDE_DMA_CONTROL_READ 8
129
130/* This waits for an ATA interrupt using polling.
131 In ATA_CONTROL, CONTROL_nIEN must be cleared.
132 */
133STATICIRAM ICODE_ATTR int ata_wait_intrq(void)
134{
135 long timeout = current_tick + HZ*10;
136
137 do
138 {
139 if (IDE0_CFG & IDE_CFG_INTRQ)
140 return 1;
141 ata_keep_active();
142 yield();
143 } while (TIME_BEFORE(current_tick, timeout));
144
145 return 0; /* timeout */
146}
147
148/* This function checks if parameters are appropriate for DMA,
149 and if they are, it sets up for DMA.
150
151 If return value is false, caller may use PIO for this transfer.
152
153 If return value is true, caller must issue a DMA ATA command
154 and then call ata_dma_finish().
155 */
156bool ata_dma_setup(void *addr, unsigned long bytes, bool write) {
157 /* Require cacheline alignment for reads to prevent interference. */
158 if (!write && ((unsigned long)addr & 15))
159 return false;
160
161 /* Writes only need to be word-aligned, but by default DMA
162 * is not used for writing as it appears to be slower.
163 */
164#ifdef ATA_DMA_WRITES
165 if (write && ((unsigned long)addr & 3))
166 return false;
167#else
168 if (write)
169 return false;
170#endif
171
172#if ATA_MAX_UDMA > 2
173 if (dma_needs_boost && !dma_boosted) {
174 cpu_boost(true);
175 dma_boosted = true;
176 }
177#endif
178
179 if (write) {
180 /* If unflushed, old data may be written to disk */
181 cpucache_flush();
182 }
183 else {
184 /* Invalidate cache because new data may be present in RAM */
185 cpucache_invalidate();
186 }
187
188 /* Clear pending interrupts so ata_dma_finish() can wait for an
189 interrupt from this transfer
190 */
191 IDE0_CFG |= IDE_CFG_INTRQ;
192
193 IDE_DMA_CONTROL |= 2;
194 IDE_DMA_LENGTH = bytes - 4;
195
196#ifndef BOOTLOADER
197 if ((unsigned long)addr < DRAM_START)
198 /* Rockbox remaps DRAM to start at 0 */
199 IDE_DMA_ADDR = (unsigned long)addr + DRAM_START;
200 else
201#endif
202 IDE_DMA_ADDR = (unsigned long)addr;
203
204 if (write)
205 IDE_DMA_CONTROL &= ~IDE_DMA_CONTROL_READ;
206 else
207 IDE_DMA_CONTROL |= IDE_DMA_CONTROL_READ;
208
209 IDE0_CFG |= 0x8000;
210
211 return true;
212}
213
214/* This function waits for a DMA transfer to end.
215 It must be called to finish what ata_dma_setup started.
216
217 Return value is true if DMA completed before the timeout, and false
218 if a timeout happened.
219 */
220bool ata_dma_finish(void) {
221 bool res;
222
223 /* It may be okay to put this at the end of setup */
224 IDE_DMA_CONTROL |= 1;
225
226 /* Wait for end of transfer.
227 Reading standard ATA status while DMA is in progress causes
228 failures and hangs. Because of that, another wait is used.
229 */
230 res = ata_wait_intrq();
231
232 IDE0_CFG &= ~0x8000;
233 IDE_DMA_CONTROL &= ~0x80000001;
234
235#if ATA_MAX_UDMA > 2
236 if (dma_boosted) {
237 cpu_boost(false);
238 dma_boosted = false;
239 }
240#endif
241
242 return res;
243}
244
245#endif /* HAVE_ATA_DMA */
diff --git a/firmware/target/arm/ata-target.h b/firmware/target/arm/ata-target.h
index 0881aaef35..82c5a5f555 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);
81void ata_reset(void); 81void ata_reset(void);
82bool ata_is_coldstart(void); 82bool ata_is_coldstart(void);
83void ata_device_init(void); 83void ata_device_init(void);
84
85#ifdef HAVE_ATA_DMA
86
87/* IDE DMA controller registers */
88#define IDE_DMA_CONTROL (*(volatile unsigned long *)(0xc3000400))
89#define IDE_DMA_LENGTH (*(volatile unsigned long *)(0xc3000408))
90#define IDE_DMA_ADDR (*(volatile unsigned long *)(0xc300040C))
91
92/* Maximum multi-word DMA mode supported by the controller */
93#define ATA_MAX_MWDMA 2
94
95#ifndef BOOTLOADER
96/* The PP5020 supports UDMA 4, but it needs cpu boosting and only
97 * improves performance by ~10% with a stock disk.
98 * UDMA 2 is stable at 30 Mhz.
99 * UDMA 1 is stable at 24 Mhz.
100 */
101#if CPUFREQ_NORMAL >= 30000000
102#define ATA_MAX_UDMA 2
103#elif CPUFREQ_NORMAL >= 24000000
104#define ATA_MAX_UDMA 1
105#else
106#error "CPU speeds under 24Mhz have not been tested with DMA"
107#endif
108#else
109/* The bootloader runs at 24 Mhz and needs a slower mode */
110#define ATA_MAX_UDMA 1
111#endif
112
113void ata_dma_set_mode(unsigned char mode);
114bool ata_dma_setup(void *addr, unsigned long bytes, bool write);
115bool ata_dma_finish(void);
116
117#endif /* HAVE_ATA_DMA */