summaryrefslogtreecommitdiff
path: root/firmware/target/arm/ata-pp5020.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/ata-pp5020.c')
-rw-r--r--firmware/target/arm/ata-pp5020.c183
1 files changed, 183 insertions, 0 deletions
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 */