summaryrefslogtreecommitdiff
path: root/firmware/target/arm/pp/ata-pp5020.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/pp/ata-pp5020.c')
-rw-r--r--firmware/target/arm/pp/ata-pp5020.c248
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
28void ata_reset()
29{
30
31}
32
33void ata_enable(bool on)
34{
35 /* TODO: Implement ata_enable() */
36 (void)on;
37}
38
39bool ata_is_coldstart()
40{
41 return false;
42 /* TODO: Implement coldstart variable */
43}
44
45void 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.
76static 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 */
85static const unsigned long tm_mwdma[] = {
86 0xF9F92, 0x56562, 0x45451
87};
88
89static 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
97static bool dma_boosted = false;
98static 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 */
104void 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 */
136STATICIRAM 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 */
159bool 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 */
223bool 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 */