diff options
Diffstat (limited to 'firmware/target/arm/ata-pp5020.c')
-rw-r--r-- | firmware/target/arm/ata-pp5020.c | 183 |
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. | ||
77 | static 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 | */ | ||
86 | static const unsigned long tm_mwdma[] = { | ||
87 | 0xF9F92, 0x56562, 0x45451 | ||
88 | }; | ||
89 | |||
90 | static 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 | ||
98 | static bool dma_boosted = false; | ||
99 | static 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 | */ | ||
105 | void 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 | */ | ||
133 | STATICIRAM 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 | */ | ||
156 | bool 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 | */ | ||
220 | bool 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 */ | ||