diff options
Diffstat (limited to 'firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c')
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c | 1131 |
1 files changed, 1131 insertions, 0 deletions
diff --git a/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c b/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c new file mode 100644 index 0000000000..ef39a5cabb --- /dev/null +++ b/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c | |||
@@ -0,0 +1,1131 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 Dave Chapman | ||
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 | #include "config.h" | ||
22 | #include "thread.h" | ||
23 | #include "disk.h" | ||
24 | #include "storage.h" | ||
25 | #include "timer.h" | ||
26 | #include "kernel.h" | ||
27 | #include "string.h" | ||
28 | #include "power.h" | ||
29 | #include "panic.h" | ||
30 | #include "mmu-arm.h" | ||
31 | #include "mmcdefs-target.h" | ||
32 | #include "s5l8702.h" | ||
33 | #include "led.h" | ||
34 | #include "ata_idle_notify.h" | ||
35 | #include "disk_cache.h" | ||
36 | |||
37 | |||
38 | #ifndef ATA_RETRIES | ||
39 | #define ATA_RETRIES 3 | ||
40 | #endif | ||
41 | |||
42 | |||
43 | #define CEATA_POWERUP_TIMEOUT 20000000 | ||
44 | #define CEATA_COMMAND_TIMEOUT 1000000 | ||
45 | #define CEATA_DAT_NONBUSY_TIMEOUT 5000000 | ||
46 | #define CEATA_MMC_RCA 1 | ||
47 | |||
48 | |||
49 | /** static, private data **/ | ||
50 | static uint8_t ceata_taskfile[16] STORAGE_ALIGN_ATTR; | ||
51 | static uint16_t ata_identify_data[0x100] STORAGE_ALIGN_ATTR; | ||
52 | static bool ceata; | ||
53 | static bool ata_lba48; | ||
54 | static bool ata_dma; | ||
55 | static uint64_t ata_total_sectors; | ||
56 | static struct mutex ata_mutex; | ||
57 | static struct semaphore ata_wakeup; | ||
58 | static uint32_t ata_dma_flags; | ||
59 | static long ata_last_activity_value = -1; | ||
60 | static long ata_sleep_timeout = 20 * HZ; | ||
61 | static uint32_t ata_stack[(DEFAULT_STACK_SIZE + 0x400) / 4]; | ||
62 | static bool ata_powered; | ||
63 | static const int ata_retries = ATA_RETRIES; | ||
64 | static const bool ata_error_srst = true; | ||
65 | static struct semaphore mmc_wakeup; | ||
66 | static struct semaphore mmc_comp_wakeup; | ||
67 | static int spinup_time = 0; | ||
68 | static int dma_mode = 0; | ||
69 | static char aligned_buffer[SECTOR_SIZE] STORAGE_ALIGN_ATTR; | ||
70 | |||
71 | static int ata_reset(void); | ||
72 | |||
73 | |||
74 | static uint16_t ata_read_cbr(uint32_t volatile* reg) | ||
75 | { | ||
76 | while (!(ATA_PIO_READY & 2)); | ||
77 | volatile uint32_t dummy __attribute__((unused)) = *reg; | ||
78 | while (!(ATA_PIO_READY & 1)); | ||
79 | return ATA_PIO_RDATA; | ||
80 | } | ||
81 | |||
82 | static void ata_write_cbr(uint32_t volatile* reg, uint16_t data) | ||
83 | { | ||
84 | while (!(ATA_PIO_READY & 2)); | ||
85 | *reg = data; | ||
86 | } | ||
87 | |||
88 | static int ata_wait_for_not_bsy(long timeout) | ||
89 | { | ||
90 | long startusec = USEC_TIMER; | ||
91 | while (true) | ||
92 | { | ||
93 | uint8_t csd = ata_read_cbr(&ATA_PIO_CSD); | ||
94 | if (!(csd & BIT(7))) return 0; | ||
95 | if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(0); | ||
96 | yield(); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | static int ata_wait_for_rdy(long timeout) | ||
101 | { | ||
102 | long startusec = USEC_TIMER; | ||
103 | PASS_RC(ata_wait_for_not_bsy(timeout), 1, 0); | ||
104 | while (true) | ||
105 | { | ||
106 | uint8_t dad = ata_read_cbr(&ATA_PIO_DAD); | ||
107 | if (dad & BIT(6)) return 0; | ||
108 | if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(1); | ||
109 | yield(); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | static int ata_wait_for_start_of_transfer(long timeout) | ||
114 | { | ||
115 | long startusec = USEC_TIMER; | ||
116 | PASS_RC(ata_wait_for_not_bsy(timeout), 2, 0); | ||
117 | while (true) | ||
118 | { | ||
119 | uint8_t dad = ata_read_cbr(&ATA_PIO_DAD); | ||
120 | if (dad & BIT(0)) RET_ERR(1); | ||
121 | if ((dad & (BIT(7) | BIT(3))) == BIT(3)) return 0; | ||
122 | if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(2); | ||
123 | yield(); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static int ata_wait_for_end_of_transfer(long timeout) | ||
128 | { | ||
129 | PASS_RC(ata_wait_for_not_bsy(timeout), 2, 0); | ||
130 | uint8_t dad = ata_read_cbr(&ATA_PIO_DAD); | ||
131 | if (dad & BIT(0)) RET_ERR(1); | ||
132 | if ((dad & (BIT(3) | BITRANGE(5, 7))) == BIT(6)) return 0; | ||
133 | RET_ERR(2); | ||
134 | } | ||
135 | |||
136 | static int mmc_dsta_check_command_success(bool disable_crc) | ||
137 | { | ||
138 | int rc = 0; | ||
139 | uint32_t dsta = SDCI_DSTA; | ||
140 | if (dsta & SDCI_DSTA_RESTOUTE) rc |= 1; | ||
141 | if (dsta & SDCI_DSTA_RESENDE) rc |= 2; | ||
142 | if (dsta & SDCI_DSTA_RESINDE) rc |= 4; | ||
143 | if (!disable_crc) | ||
144 | if (dsta & SDCI_DSTA_RESCRCE) | ||
145 | rc |= 8; | ||
146 | if (rc) RET_ERR(rc); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static bool mmc_send_command(uint32_t cmd, uint32_t arg, uint32_t* result, int timeout) | ||
151 | { | ||
152 | long starttime = USEC_TIMER; | ||
153 | while ((SDCI_STATE & SDCI_STATE_CMD_STATE_MASK) != SDCI_STATE_CMD_STATE_CMD_IDLE) | ||
154 | { | ||
155 | if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(0); | ||
156 | yield(); | ||
157 | } | ||
158 | SDCI_STAC = SDCI_STAC_CLR_CMDEND | SDCI_STAC_CLR_BIT_3 | ||
159 | | SDCI_STAC_CLR_RESEND | SDCI_STAC_CLR_DATEND | ||
160 | | SDCI_STAC_CLR_DAT_CRCEND | SDCI_STAC_CLR_CRC_STAEND | ||
161 | | SDCI_STAC_CLR_RESTOUTE | SDCI_STAC_CLR_RESENDE | ||
162 | | SDCI_STAC_CLR_RESINDE | SDCI_STAC_CLR_RESCRCE | ||
163 | | SDCI_STAC_CLR_WR_DATCRCE | SDCI_STAC_CLR_RD_DATCRCE | ||
164 | | SDCI_STAC_CLR_RD_DATENDE0 | SDCI_STAC_CLR_RD_DATENDE1 | ||
165 | | SDCI_STAC_CLR_RD_DATENDE2 | SDCI_STAC_CLR_RD_DATENDE3 | ||
166 | | SDCI_STAC_CLR_RD_DATENDE4 | SDCI_STAC_CLR_RD_DATENDE5 | ||
167 | | SDCI_STAC_CLR_RD_DATENDE6 | SDCI_STAC_CLR_RD_DATENDE7; | ||
168 | SDCI_ARGU = arg; | ||
169 | SDCI_CMD = cmd; | ||
170 | if (!(SDCI_DSTA & SDCI_DSTA_CMDRDY)) RET_ERR(1); | ||
171 | SDCI_CMD = cmd | SDCI_CMD_CMDSTR; | ||
172 | long sleepbase = USEC_TIMER; | ||
173 | while (TIMEOUT_EXPIRED(sleepbase, 1000)) yield(); | ||
174 | while (!(SDCI_DSTA & SDCI_DSTA_CMDEND)) | ||
175 | { | ||
176 | if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(2); | ||
177 | yield(); | ||
178 | } | ||
179 | if ((cmd & SDCI_CMD_RES_TYPE_MASK) != SDCI_CMD_RES_TYPE_NONE) | ||
180 | { | ||
181 | while (!(SDCI_DSTA & SDCI_DSTA_RESEND)) | ||
182 | { | ||
183 | if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(3); | ||
184 | yield(); | ||
185 | } | ||
186 | if (cmd & SDCI_CMD_RES_BUSY) | ||
187 | while (SDCI_DSTA & SDCI_DSTA_DAT_BUSY) | ||
188 | { | ||
189 | if (TIMEOUT_EXPIRED(starttime, CEATA_DAT_NONBUSY_TIMEOUT)) RET_ERR(4); | ||
190 | yield(); | ||
191 | } | ||
192 | } | ||
193 | bool nocrc = (cmd & SDCI_CMD_RES_SIZE_MASK) == SDCI_CMD_RES_SIZE_136; | ||
194 | PASS_RC(mmc_dsta_check_command_success(nocrc), 3, 5); | ||
195 | if (result) *result = SDCI_RESP0; | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int mmc_get_card_status(uint32_t* result) | ||
200 | { | ||
201 | return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_STATUS) | ||
202 | | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | ||
203 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | ||
204 | MMC_CMD_SEND_STATUS_RCA(CEATA_MMC_RCA), result, CEATA_COMMAND_TIMEOUT); | ||
205 | } | ||
206 | |||
207 | static int mmc_init(void) | ||
208 | { | ||
209 | sleep(HZ / 10); | ||
210 | PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_GO_IDLE_STATE) | ||
211 | | SDCI_CMD_CMD_TYPE_BC | SDCI_CMD_RES_TYPE_NONE | ||
212 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID, | ||
213 | 0, NULL, CEATA_COMMAND_TIMEOUT), 3, 0); | ||
214 | long startusec = USEC_TIMER; | ||
215 | uint32_t result; | ||
216 | do | ||
217 | { | ||
218 | if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(1); | ||
219 | sleep(HZ / 100); | ||
220 | PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_OP_COND) | ||
221 | | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R3 | ||
222 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID, | ||
223 | MMC_CMD_SEND_OP_COND_OCR(MMC_OCR_270_360), | ||
224 | NULL, CEATA_COMMAND_TIMEOUT), 3, 2); | ||
225 | result = SDCI_RESP0; | ||
226 | } | ||
227 | while (!(result & MMC_OCR_POWER_UP_DONE)); | ||
228 | PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_ALL_SEND_CID) | ||
229 | | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R2 | ||
230 | | SDCI_CMD_RES_SIZE_136 | SDCI_CMD_NCR_NID_NID, | ||
231 | 0, NULL, CEATA_COMMAND_TIMEOUT), 3, 3); | ||
232 | PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SET_RELATIVE_ADDR) | ||
233 | | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R1 | ||
234 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | ||
235 | MMC_CMD_SET_RELATIVE_ADDR_RCA(CEATA_MMC_RCA), | ||
236 | NULL, CEATA_COMMAND_TIMEOUT), 3, 4); | ||
237 | PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SELECT_CARD) | ||
238 | | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | ||
239 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | ||
240 | MMC_CMD_SELECT_CARD_RCA(CEATA_MMC_RCA), | ||
241 | NULL, CEATA_COMMAND_TIMEOUT), 3, 5); | ||
242 | PASS_RC(mmc_get_card_status(&result), 3, 6); | ||
243 | if ((result & MMC_STATUS_CURRENT_STATE_MASK) != MMC_STATUS_CURRENT_STATE_TRAN) RET_ERR(7); | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int mmc_fastio_write(uint32_t addr, uint32_t data) | ||
248 | { | ||
249 | return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO) | ||
250 | | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4 | ||
251 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | ||
252 | MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_WRITE | ||
253 | | MMC_CMD_FAST_IO_ADDRESS(addr) | MMC_CMD_FAST_IO_DATA(data), | ||
254 | NULL, CEATA_COMMAND_TIMEOUT); | ||
255 | } | ||
256 | |||
257 | static int mmc_fastio_read(uint32_t addr, uint32_t* data) | ||
258 | { | ||
259 | return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO) | ||
260 | | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4 | ||
261 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | ||
262 | MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_READ | ||
263 | | MMC_CMD_FAST_IO_ADDRESS(addr), data, CEATA_COMMAND_TIMEOUT); | ||
264 | } | ||
265 | |||
266 | static int ceata_soft_reset(void) | ||
267 | { | ||
268 | PASS_RC(mmc_fastio_write(6, 4), 2, 0); | ||
269 | sleep(HZ / 100); | ||
270 | PASS_RC(mmc_fastio_write(6, 0), 2, 1); | ||
271 | sleep(HZ / 100); | ||
272 | long startusec = USEC_TIMER; | ||
273 | uint32_t status; | ||
274 | do | ||
275 | { | ||
276 | PASS_RC(mmc_fastio_read(0xf, &status), 2, 2); | ||
277 | if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(3); | ||
278 | sleep(HZ / 100); | ||
279 | } | ||
280 | while (status & 0x80); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int mmc_dsta_check_data_success(void) | ||
285 | { | ||
286 | int rc = 0; | ||
287 | uint32_t dsta = SDCI_DSTA; | ||
288 | if (dsta & (SDCI_DSTA_WR_DATCRCE | SDCI_DSTA_RD_DATCRCE)) | ||
289 | { | ||
290 | if (dsta & SDCI_DSTA_WR_DATCRCE) rc |= 1; | ||
291 | if (dsta & SDCI_DSTA_RD_DATCRCE) rc |= 2; | ||
292 | if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_TXERR) rc |= 4; | ||
293 | else if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_CARDERR) rc |= 8; | ||
294 | } | ||
295 | if (dsta & (SDCI_DSTA_RD_DATENDE0 | SDCI_DSTA_RD_DATENDE1 | SDCI_DSTA_RD_DATENDE2 | ||
296 | | SDCI_DSTA_RD_DATENDE3 | SDCI_DSTA_RD_DATENDE4 | SDCI_DSTA_RD_DATENDE5 | ||
297 | | SDCI_DSTA_RD_DATENDE6 | SDCI_DSTA_RD_DATENDE7)) | ||
298 | rc |= 16; | ||
299 | if (rc) RET_ERR(rc); | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static void mmc_discard_irq(void) | ||
304 | { | ||
305 | SDCI_IRQ = SDCI_IRQ_DAT_DONE_INT | SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT | ||
306 | | SDCI_IRQ_MASK_MASK_READ_WAIT_INT; | ||
307 | semaphore_wait(&mmc_wakeup, 0); | ||
308 | } | ||
309 | |||
310 | static int ceata_read_multiple_register(uint32_t addr, void* dest, uint32_t size) | ||
311 | { | ||
312 | if (size > 0x10) RET_ERR(0); | ||
313 | mmc_discard_irq(); | ||
314 | SDCI_DMASIZE = size; | ||
315 | SDCI_DMACOUNT = 1; | ||
316 | SDCI_DMAADDR = dest; | ||
317 | SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST; | ||
318 | commit_discard_dcache(); | ||
319 | PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG) | ||
320 | | SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_RES_TYPE_R1 | ||
321 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | ||
322 | MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_READ | ||
323 | | MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc) | ||
324 | | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc), | ||
325 | NULL, CEATA_COMMAND_TIMEOUT), 2, 1); | ||
326 | if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) | ||
327 | == OBJ_WAIT_TIMEDOUT) RET_ERR(2); | ||
328 | PASS_RC(mmc_dsta_check_data_success(), 2, 3); | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int ceata_write_multiple_register(uint32_t addr, void* dest, uint32_t size) | ||
333 | { | ||
334 | uint32_t i; | ||
335 | if (size > 0x10) RET_ERR(0); | ||
336 | mmc_discard_irq(); | ||
337 | SDCI_DMASIZE = size; | ||
338 | SDCI_DMACOUNT = 0; | ||
339 | SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST; | ||
340 | PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG) | ||
341 | | SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR | ||
342 | | SDCI_CMD_RES_BUSY | SDCI_CMD_RES_TYPE_R1 | ||
343 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | ||
344 | MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_WRITE | ||
345 | | MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc) | ||
346 | | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc), | ||
347 | NULL, CEATA_COMMAND_TIMEOUT), 3, 1); | ||
348 | SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX; | ||
349 | for (i = 0; i < size / 4; i++) SDCI_DATA = ((uint32_t*)dest)[i]; | ||
350 | long startusec = USEC_TIMER; | ||
351 | if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) | ||
352 | == OBJ_WAIT_TIMEDOUT) RET_ERR(2); | ||
353 | while ((SDCI_STATE & SDCI_STATE_DAT_STATE_MASK) != SDCI_STATE_DAT_STATE_IDLE) | ||
354 | { | ||
355 | if (TIMEOUT_EXPIRED(startusec, CEATA_COMMAND_TIMEOUT)) RET_ERR(3); | ||
356 | yield(); | ||
357 | } | ||
358 | PASS_RC(mmc_dsta_check_data_success(), 3, 4); | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static int ceata_init(int buswidth) | ||
363 | { | ||
364 | uint32_t result; | ||
365 | PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SWITCH) | SDCI_CMD_RES_BUSY | ||
366 | | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | ||
367 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | ||
368 | MMC_CMD_SWITCH_ACCESS_WRITE_BYTE | ||
369 | | MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_HS_TIMING) | ||
370 | | MMC_CMD_SWITCH_VALUE(MMC_CMD_SWITCH_FIELD_HS_TIMING_HIGH_SPEED), | ||
371 | &result, CEATA_COMMAND_TIMEOUT), 3, 0); | ||
372 | if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(1); | ||
373 | if (buswidth > 1) | ||
374 | { | ||
375 | int setting; | ||
376 | if (buswidth == 4) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_4BIT; | ||
377 | else if (buswidth == 8) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_8BIT; | ||
378 | else setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_1BIT; | ||
379 | PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SWITCH) | SDCI_CMD_RES_BUSY | ||
380 | | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | ||
381 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | ||
382 | MMC_CMD_SWITCH_ACCESS_WRITE_BYTE | ||
383 | | MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_BUS_WIDTH) | ||
384 | | MMC_CMD_SWITCH_VALUE(setting), | ||
385 | &result, CEATA_COMMAND_TIMEOUT), 3, 2); | ||
386 | if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(3); | ||
387 | if (buswidth == 4) | ||
388 | SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_4BIT; | ||
389 | else if (buswidth == 8) | ||
390 | SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_8BIT; | ||
391 | } | ||
392 | PASS_RC(ceata_soft_reset(), 3, 4); | ||
393 | PASS_RC(ceata_read_multiple_register(0, ceata_taskfile, 0x10), 3, 5); | ||
394 | if (ceata_taskfile[0xc] != 0xce || ceata_taskfile[0xd] != 0xaa) RET_ERR(6); | ||
395 | PASS_RC(mmc_fastio_write(6, 0), 3, 7); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static int ceata_check_error(void) | ||
400 | { | ||
401 | uint32_t status, error; | ||
402 | PASS_RC(mmc_fastio_read(0xf, &status), 2, 0); | ||
403 | if (status & 1) | ||
404 | { | ||
405 | PASS_RC(mmc_fastio_read(0x9, &error), 2, 1); | ||
406 | RET_ERR((error << 2) | 2); | ||
407 | } | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static int ceata_wait_idle(void) | ||
412 | { | ||
413 | long startusec = USEC_TIMER; | ||
414 | while (true) | ||
415 | { | ||
416 | uint32_t status; | ||
417 | PASS_RC(mmc_fastio_read(0xf, &status), 1, 0); | ||
418 | if (!(status & 0x88)) return 0; | ||
419 | if (TIMEOUT_EXPIRED(startusec, CEATA_DAT_NONBUSY_TIMEOUT)) RET_ERR(1); | ||
420 | sleep(HZ / 20); | ||
421 | } | ||
422 | } | ||
423 | |||
424 | static int ceata_cancel_command(void) | ||
425 | { | ||
426 | *((uint32_t volatile*)0x3cf00200) = 0x9000e; | ||
427 | udelay(1); | ||
428 | *((uint32_t volatile*)0x3cf00200) = 0x9000f; | ||
429 | udelay(1); | ||
430 | *((uint32_t volatile*)0x3cf00200) = 0x90003; | ||
431 | udelay(1); | ||
432 | PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_STOP_TRANSMISSION) | ||
433 | | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY | ||
434 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | ||
435 | 0, NULL, CEATA_COMMAND_TIMEOUT), 1, 0); | ||
436 | PASS_RC(ceata_wait_idle(), 1, 1); | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static int ceata_rw_multiple_block(bool write, void* buf, uint32_t count, long timeout) | ||
441 | { | ||
442 | mmc_discard_irq(); | ||
443 | uint32_t responsetype; | ||
444 | uint32_t cmdtype; | ||
445 | uint32_t direction; | ||
446 | if (write) | ||
447 | { | ||
448 | cmdtype = SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR; | ||
449 | responsetype = SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY; | ||
450 | direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_WRITE; | ||
451 | } | ||
452 | else | ||
453 | { | ||
454 | cmdtype = SDCI_CMD_CMD_TYPE_ADTC; | ||
455 | responsetype = SDCI_CMD_RES_TYPE_R1; | ||
456 | direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_READ; | ||
457 | } | ||
458 | SDCI_DMASIZE = 0x200; | ||
459 | SDCI_DMAADDR = buf; | ||
460 | SDCI_DMACOUNT = count; | ||
461 | SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST; | ||
462 | commit_discard_dcache(); | ||
463 | PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_BLOCK) | ||
464 | | SDCI_CMD_CMD_TYPE_ADTC | cmdtype | responsetype | ||
465 | | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, | ||
466 | direction | MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT(count), | ||
467 | NULL, CEATA_COMMAND_TIMEOUT), 3, 0); | ||
468 | if (write) SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX; | ||
469 | if (semaphore_wait(&mmc_wakeup, timeout) == OBJ_WAIT_TIMEDOUT) | ||
470 | { | ||
471 | PASS_RC(ceata_cancel_command(), 3, 1); | ||
472 | RET_ERR(2); | ||
473 | } | ||
474 | PASS_RC(mmc_dsta_check_data_success(), 3, 3); | ||
475 | if (semaphore_wait(&mmc_comp_wakeup, timeout) == OBJ_WAIT_TIMEDOUT) | ||
476 | { | ||
477 | PASS_RC(ceata_cancel_command(), 3, 4); | ||
478 | RET_ERR(5); | ||
479 | } | ||
480 | PASS_RC(ceata_check_error(), 3, 6); | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int ata_identify(uint16_t* buf) | ||
485 | { | ||
486 | int i; | ||
487 | if (ceata) | ||
488 | { | ||
489 | memset(ceata_taskfile, 0, 16); | ||
490 | ceata_taskfile[0xf] = 0xec; | ||
491 | PASS_RC(ceata_wait_idle(), 2, 0); | ||
492 | PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1); | ||
493 | PASS_RC(ceata_rw_multiple_block(false, buf, 1, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 2, 2); | ||
494 | } | ||
495 | else | ||
496 | { | ||
497 | PASS_RC(ata_wait_for_not_bsy(10000000), 1, 0); | ||
498 | ata_write_cbr(&ATA_PIO_DVR, 0); | ||
499 | ata_write_cbr(&ATA_PIO_CSD, 0xec); | ||
500 | PASS_RC(ata_wait_for_start_of_transfer(10000000), 1, 1); | ||
501 | for (i = 0; i < 0x100; i++) buf[i] = ata_read_cbr(&ATA_PIO_DTR); | ||
502 | } | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static void ata_set_active(void) | ||
507 | { | ||
508 | ata_last_activity_value = current_tick; | ||
509 | } | ||
510 | |||
511 | bool ata_disk_is_active(void) | ||
512 | { | ||
513 | return ata_powered; | ||
514 | } | ||
515 | |||
516 | static int ata_set_feature(uint32_t feature, uint32_t param) | ||
517 | { | ||
518 | if (ceata) | ||
519 | { | ||
520 | memset(ceata_taskfile, 0, 16); | ||
521 | ceata_taskfile[0x1] = feature; | ||
522 | ceata_taskfile[0x2] = param; | ||
523 | ceata_taskfile[0xf] = 0xef; | ||
524 | PASS_RC(ceata_wait_idle(), 2, 0); | ||
525 | PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1); | ||
526 | PASS_RC(ceata_wait_idle(), 2, 2); | ||
527 | } | ||
528 | else | ||
529 | { | ||
530 | PASS_RC(ata_wait_for_rdy(2000000), 2, 0); | ||
531 | ata_write_cbr(&ATA_PIO_DVR, 0); | ||
532 | ata_write_cbr(&ATA_PIO_FED, feature); | ||
533 | ata_write_cbr(&ATA_PIO_SCR, param); | ||
534 | ata_write_cbr(&ATA_PIO_CSD, 0xef); | ||
535 | PASS_RC(ata_wait_for_rdy(2000000), 2, 1); | ||
536 | } | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | /* | ||
541 | * ATA_UDMA_TIME register is documented on s3c6400 datasheet, information | ||
542 | * included in s5l8700 datasheet is wrong or not valid for s5l8702. | ||
543 | * | ||
544 | * On Classic (boosted): | ||
545 | * HClk = 108 MHz. -> T = ~9.26 ns. | ||
546 | * | ||
547 | * Configured values (in nanoseconds): | ||
548 | * | ||
549 | * UDMA ATA_UDMA_TIME tACK tRP tSS tDVS tDVH Tcyc WR(MB/s) | ||
550 | * 0 0x4071152 27.8 166.7 55.6 74.1 46.3 120.4 16.6 | ||
551 | * 1 0x2050d52 27.8 129.6 55.6 55.6 27.8 83.4 24 | ||
552 | * 2 0x2030a52 27.8 101.8 55.6 37 27.8 64.8 30.9 | ||
553 | * 3 0x1020a52 27.8 101.8 55.6 27.8 18.5 46.3 43.2 | ||
554 | * 4 0x1010a52 27.8 101.8 55.6 18.5 18.5 37 54 | ||
555 | * | ||
556 | * Tcyc = tDVS+tDVH | ||
557 | * WR[bytes/s] = 1/Tcyc[s] * 2[bytes] | ||
558 | */ | ||
559 | static int ata_power_up(void) | ||
560 | { | ||
561 | ata_set_active(); | ||
562 | ide_power_enable(true); | ||
563 | long spinup_start = current_tick; | ||
564 | if (ceata) | ||
565 | { | ||
566 | ata_lba48 = true; | ||
567 | ata_dma = true; | ||
568 | PCON(8) = 0x33333333; | ||
569 | PCON(9) = 0x00000033; | ||
570 | PCON(11) |= 0xf; | ||
571 | *((uint32_t volatile*)0x38a00000) = 0; | ||
572 | *((uint32_t volatile*)0x38700000) = 0; | ||
573 | PWRCON(0) &= ~(1 << 9); | ||
574 | SDCI_RESET = 0xa5; | ||
575 | sleep(HZ / 100); | ||
576 | *((uint32_t volatile*)0x3cf00380) = 0; | ||
577 | *((uint32_t volatile*)0x3cf0010c) = 0xff; | ||
578 | SDCI_CTRL = SDCI_CTRL_SDCIEN | SDCI_CTRL_CLK_SEL_SDCLK | ||
579 | | SDCI_CTRL_BIT_8 | SDCI_CTRL_BIT_14; | ||
580 | SDCI_CDIV = SDCI_CDIV_CLKDIV(260); | ||
581 | *((uint32_t volatile*)0x3cf00200) = 0xb000f; | ||
582 | SDCI_IRQ_MASK = SDCI_IRQ_MASK_MASK_DAT_DONE_INT | SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT; | ||
583 | PASS_RC(mmc_init(), 3, 0); | ||
584 | SDCI_CDIV = SDCI_CDIV_CLKDIV(4); | ||
585 | sleep(HZ / 100); | ||
586 | PASS_RC(ceata_init(8), 3, 1); | ||
587 | PASS_RC(ata_identify(ata_identify_data), 3, 2); | ||
588 | dma_mode = 0x44; | ||
589 | } | ||
590 | else | ||
591 | { | ||
592 | PCON(7) = 0x44444444; | ||
593 | PCON(8) = 0x44444444; | ||
594 | PCON(9) = 0x44444444; | ||
595 | PCON(10) = (PCON(10) & ~0xffff) | 0x4444; | ||
596 | PWRCON(0) &= ~(1 << 5); | ||
597 | ATA_CFG = BIT(0); | ||
598 | sleep(HZ / 100); | ||
599 | ATA_CFG = 0; | ||
600 | sleep(HZ / 100); | ||
601 | ATA_SWRST = BIT(0); | ||
602 | sleep(HZ / 100); | ||
603 | ATA_SWRST = 0; | ||
604 | sleep(HZ / 10); | ||
605 | ATA_CONTROL = BIT(0); | ||
606 | sleep(HZ / 5); | ||
607 | ATA_PIO_TIME = 0x191f7; | ||
608 | ATA_PIO_LHR = 0; | ||
609 | ATA_CFG = BIT(6); | ||
610 | while (!(ATA_PIO_READY & BIT(1))) yield(); | ||
611 | PASS_RC(ata_identify(ata_identify_data), 3, 3); | ||
612 | uint32_t piotime = 0x11f3; | ||
613 | uint32_t mdmatime = 0x1c175; | ||
614 | uint32_t udmatime = 0x4071152; | ||
615 | uint32_t param = 0; | ||
616 | ata_dma_flags = 0; | ||
617 | ata_lba48 = ata_identify_data[83] & BIT(10) ? true : false; | ||
618 | if (ata_identify_data[53] & BIT(1)) | ||
619 | { | ||
620 | if (ata_identify_data[64] & BIT(1)) piotime = 0x2072; | ||
621 | else if (ata_identify_data[64] & BIT(0)) piotime = 0x7083; | ||
622 | } | ||
623 | if (ata_identify_data[63] & BIT(2)) | ||
624 | { | ||
625 | mdmatime = 0x5072; | ||
626 | param = 0x22; | ||
627 | } | ||
628 | else if (ata_identify_data[63] & BIT(1)) | ||
629 | { | ||
630 | mdmatime = 0x7083; | ||
631 | param = 0x21; | ||
632 | } | ||
633 | if (ata_identify_data[63] & BITRANGE(0, 2)) | ||
634 | { | ||
635 | ata_dma_flags = BIT(3) | BIT(10); | ||
636 | param |= 0x20; | ||
637 | } | ||
638 | if (ata_identify_data[53] & BIT(2)) | ||
639 | { | ||
640 | if (ata_identify_data[88] & BIT(4)) | ||
641 | { | ||
642 | udmatime = 0x1010a52; | ||
643 | param = 0x44; | ||
644 | } | ||
645 | else if (ata_identify_data[88] & BIT(3)) | ||
646 | { | ||
647 | udmatime = 0x1020a52; | ||
648 | param = 0x43; | ||
649 | } | ||
650 | else if (ata_identify_data[88] & BIT(2)) | ||
651 | { | ||
652 | udmatime = 0x2030a52; | ||
653 | param = 0x42; | ||
654 | } | ||
655 | else if (ata_identify_data[88] & BIT(1)) | ||
656 | { | ||
657 | udmatime = 0x2050d52; | ||
658 | param = 0x41; | ||
659 | } | ||
660 | else if (ata_identify_data[88] & BIT(0)) | ||
661 | { | ||
662 | param = 0x40; | ||
663 | } | ||
664 | if (ata_identify_data[88] & BITRANGE(0, 4)) | ||
665 | { | ||
666 | ata_dma_flags = BIT(2) | BIT(3) | BIT(9) | BIT(10); | ||
667 | } | ||
668 | } | ||
669 | ata_dma = param ? true : false; | ||
670 | dma_mode = param; | ||
671 | PASS_RC(ata_set_feature(0x03, param), 3, 4); | ||
672 | if (ata_identify_data[82] & BIT(5)) | ||
673 | PASS_RC(ata_set_feature(0x02, 0), 3, 5); | ||
674 | if (ata_identify_data[82] & BIT(6)) PASS_RC(ata_set_feature(0xaa, 0), 3, 6); | ||
675 | ATA_PIO_TIME = piotime; | ||
676 | ATA_MDMA_TIME = mdmatime; | ||
677 | ATA_UDMA_TIME = udmatime; | ||
678 | } | ||
679 | spinup_time = current_tick - spinup_start; | ||
680 | if (ata_lba48) | ||
681 | ata_total_sectors = ata_identify_data[100] | ||
682 | | (((uint64_t)ata_identify_data[101]) << 16) | ||
683 | | (((uint64_t)ata_identify_data[102]) << 32) | ||
684 | | (((uint64_t)ata_identify_data[103]) << 48); | ||
685 | else ata_total_sectors = ata_identify_data[60] | (((uint32_t)ata_identify_data[61]) << 16); | ||
686 | ata_total_sectors >>= 3; | ||
687 | ata_powered = true; | ||
688 | ata_set_active(); | ||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | static void ata_power_down(void) | ||
693 | { | ||
694 | if (!ata_powered) return; | ||
695 | if (ceata) | ||
696 | { | ||
697 | memset(ceata_taskfile, 0, 16); | ||
698 | ceata_taskfile[0xf] = 0xe0; | ||
699 | ceata_wait_idle(); | ||
700 | ceata_write_multiple_register(0, ceata_taskfile, 16); | ||
701 | ceata_wait_idle(); | ||
702 | sleep(HZ); | ||
703 | PWRCON(0) |= (1 << 9); | ||
704 | } | ||
705 | else | ||
706 | { | ||
707 | ata_wait_for_rdy(1000000); | ||
708 | ata_write_cbr(&ATA_PIO_DVR, 0); | ||
709 | ata_write_cbr(&ATA_PIO_CSD, 0xe0); | ||
710 | ata_wait_for_rdy(1000000); | ||
711 | sleep(HZ / 30); | ||
712 | ATA_CONTROL = 0; | ||
713 | while (!(ATA_CONTROL & BIT(1))) yield(); | ||
714 | PWRCON(0) |= (1 << 5); | ||
715 | } | ||
716 | PCON(7) = 0; | ||
717 | PCON(8) = 0; | ||
718 | PCON(9) = 0; | ||
719 | PCON(10) &= ~0xffff; | ||
720 | PCON(11) &= ~0xf; | ||
721 | ide_power_enable(false); | ||
722 | ata_powered = false; | ||
723 | } | ||
724 | |||
725 | static int ata_rw_chunk_internal(uint64_t sector, uint32_t cnt, void* buffer, bool write) | ||
726 | { | ||
727 | if (ceata) | ||
728 | { | ||
729 | memset(ceata_taskfile, 0, 16); | ||
730 | ceata_taskfile[0x2] = cnt >> 5; | ||
731 | ceata_taskfile[0x3] = sector >> 21; | ||
732 | ceata_taskfile[0x4] = sector >> 29; | ||
733 | ceata_taskfile[0x5] = sector >> 37; | ||
734 | ceata_taskfile[0xa] = cnt << 3; | ||
735 | ceata_taskfile[0xb] = sector << 3; | ||
736 | ceata_taskfile[0xc] = sector >> 5; | ||
737 | ceata_taskfile[0xd] = sector >> 13; | ||
738 | ceata_taskfile[0xf] = write ? 0x35 : 0x25; | ||
739 | PASS_RC(ceata_wait_idle(), 2, 0); | ||
740 | PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1); | ||
741 | PASS_RC(ceata_rw_multiple_block(write, buffer, cnt << 3, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 2, 2); | ||
742 | } | ||
743 | else | ||
744 | { | ||
745 | PASS_RC(ata_wait_for_rdy(100000), 2, 0); | ||
746 | ata_write_cbr(&ATA_PIO_DVR, 0); | ||
747 | if (ata_lba48) | ||
748 | { | ||
749 | ata_write_cbr(&ATA_PIO_SCR, cnt >> 5); | ||
750 | ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff); | ||
751 | ata_write_cbr(&ATA_PIO_LHR, (sector >> 37) & 0xff); | ||
752 | ata_write_cbr(&ATA_PIO_LMR, (sector >> 29) & 0xff); | ||
753 | ata_write_cbr(&ATA_PIO_LLR, (sector >> 21) & 0xff); | ||
754 | ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff); | ||
755 | ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff); | ||
756 | ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff); | ||
757 | ata_write_cbr(&ATA_PIO_DVR, BIT(6)); | ||
758 | if (write) ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0x35 : 0x39); | ||
759 | else ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0x25 : 0x29); | ||
760 | } | ||
761 | else | ||
762 | { | ||
763 | ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff); | ||
764 | ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff); | ||
765 | ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff); | ||
766 | ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff); | ||
767 | ata_write_cbr(&ATA_PIO_DVR, BIT(6) | ((sector >> 21) & 0xf)); | ||
768 | if (write) ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0xca : 0x30); | ||
769 | else ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0xc8 : 0xc4); | ||
770 | } | ||
771 | if (ata_dma) | ||
772 | { | ||
773 | PASS_RC(ata_wait_for_start_of_transfer(500000), 2, 1); | ||
774 | if (write) | ||
775 | { | ||
776 | ATA_SBUF_START = buffer; | ||
777 | ATA_SBUF_SIZE = SECTOR_SIZE * cnt; | ||
778 | ATA_CFG |= BIT(4); | ||
779 | } | ||
780 | else | ||
781 | { | ||
782 | ATA_TBUF_START = buffer; | ||
783 | ATA_TBUF_SIZE = SECTOR_SIZE * cnt; | ||
784 | ATA_CFG &= ~BIT(4); | ||
785 | } | ||
786 | ATA_XFR_NUM = SECTOR_SIZE * cnt - 1; | ||
787 | ATA_CFG |= ata_dma_flags; | ||
788 | ATA_CFG &= ~(BIT(7) | BIT(8)); | ||
789 | semaphore_wait(&ata_wakeup, 0); | ||
790 | ATA_IRQ = BITRANGE(0, 4); | ||
791 | ATA_IRQ_MASK = BIT(0); | ||
792 | ATA_COMMAND = BIT(0); | ||
793 | if (semaphore_wait(&ata_wakeup, 500000 * HZ / 1000000) | ||
794 | == OBJ_WAIT_TIMEDOUT) | ||
795 | { | ||
796 | ATA_COMMAND = BIT(1); | ||
797 | ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12)); | ||
798 | RET_ERR(2); | ||
799 | } | ||
800 | ATA_COMMAND = BIT(1); | ||
801 | ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12)); | ||
802 | } | ||
803 | else | ||
804 | { | ||
805 | cnt *= SECTOR_SIZE / 512; | ||
806 | while (cnt--) | ||
807 | { | ||
808 | int i; | ||
809 | PASS_RC(ata_wait_for_start_of_transfer(500000), 2, 1); | ||
810 | if (write) | ||
811 | for (i = 0; i < 256; i++) | ||
812 | ata_write_cbr(&ATA_PIO_DTR, ((uint16_t*)buffer)[i]); | ||
813 | else | ||
814 | for (i = 0; i < 256; i++) | ||
815 | ((uint16_t*)buffer)[i] = ata_read_cbr(&ATA_PIO_DTR); | ||
816 | buffer += 512; | ||
817 | } | ||
818 | } | ||
819 | PASS_RC(ata_wait_for_end_of_transfer(100000), 2, 3); | ||
820 | } | ||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | static int ata_rw_chunk(uint64_t sector, uint32_t cnt, void* buffer, bool write) | ||
825 | { | ||
826 | led(true); | ||
827 | int rc = ata_rw_chunk_internal(sector, cnt, buffer, write); | ||
828 | led(false); | ||
829 | return rc; | ||
830 | } | ||
831 | |||
832 | static int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool write) | ||
833 | { | ||
834 | if (STORAGE_OVERLAP((uint32_t)buffer)) | ||
835 | { | ||
836 | while (count) | ||
837 | { | ||
838 | if (write) | ||
839 | memcpy(aligned_buffer, buffer, SECTOR_SIZE); | ||
840 | |||
841 | PASS_RC(ata_rw_sectors(sector, 1, aligned_buffer, write), 0, 0); | ||
842 | |||
843 | if (!write) | ||
844 | memcpy(buffer, aligned_buffer, SECTOR_SIZE); | ||
845 | |||
846 | buffer += SECTOR_SIZE; | ||
847 | sector++; | ||
848 | count--; | ||
849 | } | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | if (!ata_powered) ata_power_up(); | ||
855 | if (sector + count > ata_total_sectors) RET_ERR(0); | ||
856 | ata_set_active(); | ||
857 | if (ata_dma && write) commit_dcache(); | ||
858 | else if (ata_dma) commit_discard_dcache(); | ||
859 | if (!ceata) ATA_COMMAND = BIT(1); | ||
860 | while (count) | ||
861 | { | ||
862 | uint32_t cnt = MIN(ata_lba48 ? 8192 : 32, count); | ||
863 | int rc = -1; | ||
864 | rc = ata_rw_chunk(sector, cnt, buffer, write); | ||
865 | if (rc && ata_error_srst) ata_reset(); | ||
866 | if (rc && ata_retries) | ||
867 | { | ||
868 | void* buf = buffer; | ||
869 | uint64_t sect; | ||
870 | for (sect = sector; sect < sector + cnt; sect++) | ||
871 | { | ||
872 | rc = -1; | ||
873 | int tries = ata_retries; | ||
874 | while (tries-- && rc) | ||
875 | { | ||
876 | rc = ata_rw_chunk(sect, 1, buf, write); | ||
877 | if (rc && ata_error_srst) ata_reset(); | ||
878 | } | ||
879 | if (rc) break; | ||
880 | buf += SECTOR_SIZE; | ||
881 | } | ||
882 | } | ||
883 | PASS_RC(rc, 1, 1); | ||
884 | buffer += SECTOR_SIZE * cnt; | ||
885 | sector += cnt; | ||
886 | count -= cnt; | ||
887 | } | ||
888 | ata_set_active(); | ||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | static void ata_thread(void) | ||
893 | { | ||
894 | while (true) | ||
895 | { | ||
896 | mutex_lock(&ata_mutex); | ||
897 | if (TIME_AFTER(current_tick, ata_last_activity_value + ata_sleep_timeout) && ata_powered) | ||
898 | { | ||
899 | call_storage_idle_notifys(false); | ||
900 | ata_power_down(); | ||
901 | } | ||
902 | mutex_unlock(&ata_mutex); | ||
903 | sleep(HZ / 2); | ||
904 | } | ||
905 | } | ||
906 | |||
907 | /* API Functions */ | ||
908 | int ata_soft_reset(void) | ||
909 | { | ||
910 | int rc; | ||
911 | mutex_lock(&ata_mutex); | ||
912 | if (!ata_powered) PASS_RC(ata_power_up(), 1, 0); | ||
913 | ata_set_active(); | ||
914 | if (ceata) rc = ceata_soft_reset(); | ||
915 | else | ||
916 | { | ||
917 | ata_write_cbr(&ATA_PIO_DAD, BIT(1) | BIT(2)); | ||
918 | udelay(10); | ||
919 | ata_write_cbr(&ATA_PIO_DAD, 0); | ||
920 | rc = ata_wait_for_rdy(3000000); | ||
921 | } | ||
922 | ata_set_active(); | ||
923 | mutex_unlock(&ata_mutex); | ||
924 | PASS_RC(rc, 1, 1); | ||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | int ata_hard_reset(void) | ||
929 | { | ||
930 | mutex_lock(&ata_mutex); | ||
931 | PASS_RC(ata_power_up(), 0, 0); | ||
932 | ata_set_active(); | ||
933 | mutex_unlock(&ata_mutex); | ||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | static int ata_reset(void) | ||
938 | { | ||
939 | int rc; | ||
940 | mutex_lock(&ata_mutex); | ||
941 | if (!ata_powered) PASS_RC(ata_power_up(), 2, 0); | ||
942 | ata_set_active(); | ||
943 | rc = ata_soft_reset(); | ||
944 | if (IS_ERR(rc)) | ||
945 | { | ||
946 | rc = ata_hard_reset(); | ||
947 | if (IS_ERR(rc)) | ||
948 | { | ||
949 | rc = ERR_RC((rc << 2) | 1); | ||
950 | ata_power_down(); | ||
951 | sleep(HZ * 3); | ||
952 | int rc2 = ata_power_up(); | ||
953 | if (IS_ERR(rc2)) rc = ERR_RC((rc << 2) | 2); | ||
954 | } | ||
955 | else rc = 1; | ||
956 | } | ||
957 | ata_set_active(); | ||
958 | mutex_unlock(&ata_mutex); | ||
959 | return rc; | ||
960 | } | ||
961 | |||
962 | int ata_read_sectors(IF_MD(int drive,) unsigned long start, int incount, | ||
963 | void* inbuf) | ||
964 | { | ||
965 | mutex_lock(&ata_mutex); | ||
966 | int rc = ata_rw_sectors(start, incount, inbuf, false); | ||
967 | mutex_unlock(&ata_mutex); | ||
968 | return rc; | ||
969 | } | ||
970 | |||
971 | int ata_write_sectors(IF_MD(int drive,) unsigned long start, int count, | ||
972 | const void* outbuf) | ||
973 | { | ||
974 | mutex_lock(&ata_mutex); | ||
975 | int rc = ata_rw_sectors(start, count, (void*)((uint32_t)outbuf), true); | ||
976 | mutex_unlock(&ata_mutex); | ||
977 | return rc; | ||
978 | } | ||
979 | |||
980 | void ata_spindown(int seconds) | ||
981 | { | ||
982 | ata_sleep_timeout = seconds * HZ; | ||
983 | } | ||
984 | |||
985 | void ata_sleep(void) | ||
986 | { | ||
987 | ata_last_activity_value = current_tick - ata_sleep_timeout + HZ / 5; | ||
988 | } | ||
989 | |||
990 | void ata_sleepnow(void) | ||
991 | { | ||
992 | mutex_lock(&ata_mutex); | ||
993 | ata_power_down(); | ||
994 | mutex_unlock(&ata_mutex); | ||
995 | } | ||
996 | |||
997 | void ata_close(void) | ||
998 | { | ||
999 | ata_sleepnow(); | ||
1000 | } | ||
1001 | |||
1002 | void ata_spin(void) | ||
1003 | { | ||
1004 | ata_set_active(); | ||
1005 | } | ||
1006 | |||
1007 | void ata_get_info(IF_MD(int drive,) struct storage_info *info) | ||
1008 | { | ||
1009 | (*info).sector_size = SECTOR_SIZE; | ||
1010 | (*info).num_sectors = ata_total_sectors; | ||
1011 | (*info).vendor = "Apple"; | ||
1012 | (*info).product = "iPod Classic"; | ||
1013 | (*info).revision = "1.0"; | ||
1014 | } | ||
1015 | |||
1016 | long ata_last_disk_activity(void) | ||
1017 | { | ||
1018 | return ata_last_activity_value; | ||
1019 | } | ||
1020 | |||
1021 | int ata_init(void) | ||
1022 | { | ||
1023 | mutex_init(&ata_mutex); | ||
1024 | semaphore_init(&ata_wakeup, 1, 0); | ||
1025 | semaphore_init(&mmc_wakeup, 1, 0); | ||
1026 | semaphore_init(&mmc_comp_wakeup, 1, 0); | ||
1027 | ceata = PDAT(11) & BIT(1); | ||
1028 | ata_powered = false; | ||
1029 | ata_total_sectors = 0; | ||
1030 | |||
1031 | /* get ata_identify_data */ | ||
1032 | mutex_lock(&ata_mutex); | ||
1033 | int rc = ata_power_up(); | ||
1034 | mutex_unlock(&ata_mutex); | ||
1035 | if (IS_ERR(rc)) return rc; | ||
1036 | |||
1037 | create_thread(ata_thread, ata_stack, | ||
1038 | sizeof(ata_stack), 0, "ATA idle monitor" | ||
1039 | IF_PRIO(, PRIORITY_USER_INTERFACE) | ||
1040 | IF_COP(, CPU)); | ||
1041 | return 0; | ||
1042 | } | ||
1043 | |||
1044 | #ifdef HAVE_ATA_SMART | ||
1045 | static int ata_smart(uint16_t* buf) | ||
1046 | { | ||
1047 | if (!ata_powered) PASS_RC(ata_power_up(), 3, 0); | ||
1048 | if (ceata) | ||
1049 | { | ||
1050 | memset(ceata_taskfile, 0, 16); | ||
1051 | ceata_taskfile[0xc] = 0x4f; | ||
1052 | ceata_taskfile[0xd] = 0xc2; | ||
1053 | ceata_taskfile[0xe] = BIT(6); | ||
1054 | ceata_taskfile[0xf] = 0xb0; | ||
1055 | PASS_RC(ceata_wait_idle(), 3, 1); | ||
1056 | if (((uint8_t*)ata_identify_data)[54] != 'A') /* Model != aAmsung */ | ||
1057 | { | ||
1058 | ceata_taskfile[0x9] = 0xd8; /* SMART enable operations */ | ||
1059 | PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 3, 2); | ||
1060 | PASS_RC(ceata_check_error(), 3, 3); | ||
1061 | } | ||
1062 | ceata_taskfile[0x9] = 0xd0; /* SMART read data */ | ||
1063 | PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 3, 4); | ||
1064 | PASS_RC(ceata_rw_multiple_block(false, buf, 1, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 3, 5); | ||
1065 | } | ||
1066 | else | ||
1067 | { | ||
1068 | int i; | ||
1069 | PASS_RC(ata_wait_for_not_bsy(10000000), 3, 6); | ||
1070 | ata_write_cbr(&ATA_PIO_FED, 0xd0); | ||
1071 | ata_write_cbr(&ATA_PIO_LMR, 0x4f); | ||
1072 | ata_write_cbr(&ATA_PIO_LHR, 0xc2); | ||
1073 | ata_write_cbr(&ATA_PIO_DVR, BIT(6)); | ||
1074 | ata_write_cbr(&ATA_PIO_CSD, 0xb0); | ||
1075 | PASS_RC(ata_wait_for_start_of_transfer(10000000), 3, 7); | ||
1076 | for (i = 0; i < 0x100; i++) buf[i] = ata_read_cbr(&ATA_PIO_DTR); | ||
1077 | } | ||
1078 | ata_set_active(); | ||
1079 | return 0; | ||
1080 | } | ||
1081 | |||
1082 | int ata_read_smart(struct ata_smart_values* smart_data) | ||
1083 | { | ||
1084 | mutex_lock(&ata_mutex); | ||
1085 | int rc = ata_smart((uint16_t*)smart_data); | ||
1086 | mutex_unlock(&ata_mutex); | ||
1087 | return rc; | ||
1088 | } | ||
1089 | #endif /* HAVE_ATA_SMART */ | ||
1090 | |||
1091 | #ifdef CONFIG_STORAGE_MULTI | ||
1092 | static int ata_num_drives(int first_drive) | ||
1093 | { | ||
1094 | /* We don't care which logical drive number(s) we have been assigned */ | ||
1095 | (void)first_drive; | ||
1096 | |||
1097 | return 1; | ||
1098 | } | ||
1099 | #endif | ||
1100 | |||
1101 | unsigned short* ata_get_identify(void) | ||
1102 | { | ||
1103 | return ata_identify_data; | ||
1104 | } | ||
1105 | |||
1106 | int ata_spinup_time(void) | ||
1107 | { | ||
1108 | return spinup_time; | ||
1109 | } | ||
1110 | |||
1111 | int ata_get_dma_mode(void) | ||
1112 | { | ||
1113 | return dma_mode; | ||
1114 | } | ||
1115 | |||
1116 | void INT_ATA(void) | ||
1117 | { | ||
1118 | uint32_t ata_irq = ATA_IRQ; | ||
1119 | ATA_IRQ = ata_irq; | ||
1120 | if (ata_irq & ATA_IRQ_MASK) semaphore_release(&ata_wakeup); | ||
1121 | ATA_IRQ_MASK = 0; | ||
1122 | } | ||
1123 | |||
1124 | void INT_MMC(void) | ||
1125 | { | ||
1126 | uint32_t irq = SDCI_IRQ; | ||
1127 | if (irq & SDCI_IRQ_DAT_DONE_INT) semaphore_release(&mmc_wakeup); | ||
1128 | if (irq & SDCI_IRQ_IOCARD_IRQ_INT) semaphore_release(&mmc_comp_wakeup); | ||
1129 | SDCI_IRQ = irq; | ||
1130 | } | ||
1131 | |||