diff options
Diffstat (limited to 'firmware/target/arm/pp/ata-pp5020.c')
-rw-r--r-- | firmware/target/arm/pp/ata-pp5020.c | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/firmware/target/arm/pp/ata-pp5020.c b/firmware/target/arm/pp/ata-pp5020.c new file mode 100644 index 0000000000..50a38cb23d --- /dev/null +++ b/firmware/target/arm/pp/ata-pp5020.c | |||
@@ -0,0 +1,248 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Barry Wardell | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | /* ATA stuff was taken from the iPod code */ | ||
23 | |||
24 | #include <stdbool.h> | ||
25 | #include "system.h" | ||
26 | #include "ata-driver.h" | ||
27 | |||
28 | void ata_reset() | ||
29 | { | ||
30 | |||
31 | } | ||
32 | |||
33 | void ata_enable(bool on) | ||
34 | { | ||
35 | /* TODO: Implement ata_enable() */ | ||
36 | (void)on; | ||
37 | } | ||
38 | |||
39 | bool ata_is_coldstart() | ||
40 | { | ||
41 | return false; | ||
42 | /* TODO: Implement coldstart variable */ | ||
43 | } | ||
44 | |||
45 | void ata_device_init() | ||
46 | { | ||
47 | #ifdef SAMSUNG_YH920 | ||
48 | CPU_INT_DIS = (1<<IDE_IRQ); | ||
49 | #endif | ||
50 | #ifdef HAVE_ATA_DMA | ||
51 | IDE_DMA_CONTROL |= 2; | ||
52 | IDE_DMA_CONTROL &= ~1; | ||
53 | IDE0_CFG &= ~0x8010; | ||
54 | IDE0_CFG |= 0x20; | ||
55 | #else | ||
56 | |||
57 | /* From ipod-ide.c:ipod_ide_register() */ | ||
58 | IDE0_CFG |= (1<<5); | ||
59 | #ifdef IPOD_NANO | ||
60 | IDE0_CFG |= (0x10000000); /* cpu > 65MHz */ | ||
61 | #else | ||
62 | IDE0_CFG &=~(0x10000000); /* cpu < 65MHz */ | ||
63 | #endif | ||
64 | #endif | ||
65 | |||
66 | IDE0_PRI_TIMING0 = 0x10; | ||
67 | IDE0_PRI_TIMING1 = 0x80002150; | ||
68 | } | ||
69 | |||
70 | /* These are PIO timings for 80 Mhz. At 24 Mhz, | ||
71 | the first value is 0 but the rest are the same. | ||
72 | They go in IDE0_PRI_TIMING0. | ||
73 | |||
74 | Rockbox used 0x10, and test_disk shows that leads to faster PIO. | ||
75 | If 0x10 is incorrect, these timings may be needed with some devices. | ||
76 | static const unsigned long pio80mhz[] = { | ||
77 | 0xC293, 0x43A2, 0x11A1, 0x7232, 0x3131 | ||
78 | }; | ||
79 | */ | ||
80 | |||
81 | #ifdef HAVE_ATA_DMA | ||
82 | /* Timings for multi-word and ultra DMA modes. | ||
83 | These go in IDE0_PRI_TIMING1 | ||
84 | */ | ||
85 | static const unsigned long tm_mwdma[] = { | ||
86 | 0xF9F92, 0x56562, 0x45451 | ||
87 | }; | ||
88 | |||
89 | static const unsigned long tm_udma[] = { | ||
90 | 0x800037C1, 0x80003491, 0x80003371, | ||
91 | #if ATA_MAX_UDMA > 2 | ||
92 | 0x80003271, 0x80003071 | ||
93 | #endif | ||
94 | }; | ||
95 | |||
96 | #if ATA_MAX_UDMA > 2 | ||
97 | static bool dma_boosted = false; | ||
98 | static bool dma_needs_boost; | ||
99 | #endif | ||
100 | |||
101 | /* This function sets up registers for 80 Mhz. | ||
102 | Ultra DMA mode 2 works at 30 Mhz. | ||
103 | */ | ||
104 | void ata_dma_set_mode(unsigned char mode) { | ||
105 | int modeidx; | ||
106 | |||
107 | (*(volatile unsigned long *)(0x600060C4)) = 0xC0000000; /* 80 Mhz */ | ||
108 | #if !defined(IPOD_NANO) | ||
109 | IDE0_CFG &= ~0x10000000; | ||
110 | #endif | ||
111 | |||
112 | modeidx = mode & 7; | ||
113 | mode &= 0xF8; | ||
114 | if (mode == 0x40 && modeidx <= ATA_MAX_UDMA) { | ||
115 | IDE0_PRI_TIMING1 = tm_udma[modeidx]; | ||
116 | #if ATA_MAX_UDMA > 2 | ||
117 | if (modeidx > 2) | ||
118 | dma_needs_boost = true; | ||
119 | else | ||
120 | dma_needs_boost = false; | ||
121 | #endif | ||
122 | } else if (mode == 0x20 && modeidx <= ATA_MAX_MWDMA) | ||
123 | IDE0_PRI_TIMING1 = tm_mwdma[modeidx]; | ||
124 | |||
125 | #if !defined(IPOD_NANO) | ||
126 | IDE0_CFG |= 0x20000000; /* >= 50 Mhz */ | ||
127 | #endif | ||
128 | } | ||
129 | |||
130 | #define IDE_CFG_INTRQ 8 | ||
131 | #define IDE_DMA_CONTROL_READ 8 | ||
132 | |||
133 | /* This waits for an ATA interrupt using polling. | ||
134 | In ATA_CONTROL, CONTROL_nIEN must be cleared. | ||
135 | */ | ||
136 | STATICIRAM ICODE_ATTR int ata_wait_intrq(void) | ||
137 | { | ||
138 | long timeout = current_tick + HZ*10; | ||
139 | |||
140 | do | ||
141 | { | ||
142 | if (IDE0_CFG & IDE_CFG_INTRQ) | ||
143 | return 1; | ||
144 | ata_keep_active(); | ||
145 | yield(); | ||
146 | } while (TIME_BEFORE(current_tick, timeout)); | ||
147 | |||
148 | return 0; /* timeout */ | ||
149 | } | ||
150 | |||
151 | /* This function checks if parameters are appropriate for DMA, | ||
152 | and if they are, it sets up for DMA. | ||
153 | |||
154 | If return value is false, caller may use PIO for this transfer. | ||
155 | |||
156 | If return value is true, caller must issue a DMA ATA command | ||
157 | and then call ata_dma_finish(). | ||
158 | */ | ||
159 | bool ata_dma_setup(void *addr, unsigned long bytes, bool write) { | ||
160 | /* Require cacheline alignment for reads to prevent interference. */ | ||
161 | if (!write && ((unsigned long)addr & 15)) | ||
162 | return false; | ||
163 | |||
164 | /* Writes only need to be word-aligned, but by default DMA | ||
165 | * is not used for writing as it appears to be slower. | ||
166 | */ | ||
167 | #ifdef ATA_DMA_WRITES | ||
168 | if (write && ((unsigned long)addr & 3)) | ||
169 | return false; | ||
170 | #else | ||
171 | if (write) | ||
172 | return false; | ||
173 | #endif | ||
174 | |||
175 | #if ATA_MAX_UDMA > 2 | ||
176 | if (dma_needs_boost && !dma_boosted) { | ||
177 | cpu_boost(true); | ||
178 | dma_boosted = true; | ||
179 | } | ||
180 | #endif | ||
181 | |||
182 | if (write) { | ||
183 | /* If unflushed, old data may be written to disk */ | ||
184 | commit_dcache(); | ||
185 | } | ||
186 | else { | ||
187 | /* Invalidate cache because new data may be present in RAM */ | ||
188 | commit_discard_dcache(); | ||
189 | } | ||
190 | |||
191 | /* Clear pending interrupts so ata_dma_finish() can wait for an | ||
192 | interrupt from this transfer | ||
193 | */ | ||
194 | IDE0_CFG |= IDE_CFG_INTRQ; | ||
195 | |||
196 | IDE_DMA_CONTROL |= 2; | ||
197 | IDE_DMA_LENGTH = bytes - 4; | ||
198 | |||
199 | #if !defined(BOOTLOADER) || defined (HAVE_BOOTLOADER_USB_MODE) | ||
200 | if ((unsigned long)addr < DRAM_START) | ||
201 | /* Rockbox remaps DRAM to start at 0 */ | ||
202 | IDE_DMA_ADDR = (unsigned long)addr + DRAM_START; | ||
203 | else | ||
204 | #endif | ||
205 | IDE_DMA_ADDR = (unsigned long)addr; | ||
206 | |||
207 | if (write) | ||
208 | IDE_DMA_CONTROL &= ~IDE_DMA_CONTROL_READ; | ||
209 | else | ||
210 | IDE_DMA_CONTROL |= IDE_DMA_CONTROL_READ; | ||
211 | |||
212 | IDE0_CFG |= 0x8000; | ||
213 | |||
214 | return true; | ||
215 | } | ||
216 | |||
217 | /* This function waits for a DMA transfer to end. | ||
218 | It must be called to finish what ata_dma_setup started. | ||
219 | |||
220 | Return value is true if DMA completed before the timeout, and false | ||
221 | if a timeout happened. | ||
222 | */ | ||
223 | bool ata_dma_finish(void) { | ||
224 | bool res; | ||
225 | |||
226 | /* It may be okay to put this at the end of setup */ | ||
227 | IDE_DMA_CONTROL |= 1; | ||
228 | |||
229 | /* Wait for end of transfer. | ||
230 | Reading standard ATA status while DMA is in progress causes | ||
231 | failures and hangs. Because of that, another wait is used. | ||
232 | */ | ||
233 | res = ata_wait_intrq(); | ||
234 | |||
235 | IDE0_CFG &= ~0x8000; | ||
236 | IDE_DMA_CONTROL &= ~0x80000001; | ||
237 | |||
238 | #if ATA_MAX_UDMA > 2 | ||
239 | if (dma_boosted) { | ||
240 | cpu_boost(false); | ||
241 | dma_boosted = false; | ||
242 | } | ||
243 | #endif | ||
244 | |||
245 | return res; | ||
246 | } | ||
247 | |||
248 | #endif /* HAVE_ATA_DMA */ | ||