| 643 |
theseven |
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 "global.h"
|
|
|
22 |
#include "thread.h"
|
|
|
23 |
#include "disk.h"
|
|
|
24 |
#include "storage.h"
|
|
|
25 |
#include "storage_ata-target.h"
|
|
|
26 |
#include "timer.h"
|
| 813 |
theseven |
27 |
#include "malloc.h"
|
| 643 |
theseven |
28 |
#include "constants/mmc.h"
|
|
|
29 |
#include "../ipodnano3g/s5l8702.h"
|
|
|
30 |
|
|
|
31 |
|
|
|
32 |
#ifndef ATA_RETRIES
|
|
|
33 |
#define ATA_RETRIES 3
|
|
|
34 |
#endif
|
|
|
35 |
|
|
|
36 |
|
|
|
37 |
#define CEATA_POWERUP_TIMEOUT 30000000
|
|
|
38 |
#define CEATA_COMMAND_TIMEOUT 1000000
|
|
|
39 |
#define CEATA_DAT_NONBUSY_TIMEOUT 5000000
|
|
|
40 |
#define CEATA_MMC_RCA 1
|
|
|
41 |
|
|
|
42 |
|
|
|
43 |
/** static, private data **/
|
| 738 |
theseven |
44 |
static uint8_t ceata_taskfile[16] CACHEALIGN_ATTR;
|
|
|
45 |
uint16_t ata_identify_data[0x100] CACHEALIGN_ATTR;
|
| 643 |
theseven |
46 |
bool ceata;
|
|
|
47 |
bool ata_lba48;
|
|
|
48 |
bool ata_dma;
|
|
|
49 |
uint64_t ata_total_sectors;
|
|
|
50 |
struct mutex ata_mutex;
|
|
|
51 |
static struct wakeup ata_wakeup;
|
|
|
52 |
static uint32_t ata_dma_flags;
|
|
|
53 |
static long ata_last_activity_value = -1;
|
|
|
54 |
static long ata_sleep_timeout = 20000000;
|
|
|
55 |
static struct scheduler_thread ata_thread_handle;
|
|
|
56 |
static uint32_t ata_stack[0x80] STACK_ATTR;
|
|
|
57 |
static bool ata_powered;
|
|
|
58 |
static int ata_retries = ATA_RETRIES;
|
|
|
59 |
static bool ata_error_srst = true;
|
|
|
60 |
static struct wakeup mmc_wakeup;
|
|
|
61 |
static struct wakeup mmc_comp_wakeup;
|
|
|
62 |
|
|
|
63 |
|
|
|
64 |
#ifdef ATA_HAVE_BBT
|
|
|
65 |
#include "panic.h"
|
|
|
66 |
uint16_t (*ata_bbt)[0x20];
|
|
|
67 |
uint64_t ata_virtual_sectors;
|
|
|
68 |
uint32_t ata_last_offset;
|
|
|
69 |
uint64_t ata_last_phys;
|
|
|
70 |
|
| 965 |
theseven |
71 |
static uint16_t ata_read_cbr(uint32_t volatile* reg);
|
| 643 |
theseven |
72 |
int ata_bbt_read_sectors(uint32_t sector, uint32_t count, void* buffer)
|
|
|
73 |
{
|
| 965 |
theseven |
74 |
if (ata_last_phys != sector - 1 && ata_last_phys > sector - 64) ata_reset();
|
| 643 |
theseven |
75 |
int rc = ata_rw_sectors_internal(sector, count, buffer, false);
|
|
|
76 |
if (rc) rc = ata_rw_sectors_internal(sector, count, buffer, false);
|
|
|
77 |
ata_last_phys = sector + count - 1;
|
|
|
78 |
ata_last_offset = 0;
|
|
|
79 |
if (IS_ERR(rc))
|
|
|
80 |
cprintf(CONSOLE_BOOT, "ATA: Error %08X while reading BBT (sector %d, count %d)\n",
|
|
|
81 |
rc, sector, count);
|
|
|
82 |
return rc;
|
|
|
83 |
}
|
|
|
84 |
#endif
|
|
|
85 |
|
|
|
86 |
static struct ata_target_driverinfo drvinfo =
|
|
|
87 |
{
|
|
|
88 |
.set_retries = ata_set_retries,
|
|
|
89 |
.srst_after_error = ata_srst_after_error,
|
|
|
90 |
#ifdef ATA_HAVE_BBT
|
|
|
91 |
.bbt_translate = ata_bbt_translate,
|
|
|
92 |
.bbt_reload = ata_bbt_reload,
|
| 965 |
theseven |
93 |
.bbt_disable = ata_bbt_disable,
|
| 643 |
theseven |
94 |
#endif
|
| 966 |
theseven |
95 |
.soft_reset = ata_soft_reset,
|
|
|
96 |
.hard_reset = ata_hard_reset,
|
|
|
97 |
.read_taskfile = ata_read_taskfile,
|
|
|
98 |
.raw_cmd = ata_raw_cmd,
|
| 643 |
theseven |
99 |
};
|
|
|
100 |
|
|
|
101 |
|
|
|
102 |
void ata_set_retries(int retries)
|
|
|
103 |
{
|
|
|
104 |
ata_retries = retries;
|
|
|
105 |
}
|
|
|
106 |
|
|
|
107 |
void ata_srst_after_error(bool enable)
|
|
|
108 |
{
|
|
|
109 |
ata_error_srst = enable;
|
|
|
110 |
}
|
|
|
111 |
|
| 968 |
theseven |
112 |
int ata_lock_exclusive(int timeout)
|
|
|
113 |
{
|
|
|
114 |
return mutex_lock(&ata_mutex, timeout);
|
|
|
115 |
}
|
|
|
116 |
|
|
|
117 |
void ata_unlock_exclusive()
|
|
|
118 |
{
|
|
|
119 |
mutex_unlock(&ata_mutex);
|
|
|
120 |
}
|
|
|
121 |
|
| 643 |
theseven |
122 |
static uint16_t ata_read_cbr(uint32_t volatile* reg)
|
|
|
123 |
{
|
|
|
124 |
while (!(ATA_PIO_READY & 2)) yield();
|
| 965 |
theseven |
125 |
uint32_t dummy = *reg;
|
| 643 |
theseven |
126 |
while (!(ATA_PIO_READY & 1)) yield();
|
|
|
127 |
return ATA_PIO_RDATA;
|
|
|
128 |
}
|
|
|
129 |
|
|
|
130 |
static void ata_write_cbr(uint32_t volatile* reg, uint16_t data)
|
|
|
131 |
{
|
|
|
132 |
while (!(ATA_PIO_READY & 2)) yield();
|
|
|
133 |
*reg = data;
|
|
|
134 |
}
|
|
|
135 |
|
|
|
136 |
static int ata_wait_for_not_bsy(long timeout)
|
|
|
137 |
{
|
|
|
138 |
long startusec = USEC_TIMER;
|
|
|
139 |
while (true)
|
|
|
140 |
{
|
|
|
141 |
uint8_t csd = ata_read_cbr(&ATA_PIO_CSD);
|
|
|
142 |
if (!(csd & BIT(7))) return 0;
|
|
|
143 |
if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(0);
|
|
|
144 |
}
|
|
|
145 |
}
|
|
|
146 |
|
|
|
147 |
static int ata_wait_for_rdy(long timeout)
|
|
|
148 |
{
|
|
|
149 |
long startusec = USEC_TIMER;
|
|
|
150 |
PASS_RC(ata_wait_for_not_bsy(timeout), 1, 0);
|
|
|
151 |
while (true)
|
|
|
152 |
{
|
|
|
153 |
uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
|
|
|
154 |
if (dad & BIT(6)) return 0;
|
|
|
155 |
if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(1);
|
|
|
156 |
}
|
|
|
157 |
}
|
|
|
158 |
|
|
|
159 |
static int ata_wait_for_start_of_transfer(long timeout)
|
|
|
160 |
{
|
|
|
161 |
long startusec = USEC_TIMER;
|
|
|
162 |
PASS_RC(ata_wait_for_not_bsy(timeout), 2, 0);
|
|
|
163 |
while (true)
|
|
|
164 |
{
|
|
|
165 |
uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
|
|
|
166 |
if (dad & BIT(0)) RET_ERR(1);
|
|
|
167 |
if ((dad & (BIT(7) | BIT(3))) == BIT(3)) return 0;
|
|
|
168 |
if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(2);
|
|
|
169 |
}
|
|
|
170 |
}
|
|
|
171 |
|
|
|
172 |
static int ata_wait_for_end_of_transfer(long timeout)
|
|
|
173 |
{
|
|
|
174 |
PASS_RC(ata_wait_for_not_bsy(timeout), 2, 0);
|
|
|
175 |
uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
|
|
|
176 |
if (dad & BIT(0)) RET_ERR(1);
|
|
|
177 |
if ((dad & (BIT(3) | BITRANGE(5, 7))) == BIT(6)) return 0;
|
|
|
178 |
RET_ERR(2);
|
|
|
179 |
}
|
|
|
180 |
|
|
|
181 |
int mmc_dsta_check_command_success(bool disable_crc)
|
|
|
182 |
{
|
|
|
183 |
int rc = 0;
|
|
|
184 |
uint32_t dsta = SDCI_DSTA;
|
|
|
185 |
if (dsta & SDCI_DSTA_RESTOUTE) rc |= 1;
|
|
|
186 |
if (dsta & SDCI_DSTA_RESENDE) rc |= 2;
|
|
|
187 |
if (dsta & SDCI_DSTA_RESINDE) rc |= 4;
|
|
|
188 |
if (!disable_crc)
|
|
|
189 |
if (dsta & SDCI_DSTA_RESCRCE)
|
|
|
190 |
rc |= 8;
|
|
|
191 |
if (rc) RET_ERR(rc);
|
|
|
192 |
return 0;
|
|
|
193 |
}
|
|
|
194 |
|
|
|
195 |
bool mmc_send_command(uint32_t cmd, uint32_t arg, uint32_t* result, int timeout)
|
|
|
196 |
{
|
|
|
197 |
long starttime = USEC_TIMER;
|
|
|
198 |
while ((SDCI_STATE & SDCI_STATE_CMD_STATE_MASK) != SDCI_STATE_CMD_STATE_CMD_IDLE)
|
|
|
199 |
{
|
|
|
200 |
if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(0);
|
|
|
201 |
yield();
|
|
|
202 |
}
|
|
|
203 |
SDCI_STAC = SDCI_STAC_CLR_CMDEND | SDCI_STAC_CLR_BIT_3
|
|
|
204 |
| SDCI_STAC_CLR_RESEND | SDCI_STAC_CLR_DATEND
|
|
|
205 |
| SDCI_STAC_CLR_DAT_CRCEND | SDCI_STAC_CLR_CRC_STAEND
|
|
|
206 |
| SDCI_STAC_CLR_RESTOUTE | SDCI_STAC_CLR_RESENDE
|
|
|
207 |
| SDCI_STAC_CLR_RESINDE | SDCI_STAC_CLR_RESCRCE
|
|
|
208 |
| SDCI_STAC_CLR_WR_DATCRCE | SDCI_STAC_CLR_RD_DATCRCE
|
|
|
209 |
| SDCI_STAC_CLR_RD_DATENDE0 | SDCI_STAC_CLR_RD_DATENDE1
|
|
|
210 |
| SDCI_STAC_CLR_RD_DATENDE2 | SDCI_STAC_CLR_RD_DATENDE3
|
|
|
211 |
| SDCI_STAC_CLR_RD_DATENDE4 | SDCI_STAC_CLR_RD_DATENDE5
|
|
|
212 |
| SDCI_STAC_CLR_RD_DATENDE6 | SDCI_STAC_CLR_RD_DATENDE7;
|
|
|
213 |
SDCI_ARGU = arg;
|
|
|
214 |
SDCI_CMD = cmd;
|
|
|
215 |
if (!(SDCI_DSTA & SDCI_DSTA_CMDRDY)) RET_ERR(1);
|
|
|
216 |
SDCI_CMD = cmd | SDCI_CMD_CMDSTR;
|
|
|
217 |
sleep(1000);
|
|
|
218 |
while (!(SDCI_DSTA & SDCI_DSTA_CMDEND))
|
|
|
219 |
{
|
|
|
220 |
if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(2);
|
|
|
221 |
yield();
|
|
|
222 |
}
|
|
|
223 |
if ((cmd & SDCI_CMD_RES_TYPE_MASK) != SDCI_CMD_RES_TYPE_NONE)
|
|
|
224 |
{
|
|
|
225 |
while (!(SDCI_DSTA & SDCI_DSTA_RESEND))
|
|
|
226 |
{
|
|
|
227 |
if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(3);
|
|
|
228 |
yield();
|
|
|
229 |
}
|
|
|
230 |
if (cmd & SDCI_CMD_RES_BUSY)
|
|
|
231 |
while (SDCI_DSTA & SDCI_DSTA_DAT_BUSY)
|
|
|
232 |
{
|
|
|
233 |
if (TIMEOUT_EXPIRED(starttime, CEATA_DAT_NONBUSY_TIMEOUT)) RET_ERR(4);
|
|
|
234 |
yield();
|
|
|
235 |
}
|
|
|
236 |
}
|
|
|
237 |
bool nocrc = (cmd & SDCI_CMD_RES_SIZE_MASK) == SDCI_CMD_RES_SIZE_136;
|
|
|
238 |
PASS_RC(mmc_dsta_check_command_success(nocrc), 3, 5);
|
|
|
239 |
if (result) *result = SDCI_RESP0;
|
|
|
240 |
return 0;
|
|
|
241 |
}
|
|
|
242 |
|
|
|
243 |
int mmc_get_card_status(uint32_t* result)
|
|
|
244 |
{
|
|
|
245 |
return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_STATUS)
|
|
|
246 |
| SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
|
|
|
247 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
|
|
|
248 |
MMC_CMD_SEND_STATUS_RCA(CEATA_MMC_RCA), result, CEATA_COMMAND_TIMEOUT);
|
|
|
249 |
}
|
|
|
250 |
|
|
|
251 |
int mmc_init()
|
|
|
252 |
{
|
|
|
253 |
sleep(100000);
|
|
|
254 |
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_GO_IDLE_STATE)
|
|
|
255 |
| SDCI_CMD_CMD_TYPE_BC | SDCI_CMD_RES_TYPE_NONE
|
|
|
256 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID,
|
|
|
257 |
0, NULL, CEATA_COMMAND_TIMEOUT), 3, 0);
|
|
|
258 |
long startusec = USEC_TIMER;
|
|
|
259 |
uint32_t result;
|
|
|
260 |
do
|
|
|
261 |
{
|
|
|
262 |
if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(1);
|
|
|
263 |
sleep(1000);
|
|
|
264 |
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_OP_COND)
|
|
|
265 |
| SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R3
|
|
|
266 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID,
|
|
|
267 |
MMC_CMD_SEND_OP_COND_OCR(MMC_OCR_270_360),
|
|
|
268 |
NULL, CEATA_COMMAND_TIMEOUT), 3, 2);
|
|
|
269 |
result = SDCI_RESP0;
|
|
|
270 |
}
|
|
|
271 |
while (!(result & MMC_OCR_POWER_UP_DONE));
|
|
|
272 |
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_ALL_SEND_CID)
|
|
|
273 |
| SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R2
|
|
|
274 |
| SDCI_CMD_RES_SIZE_136 | SDCI_CMD_NCR_NID_NID,
|
|
|
275 |
0, NULL, CEATA_COMMAND_TIMEOUT), 3, 3);
|
|
|
276 |
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SET_RELATIVE_ADDR)
|
|
|
277 |
| SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R1
|
|
|
278 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
|
|
|
279 |
MMC_CMD_SET_RELATIVE_ADDR_RCA(CEATA_MMC_RCA),
|
|
|
280 |
NULL, CEATA_COMMAND_TIMEOUT), 3, 4);
|
|
|
281 |
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SELECT_CARD)
|
|
|
282 |
| SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
|
|
|
283 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
|
|
|
284 |
MMC_CMD_SELECT_CARD_RCA(CEATA_MMC_RCA),
|
|
|
285 |
NULL, CEATA_COMMAND_TIMEOUT), 3, 5);
|
|
|
286 |
PASS_RC(mmc_get_card_status(&result), 3, 6);
|
|
|
287 |
if ((result & MMC_STATUS_CURRENT_STATE_MASK) != MMC_STATUS_CURRENT_STATE_TRAN) RET_ERR(7);
|
|
|
288 |
return 0;
|
|
|
289 |
}
|
|
|
290 |
|
|
|
291 |
int mmc_fastio_write(uint32_t addr, uint32_t data)
|
|
|
292 |
{
|
|
|
293 |
return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO)
|
|
|
294 |
| SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4
|
|
|
295 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
|
|
|
296 |
MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_WRITE
|
|
|
297 |
| MMC_CMD_FAST_IO_ADDRESS(addr) | MMC_CMD_FAST_IO_DATA(data),
|
|
|
298 |
NULL, CEATA_COMMAND_TIMEOUT);
|
|
|
299 |
}
|
|
|
300 |
|
|
|
301 |
int mmc_fastio_read(uint32_t addr, uint32_t* data)
|
|
|
302 |
{
|
|
|
303 |
return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO)
|
|
|
304 |
| SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4
|
|
|
305 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
|
|
|
306 |
MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_READ
|
|
|
307 |
| MMC_CMD_FAST_IO_ADDRESS(addr), data, CEATA_COMMAND_TIMEOUT);
|
|
|
308 |
}
|
|
|
309 |
|
|
|
310 |
int ceata_soft_reset()
|
|
|
311 |
{
|
|
|
312 |
PASS_RC(mmc_fastio_write(6, 4), 2, 0);
|
|
|
313 |
sleep(1000);
|
|
|
314 |
PASS_RC(mmc_fastio_write(6, 0), 2, 1);
|
|
|
315 |
sleep(10000);
|
|
|
316 |
long startusec = USEC_TIMER;
|
|
|
317 |
uint32_t status;
|
|
|
318 |
do
|
|
|
319 |
{
|
|
|
320 |
PASS_RC(mmc_fastio_read(0xf, &status), 2, 2);
|
|
|
321 |
if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(3);
|
|
|
322 |
sleep(1000);
|
|
|
323 |
}
|
|
|
324 |
while (status & 0x80);
|
|
|
325 |
return 0;
|
|
|
326 |
}
|
|
|
327 |
|
|
|
328 |
int mmc_dsta_check_data_success()
|
|
|
329 |
{
|
|
|
330 |
int rc = 0;
|
|
|
331 |
uint32_t dsta = SDCI_DSTA;
|
|
|
332 |
if (dsta & (SDCI_DSTA_WR_DATCRCE | SDCI_DSTA_RD_DATCRCE))
|
|
|
333 |
{
|
|
|
334 |
if (dsta & SDCI_DSTA_WR_DATCRCE) rc |= 1;
|
|
|
335 |
if (dsta & SDCI_DSTA_RD_DATCRCE) rc |= 2;
|
|
|
336 |
if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_TXERR) rc |= 4;
|
|
|
337 |
else if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_CARDERR) rc |= 8;
|
|
|
338 |
}
|
|
|
339 |
if (dsta & (SDCI_DSTA_RD_DATENDE0 | SDCI_DSTA_RD_DATENDE1 | SDCI_DSTA_RD_DATENDE2
|
|
|
340 |
| SDCI_DSTA_RD_DATENDE3 | SDCI_DSTA_RD_DATENDE4 | SDCI_DSTA_RD_DATENDE5
|
|
|
341 |
| SDCI_DSTA_RD_DATENDE6 | SDCI_DSTA_RD_DATENDE7))
|
|
|
342 |
rc |= 16;
|
|
|
343 |
if (rc) RET_ERR(rc);
|
|
|
344 |
return 0;
|
|
|
345 |
}
|
|
|
346 |
|
|
|
347 |
void mmc_discard_irq()
|
|
|
348 |
{
|
|
|
349 |
SDCI_IRQ = SDCI_IRQ_DAT_DONE_INT | SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT
|
|
|
350 |
| SDCI_IRQ_MASK_MASK_READ_WAIT_INT;
|
|
|
351 |
wakeup_wait(&mmc_wakeup, TIMEOUT_NONE);
|
|
|
352 |
}
|
|
|
353 |
|
|
|
354 |
int ceata_read_multiple_register(uint32_t addr, void* dest, uint32_t size)
|
|
|
355 |
{
|
|
|
356 |
if (size > 0x10) RET_ERR(0);
|
|
|
357 |
mmc_discard_irq();
|
|
|
358 |
SDCI_DMASIZE = size;
|
|
|
359 |
SDCI_DMACOUNT = 1;
|
|
|
360 |
SDCI_DMAADDR = dest;
|
|
|
361 |
SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST;
|
|
|
362 |
invalidate_dcache();
|
|
|
363 |
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG)
|
|
|
364 |
| SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_RES_TYPE_R1
|
|
|
365 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
|
|
|
366 |
MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_READ
|
|
|
367 |
| MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc)
|
|
|
368 |
| MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc),
|
|
|
369 |
NULL, CEATA_COMMAND_TIMEOUT), 2, 1);
|
|
|
370 |
if (wakeup_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT) == THREAD_TIMEOUT) RET_ERR(2);
|
|
|
371 |
PASS_RC(mmc_dsta_check_data_success(), 2, 3);
|
|
|
372 |
return 0;
|
|
|
373 |
}
|
|
|
374 |
|
|
|
375 |
int ceata_write_multiple_register(uint32_t addr, void* dest, uint32_t size)
|
|
|
376 |
{
|
|
|
377 |
int i;
|
|
|
378 |
if (size > 0x10) RET_ERR(0);
|
|
|
379 |
mmc_discard_irq();
|
|
|
380 |
SDCI_DMASIZE = size;
|
|
|
381 |
SDCI_DMACOUNT = 0;
|
|
|
382 |
SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST;
|
|
|
383 |
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG)
|
|
|
384 |
| SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR
|
|
|
385 |
| SDCI_CMD_RES_BUSY | SDCI_CMD_RES_TYPE_R1
|
|
|
386 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
|
|
|
387 |
MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_WRITE
|
|
|
388 |
| MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc)
|
|
|
389 |
| MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc),
|
|
|
390 |
NULL, CEATA_COMMAND_TIMEOUT), 3, 1);
|
|
|
391 |
SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX;
|
|
|
392 |
for (i = 0; i < size / 4; i++) SDCI_DATA = ((uint32_t*)dest)[i];
|
|
|
393 |
long startusec = USEC_TIMER;
|
|
|
394 |
if (wakeup_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT) == THREAD_TIMEOUT) RET_ERR(2);
|
|
|
395 |
while ((SDCI_STATE & SDCI_STATE_DAT_STATE_MASK) != SDCI_STATE_DAT_STATE_IDLE)
|
|
|
396 |
{
|
|
|
397 |
if (TIMEOUT_EXPIRED(startusec, CEATA_COMMAND_TIMEOUT)) RET_ERR(3);
|
|
|
398 |
yield();
|
|
|
399 |
}
|
|
|
400 |
PASS_RC(mmc_dsta_check_data_success(), 3, 4);
|
|
|
401 |
return 0;
|
|
|
402 |
}
|
|
|
403 |
|
|
|
404 |
int ceata_init(int buswidth)
|
|
|
405 |
{
|
|
|
406 |
uint32_t result;
|
|
|
407 |
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SWITCH) | SDCI_CMD_RES_BUSY
|
|
|
408 |
| SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
|
|
|
409 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
|
|
|
410 |
MMC_CMD_SWITCH_ACCESS_WRITE_BYTE
|
|
|
411 |
| MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_HS_TIMING)
|
|
|
412 |
| MMC_CMD_SWITCH_VALUE(MMC_CMD_SWITCH_FIELD_HS_TIMING_HIGH_SPEED),
|
|
|
413 |
&result, CEATA_COMMAND_TIMEOUT), 3, 0);
|
|
|
414 |
if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(1);
|
|
|
415 |
if (buswidth > 1)
|
|
|
416 |
{
|
|
|
417 |
int setting;
|
|
|
418 |
if (buswidth == 4) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_4BIT;
|
|
|
419 |
else if (buswidth == 8) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_8BIT;
|
|
|
420 |
else setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_1BIT;
|
|
|
421 |
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SWITCH) | SDCI_CMD_RES_BUSY
|
|
|
422 |
| SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
|
|
|
423 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
|
|
|
424 |
MMC_CMD_SWITCH_ACCESS_WRITE_BYTE
|
|
|
425 |
| MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_BUS_WIDTH)
|
|
|
426 |
| MMC_CMD_SWITCH_VALUE(setting),
|
|
|
427 |
&result, CEATA_COMMAND_TIMEOUT), 3, 2);
|
|
|
428 |
if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(3);
|
|
|
429 |
if (buswidth == 4)
|
|
|
430 |
SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_4BIT;
|
|
|
431 |
else if (buswidth == 8)
|
|
|
432 |
SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_8BIT;
|
|
|
433 |
}
|
|
|
434 |
PASS_RC(ceata_soft_reset(), 3, 4);
|
|
|
435 |
PASS_RC(ceata_read_multiple_register(0, ceata_taskfile, 0x10), 3, 5);
|
|
|
436 |
if (ceata_taskfile[0xc] != 0xce || ceata_taskfile[0xd] != 0xaa) RET_ERR(6);
|
|
|
437 |
PASS_RC(mmc_fastio_write(6, 0), 3, 7);
|
|
|
438 |
return 0;
|
|
|
439 |
}
|
|
|
440 |
|
|
|
441 |
int ceata_check_error()
|
|
|
442 |
{
|
|
|
443 |
uint32_t status, error;
|
|
|
444 |
PASS_RC(mmc_fastio_read(0xf, &status), 2, 0);
|
|
|
445 |
if (status & 1)
|
|
|
446 |
{
|
|
|
447 |
PASS_RC(mmc_fastio_read(0x9, &error), 2, 1);
|
|
|
448 |
RET_ERR((error << 2) | 2);
|
|
|
449 |
}
|
|
|
450 |
return 0;
|
|
|
451 |
}
|
|
|
452 |
|
|
|
453 |
int ceata_wait_idle()
|
|
|
454 |
{
|
|
|
455 |
long startusec = USEC_TIMER;
|
|
|
456 |
while (true)
|
|
|
457 |
{
|
|
|
458 |
uint32_t status;
|
|
|
459 |
PASS_RC(mmc_fastio_read(0xf, &status), 1, 0);
|
|
|
460 |
if (!(status & 0x88)) return 0;
|
|
|
461 |
if (TIMEOUT_EXPIRED(startusec, CEATA_DAT_NONBUSY_TIMEOUT)) RET_ERR(1);
|
|
|
462 |
sleep(50000);
|
|
|
463 |
}
|
|
|
464 |
}
|
|
|
465 |
|
|
|
466 |
int ceata_cancel_command()
|
|
|
467 |
{
|
|
|
468 |
*((uint32_t volatile*)0x3cf00200) = 0x9000e;
|
|
|
469 |
sleep(1);
|
|
|
470 |
*((uint32_t volatile*)0x3cf00200) = 0x9000f;
|
|
|
471 |
sleep(1);
|
|
|
472 |
*((uint32_t volatile*)0x3cf00200) = 0x90003;
|
|
|
473 |
sleep(1);
|
|
|
474 |
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_STOP_TRANSMISSION)
|
|
|
475 |
| SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY
|
|
|
476 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
|
|
|
477 |
0, NULL, CEATA_COMMAND_TIMEOUT), 1, 0);
|
|
|
478 |
PASS_RC(ceata_wait_idle(), 1, 1);
|
|
|
479 |
return 0;
|
|
|
480 |
}
|
|
|
481 |
|
| 966 |
theseven |
482 |
int ceata_rw_multiple_block(bool write, void* buf, uint32_t count, uint32_t blksize, long timeout)
|
| 643 |
theseven |
483 |
{
|
|
|
484 |
mmc_discard_irq();
|
|
|
485 |
uint32_t responsetype;
|
|
|
486 |
uint32_t cmdtype;
|
|
|
487 |
uint32_t direction;
|
|
|
488 |
if (write)
|
|
|
489 |
{
|
|
|
490 |
cmdtype = SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR;
|
|
|
491 |
responsetype = SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY;
|
|
|
492 |
direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_WRITE;
|
| 813 |
theseven |
493 |
clean_dcache();
|
| 643 |
theseven |
494 |
}
|
|
|
495 |
else
|
|
|
496 |
{
|
|
|
497 |
cmdtype = SDCI_CMD_CMD_TYPE_ADTC;
|
|
|
498 |
responsetype = SDCI_CMD_RES_TYPE_R1;
|
|
|
499 |
direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_READ;
|
| 813 |
theseven |
500 |
invalidate_dcache();
|
| 643 |
theseven |
501 |
}
|
| 966 |
theseven |
502 |
SDCI_DMASIZE = blksize;
|
| 643 |
theseven |
503 |
SDCI_DMAADDR = buf;
|
|
|
504 |
SDCI_DMACOUNT = count;
|
|
|
505 |
SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST;
|
|
|
506 |
PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_BLOCK)
|
|
|
507 |
| SDCI_CMD_CMD_TYPE_ADTC | cmdtype | responsetype
|
|
|
508 |
| SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
|
|
|
509 |
direction | MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT(count),
|
| 965 |
theseven |
510 |
NULL, CEATA_COMMAND_TIMEOUT), 3, 0);
|
| 643 |
theseven |
511 |
if (write) SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX;
|
|
|
512 |
if (wakeup_wait(&mmc_wakeup, timeout) == THREAD_TIMEOUT)
|
|
|
513 |
{
|
| 965 |
theseven |
514 |
PASS_RC(ceata_cancel_command(), 3, 1);
|
| 643 |
theseven |
515 |
RET_ERR(2);
|
|
|
516 |
}
|
| 965 |
theseven |
517 |
PASS_RC(mmc_dsta_check_data_success(), 3, 3);
|
| 643 |
theseven |
518 |
if (wakeup_wait(&mmc_comp_wakeup, timeout) == THREAD_TIMEOUT)
|
|
|
519 |
{
|
| 965 |
theseven |
520 |
PASS_RC(ceata_cancel_command(), 3, 4);
|
|
|
521 |
RET_ERR(5);
|
| 643 |
theseven |
522 |
}
|
| 965 |
theseven |
523 |
PASS_RC(ceata_check_error(), 3, 6);
|
| 643 |
theseven |
524 |
return 0;
|
|
|
525 |
}
|
|
|
526 |
|
|
|
527 |
int ata_identify(uint16_t* buf)
|
|
|
528 |
{
|
|
|
529 |
int i;
|
|
|
530 |
if (ceata)
|
|
|
531 |
{
|
|
|
532 |
memset(ceata_taskfile, 0, 16);
|
|
|
533 |
ceata_taskfile[0xf] = 0xec;
|
|
|
534 |
PASS_RC(ceata_wait_idle(), 2, 0);
|
|
|
535 |
PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1);
|
| 966 |
theseven |
536 |
PASS_RC(ceata_rw_multiple_block(false, buf, 1, 256, CEATA_COMMAND_TIMEOUT), 2, 2);
|
| 643 |
theseven |
537 |
}
|
|
|
538 |
else
|
|
|
539 |
{
|
| 966 |
theseven |
540 |
PASS_RC(ata_wait_for_not_bsy(10000000), 2, 0);
|
| 643 |
theseven |
541 |
ata_write_cbr(&ATA_PIO_DVR, 0);
|
|
|
542 |
ata_write_cbr(&ATA_PIO_CSD, 0xec);
|
| 966 |
theseven |
543 |
PASS_RC(ata_wait_for_start_of_transfer(10000000), 2, 1);
|
| 836 |
theseven |
544 |
for (i = 0; i < 0x100; i++) buf[i] = ata_read_cbr(&ATA_PIO_DTR);
|
| 966 |
theseven |
545 |
PASS_RC(ata_wait_for_end_of_transfer(100000), 2, 2);
|
| 643 |
theseven |
546 |
}
|
|
|
547 |
return 0;
|
|
|
548 |
}
|
|
|
549 |
|
|
|
550 |
void ata_set_active(void)
|
|
|
551 |
{
|
|
|
552 |
ata_last_activity_value = USEC_TIMER;
|
|
|
553 |
}
|
|
|
554 |
|
|
|
555 |
bool ata_disk_is_active(void)
|
|
|
556 |
{
|
|
|
557 |
return ata_powered;
|
|
|
558 |
}
|
|
|
559 |
|
|
|
560 |
int ata_set_feature(uint32_t feature, uint32_t param)
|
|
|
561 |
{
|
| 965 |
theseven |
562 |
if (ceata)
|
|
|
563 |
{
|
|
|
564 |
memset(ceata_taskfile, 0, 16);
|
|
|
565 |
ceata_taskfile[0x1] = feature;
|
|
|
566 |
ceata_taskfile[0x2] = param;
|
|
|
567 |
ceata_taskfile[0xf] = 0xef;
|
|
|
568 |
PASS_RC(ceata_wait_idle(), 2, 0);
|
|
|
569 |
PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1);
|
|
|
570 |
PASS_RC(ceata_wait_idle(), 2, 2);
|
|
|
571 |
}
|
|
|
572 |
else
|
|
|
573 |
{
|
|
|
574 |
PASS_RC(ata_wait_for_rdy(2000000), 2, 0);
|
|
|
575 |
ata_write_cbr(&ATA_PIO_DVR, 0);
|
|
|
576 |
ata_write_cbr(&ATA_PIO_FED, feature);
|
|
|
577 |
ata_write_cbr(&ATA_PIO_SCR, param);
|
|
|
578 |
ata_write_cbr(&ATA_PIO_CSD, 0xef);
|
|
|
579 |
PASS_RC(ata_wait_for_rdy(2000000), 2, 1);
|
|
|
580 |
}
|
| 643 |
theseven |
581 |
return 0;
|
|
|
582 |
}
|
|
|
583 |
|
|
|
584 |
int ata_power_up()
|
|
|
585 |
{
|
|
|
586 |
ata_set_active();
|
|
|
587 |
i2c_sendbyte(0, 0xe6, 0x1b, 1);
|
|
|
588 |
if (ceata)
|
|
|
589 |
{
|
| 965 |
theseven |
590 |
ata_lba48 = true;
|
|
|
591 |
ata_dma = true;
|
|
|
592 |
PCON(8) = 0x33333333;
|
|
|
593 |
PCON(9) = 0x00000033;
|
|
|
594 |
PCON(11) |= 0xf;
|
|
|
595 |
*((uint32_t volatile*)0x38a00000) = 0;
|
|
|
596 |
*((uint32_t volatile*)0x38700000) = 0;
|
| 643 |
theseven |
597 |
clockgate_enable(9, true);
|
|
|
598 |
SDCI_RESET = 0xa5;
|
|
|
599 |
sleep(1000);
|
|
|
600 |
*((uint32_t volatile*)0x3cf00380) = 0;
|
|
|
601 |
*((uint32_t volatile*)0x3cf0010c) = 0xff;
|
|
|
602 |
SDCI_CTRL = SDCI_CTRL_SDCIEN | SDCI_CTRL_CLK_SEL_SDCLK
|
|
|
603 |
| SDCI_CTRL_BIT_8 | SDCI_CTRL_BIT_14;
|
|
|
604 |
SDCI_CDIV = SDCI_CDIV_CLKDIV(260);
|
|
|
605 |
*((uint32_t volatile*)0x3cf00200) = 0xb000f;
|
|
|
606 |
SDCI_IRQ_MASK = SDCI_IRQ_MASK_MASK_DAT_DONE_INT | SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT;
|
| 965 |
theseven |
607 |
PASS_RC(mmc_init(), 3, 0);
|
| 643 |
theseven |
608 |
SDCI_CDIV = SDCI_CDIV_CLKDIV(4);
|
|
|
609 |
sleep(10000);
|
| 965 |
theseven |
610 |
PASS_RC(ceata_init(8), 3, 1);
|
|
|
611 |
PASS_RC(ata_identify(ata_identify_data), 3, 2);
|
| 643 |
theseven |
612 |
}
|
|
|
613 |
else
|
|
|
614 |
{
|
| 965 |
theseven |
615 |
PCON(7) = 0x44444444;
|
|
|
616 |
PCON(8) = 0x44444444;
|
|
|
617 |
PCON(9) = 0x44444444;
|
|
|
618 |
PCON(10) = (PCON(10) & ~0xffff) | 0x4444;
|
| 643 |
theseven |
619 |
clockgate_enable(5, true);
|
|
|
620 |
ATA_CFG = BIT(0);
|
| 965 |
theseven |
621 |
sleep(10000);
|
| 643 |
theseven |
622 |
ATA_CFG = 0;
|
|
|
623 |
sleep(6000);
|
|
|
624 |
ATA_SWRST = BIT(0);
|
|
|
625 |
sleep(500);
|
|
|
626 |
ATA_SWRST = 0;
|
|
|
627 |
sleep(90000);
|
|
|
628 |
ATA_CONTROL = BIT(0);
|
|
|
629 |
sleep(200000);
|
|
|
630 |
ATA_PIO_TIME = 0x191f7;
|
|
|
631 |
ATA_PIO_LHR = 0;
|
| 836 |
theseven |
632 |
ATA_CFG = BIT(6);
|
| 643 |
theseven |
633 |
while (!(ATA_PIO_READY & BIT(1))) sleep(100);
|
| 965 |
theseven |
634 |
PASS_RC(ata_identify(ata_identify_data), 3, 3);
|
| 643 |
theseven |
635 |
uint32_t piotime = 0x11f3;
|
|
|
636 |
uint32_t mdmatime = 0x1c175;
|
|
|
637 |
uint32_t udmatime = 0x5071152;
|
|
|
638 |
uint32_t param = 0;
|
|
|
639 |
ata_dma_flags = 0;
|
|
|
640 |
ata_lba48 = ata_identify_data[83] & BIT(10) ? true : false;
|
|
|
641 |
if (ata_identify_data[53] & BIT(1))
|
|
|
642 |
{
|
|
|
643 |
if (ata_identify_data[64] & BIT(1)) piotime = 0x2072;
|
|
|
644 |
else if (ata_identify_data[64] & BIT(0)) piotime = 0x7083;
|
|
|
645 |
}
|
|
|
646 |
if (ata_identify_data[63] & BIT(2))
|
|
|
647 |
{
|
|
|
648 |
mdmatime = 0x5072;
|
|
|
649 |
param = 0x22;
|
|
|
650 |
}
|
|
|
651 |
else if (ata_identify_data[63] & BIT(1))
|
|
|
652 |
{
|
|
|
653 |
mdmatime = 0x7083;
|
|
|
654 |
param = 0x21;
|
|
|
655 |
}
|
|
|
656 |
if (ata_identify_data[63] & BITRANGE(0, 2))
|
|
|
657 |
{
|
|
|
658 |
ata_dma_flags = BIT(3) | BIT(10);
|
|
|
659 |
param |= 0x20;
|
|
|
660 |
}
|
|
|
661 |
if (ata_identify_data[53] & BIT(2))
|
|
|
662 |
{
|
|
|
663 |
if (ata_identify_data[88] & BIT(4))
|
|
|
664 |
{
|
|
|
665 |
udmatime = 0x2010a52;
|
|
|
666 |
param = 0x44;
|
|
|
667 |
}
|
|
|
668 |
else if (ata_identify_data[88] & BIT(3))
|
|
|
669 |
{
|
|
|
670 |
udmatime = 0x2020a52;
|
|
|
671 |
param = 0x43;
|
|
|
672 |
}
|
|
|
673 |
else if (ata_identify_data[88] & BIT(2))
|
|
|
674 |
{
|
|
|
675 |
udmatime = 0x3030a52;
|
|
|
676 |
param = 0x42;
|
|
|
677 |
}
|
|
|
678 |
else if (ata_identify_data[88] & BIT(1))
|
|
|
679 |
{
|
|
|
680 |
udmatime = 0x3050a52;
|
|
|
681 |
param = 0x41;
|
|
|
682 |
}
|
|
|
683 |
if (ata_identify_data[88] & BITRANGE(0, 4))
|
|
|
684 |
{
|
|
|
685 |
ata_dma_flags = BIT(2) | BIT(3) | BIT(9) | BIT(10);
|
|
|
686 |
param |= 0x40;
|
|
|
687 |
}
|
|
|
688 |
}
|
|
|
689 |
ata_dma = param ? true : false;
|
| 965 |
theseven |
690 |
PASS_RC(ata_set_feature(0x03, param), 3, 4);
|
| 643 |
theseven |
691 |
ATA_PIO_TIME = piotime;
|
|
|
692 |
ATA_MDMA_TIME = mdmatime;
|
|
|
693 |
ATA_UDMA_TIME = udmatime;
|
|
|
694 |
}
|
| 965 |
theseven |
695 |
if (ata_identify_data[82] & BIT(5))
|
|
|
696 |
PASS_RC(ata_set_feature(ata_bbt ? 0x82 : 0x02, 0), 3, 5);
|
|
|
697 |
if (ata_identify_data[82] & BIT(6)) PASS_RC(ata_set_feature(0xaa, 0), 3, 6);
|
| 643 |
theseven |
698 |
if (ata_lba48)
|
|
|
699 |
ata_total_sectors = ata_identify_data[100]
|
|
|
700 |
| (((uint64_t)ata_identify_data[101]) << 16)
|
|
|
701 |
| (((uint64_t)ata_identify_data[102]) << 32)
|
|
|
702 |
| (((uint64_t)ata_identify_data[103]) << 48);
|
|
|
703 |
else ata_total_sectors = ata_identify_data[60] | (((uint32_t)ata_identify_data[61]) << 16);
|
|
|
704 |
ata_total_sectors >>= 3;
|
|
|
705 |
ata_powered = true;
|
|
|
706 |
ata_set_active();
|
|
|
707 |
return 0;
|
|
|
708 |
}
|
|
|
709 |
|
|
|
710 |
void ata_power_down()
|
|
|
711 |
{
|
|
|
712 |
if (!ata_powered) return;
|
|
|
713 |
ata_powered = false;
|
|
|
714 |
if (ceata)
|
|
|
715 |
{
|
|
|
716 |
memset(ceata_taskfile, 0, 16);
|
|
|
717 |
ceata_taskfile[0xf] = 0xe0;
|
|
|
718 |
ceata_wait_idle();
|
|
|
719 |
ceata_write_multiple_register(0, ceata_taskfile, 16);
|
| 965 |
theseven |
720 |
ceata_wait_idle();
|
|
|
721 |
sleep(100000);
|
| 643 |
theseven |
722 |
clockgate_enable(9, false);
|
|
|
723 |
}
|
|
|
724 |
else
|
|
|
725 |
{
|
|
|
726 |
ata_wait_for_rdy(1000000);
|
|
|
727 |
ata_write_cbr(&ATA_PIO_DVR, 0);
|
|
|
728 |
ata_write_cbr(&ATA_PIO_CSD, 0xe0);
|
|
|
729 |
ata_wait_for_rdy(1000000);
|
|
|
730 |
sleep(30000);
|
|
|
731 |
ATA_CONTROL = 0;
|
|
|
732 |
while (!(ATA_CONTROL & BIT(1))) yield();
|
|
|
733 |
clockgate_enable(5, false);
|
|
|
734 |
}
|
| 965 |
theseven |
735 |
PCON(7) = 0;
|
|
|
736 |
PCON(8) = 0;
|
|
|
737 |
PCON(9) = 0;
|
|
|
738 |
PCON(10) &= ~0xffff;
|
|
|
739 |
PCON(11) &= ~0xf;
|
| 643 |
theseven |
740 |
i2c_sendbyte(0, 0xe6, 0x1b, 0);
|
|
|
741 |
}
|
|
|
742 |
|
|
|
743 |
int ata_rw_chunk(uint64_t sector, uint32_t cnt, void* buffer, bool write)
|
|
|
744 |
{
|
|
|
745 |
if (ceata)
|
|
|
746 |
{
|
|
|
747 |
memset(ceata_taskfile, 0, 16);
|
|
|
748 |
ceata_taskfile[0x2] = cnt >> 5;
|
|
|
749 |
ceata_taskfile[0x3] = sector >> 21;
|
|
|
750 |
ceata_taskfile[0x4] = sector >> 29;
|
|
|
751 |
ceata_taskfile[0x5] = sector >> 37;
|
|
|
752 |
ceata_taskfile[0xa] = cnt << 3;
|
|
|
753 |
ceata_taskfile[0xb] = sector << 3;
|
|
|
754 |
ceata_taskfile[0xc] = sector >> 5;
|
|
|
755 |
ceata_taskfile[0xd] = sector >> 13;
|
|
|
756 |
ceata_taskfile[0xf] = write ? 0x35 : 0x25;
|
|
|
757 |
PASS_RC(ceata_wait_idle(), 2, 0);
|
|
|
758 |
PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1);
|
| 966 |
theseven |
759 |
PASS_RC(ceata_rw_multiple_block(write, buffer, cnt << 3, 512, CEATA_COMMAND_TIMEOUT), 2, 2);
|
| 643 |
theseven |
760 |
}
|
|
|
761 |
else
|
|
|
762 |
{
|
|
|
763 |
PASS_RC(ata_wait_for_rdy(100000), 2, 0);
|
|
|
764 |
ata_write_cbr(&ATA_PIO_DVR, 0);
|
|
|
765 |
if (ata_lba48)
|
|
|
766 |
{
|
|
|
767 |
ata_write_cbr(&ATA_PIO_SCR, cnt >> 5);
|
|
|
768 |
ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff);
|
|
|
769 |
ata_write_cbr(&ATA_PIO_LHR, (sector >> 37) & 0xff);
|
|
|
770 |
ata_write_cbr(&ATA_PIO_LMR, (sector >> 29) & 0xff);
|
|
|
771 |
ata_write_cbr(&ATA_PIO_LLR, (sector >> 21) & 0xff);
|
|
|
772 |
ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff);
|
|
|
773 |
ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff);
|
|
|
774 |
ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff);
|
|
|
775 |
ata_write_cbr(&ATA_PIO_DVR, BIT(6));
|
|
|
776 |
if (write) ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0x35 : 0x39);
|
|
|
777 |
else ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0x25 : 0x29);
|
|
|
778 |
}
|
|
|
779 |
else
|
|
|
780 |
{
|
|
|
781 |
ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff);
|
|
|
782 |
ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff);
|
|
|
783 |
ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff);
|
|
|
784 |
ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff);
|
|
|
785 |
ata_write_cbr(&ATA_PIO_DVR, BIT(6) | ((sector >> 21) & 0xf));
|
|
|
786 |
if (write) ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0xca : 0x30);
|
|
|
787 |
else ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0xc8 : 0xc4);
|
|
|
788 |
}
|
|
|
789 |
if (ata_dma)
|
|
|
790 |
{
|
|
|
791 |
PASS_RC(ata_wait_for_start_of_transfer(500000), 2, 1);
|
|
|
792 |
if (write)
|
|
|
793 |
{
|
| 813 |
theseven |
794 |
clean_dcache();
|
| 643 |
theseven |
795 |
ATA_SBUF_START = buffer;
|
|
|
796 |
ATA_SBUF_SIZE = SECTOR_SIZE * cnt;
|
|
|
797 |
ATA_CFG |= BIT(4);
|
|
|
798 |
}
|
|
|
799 |
else
|
|
|
800 |
{
|
| 813 |
theseven |
801 |
invalidate_dcache();
|
| 643 |
theseven |
802 |
ATA_TBUF_START = buffer;
|
|
|
803 |
ATA_TBUF_SIZE = SECTOR_SIZE * cnt;
|
|
|
804 |
ATA_CFG &= ~BIT(4);
|
|
|
805 |
}
|
|
|
806 |
ATA_XFR_NUM = SECTOR_SIZE * cnt - 1;
|
|
|
807 |
ATA_CFG |= ata_dma_flags;
|
|
|
808 |
ATA_CFG &= ~(BIT(7) | BIT(8));
|
|
|
809 |
wakeup_wait(&ata_wakeup, TIMEOUT_NONE);
|
|
|
810 |
ATA_IRQ = BITRANGE(0, 4);
|
|
|
811 |
ATA_IRQ_MASK = BIT(0);
|
|
|
812 |
ATA_COMMAND = BIT(0);
|
|
|
813 |
if (wakeup_wait(&ata_wakeup, 500000) == THREAD_TIMEOUT)
|
|
|
814 |
{
|
|
|
815 |
ATA_COMMAND = BIT(1);
|
|
|
816 |
ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12));
|
|
|
817 |
RET_ERR(2);
|
|
|
818 |
}
|
|
|
819 |
ATA_COMMAND = BIT(1);
|
|
|
820 |
ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12));
|
|
|
821 |
}
|
|
|
822 |
else
|
|
|
823 |
{
|
|
|
824 |
cnt *= SECTOR_SIZE / 512;
|
|
|
825 |
while (cnt--)
|
|
|
826 |
{
|
|
|
827 |
int i;
|
|
|
828 |
PASS_RC(ata_wait_for_start_of_transfer(500000), 2, 1);
|
|
|
829 |
if (write)
|
|
|
830 |
for (i = 0; i < 256; i++)
|
|
|
831 |
ata_write_cbr(&ATA_PIO_DTR, ((uint16_t*)buffer)[i]);
|
|
|
832 |
else
|
|
|
833 |
for (i = 0; i < 256; i++)
|
|
|
834 |
((uint16_t*)buffer)[i] = ata_read_cbr(&ATA_PIO_DTR);
|
|
|
835 |
buffer += 512;
|
|
|
836 |
}
|
|
|
837 |
}
|
|
|
838 |
PASS_RC(ata_wait_for_end_of_transfer(100000), 2, 3);
|
|
|
839 |
}
|
|
|
840 |
return 0;
|
|
|
841 |
}
|
|
|
842 |
|
|
|
843 |
#ifdef ATA_HAVE_BBT
|
|
|
844 |
int ata_bbt_translate(uint64_t sector, uint32_t count, uint64_t* phys, uint32_t* physcount)
|
|
|
845 |
{
|
|
|
846 |
if (sector + count > ata_virtual_sectors) RET_ERR(0);
|
|
|
847 |
if (!ata_bbt)
|
|
|
848 |
{
|
|
|
849 |
*phys = sector;
|
|
|
850 |
*physcount = count;
|
|
|
851 |
return 0;
|
|
|
852 |
}
|
|
|
853 |
if (!count)
|
|
|
854 |
{
|
|
|
855 |
*phys = 0;
|
|
|
856 |
*physcount = 0;
|
|
|
857 |
return 0;
|
|
|
858 |
}
|
|
|
859 |
uint32_t offset;
|
|
|
860 |
uint32_t l0idx = sector >> 15;
|
|
|
861 |
uint32_t l0offs = sector & 0x7fff;
|
|
|
862 |
*physcount = MIN(count, 0x8000 - l0offs);
|
|
|
863 |
uint32_t l0data = ata_bbt[0][l0idx << 1];
|
|
|
864 |
uint32_t base = ata_bbt[0][(l0idx << 1) | 1] << 12;
|
|
|
865 |
if (l0data < 0x8000) offset = l0data + base;
|
|
|
866 |
else
|
|
|
867 |
{
|
|
|
868 |
uint32_t l1idx = (sector >> 10) & 0x1f;
|
|
|
869 |
uint32_t l1offs = sector & 0x3ff;
|
|
|
870 |
*physcount = MIN(count, 0x400 - l1offs);
|
|
|
871 |
uint32_t l1data = ata_bbt[l0data & 0x7fff][l1idx];
|
|
|
872 |
if (l1data < 0x8000) offset = l1data + base;
|
|
|
873 |
else
|
|
|
874 |
{
|
|
|
875 |
uint32_t l2idx = (sector >> 5) & 0x1f;
|
|
|
876 |
uint32_t l2offs = sector & 0x1f;
|
|
|
877 |
*physcount = MIN(count, 0x20 - l2offs);
|
|
|
878 |
uint32_t l2data = ata_bbt[l1data & 0x7fff][l2idx];
|
|
|
879 |
if (l2data < 0x8000) offset = l2data + base;
|
|
|
880 |
else
|
|
|
881 |
{
|
|
|
882 |
uint32_t l3idx = sector & 0x1f;
|
|
|
883 |
uint32_t l3data = ata_bbt[l2data & 0x7fff][l3idx];
|
| 650 |
theseven |
884 |
for (*physcount = 1; *physcount < count && l3idx + *physcount < 0x20; (*physcount)++)
|
| 643 |
theseven |
885 |
if (ata_bbt[l2data & 0x7fff][l3idx + *physcount] != l3data)
|
|
|
886 |
break;
|
|
|
887 |
offset = l3data + base;
|
|
|
888 |
}
|
|
|
889 |
}
|
|
|
890 |
}
|
|
|
891 |
*phys = sector + offset;
|
|
|
892 |
return 0;
|
|
|
893 |
}
|
|
|
894 |
#endif
|
|
|
895 |
|
|
|
896 |
int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool write)
|
|
|
897 |
{
|
|
|
898 |
if (((uint32_t)buffer) & (CACHEALIGN_SIZE - 1))
|
|
|
899 |
panicf(PANIC_KILLTHREAD,
|
|
|
900 |
"ATA: Misaligned data buffer at %08X (sector %lu, count %lu)",
|
|
|
901 |
(unsigned int)buffer, (unsigned int)sector, count);
|
|
|
902 |
#ifdef ATA_HAVE_BBT
|
|
|
903 |
if (sector + count > ata_virtual_sectors) RET_ERR(0);
|
|
|
904 |
if (ata_bbt)
|
|
|
905 |
while (count)
|
|
|
906 |
{
|
|
|
907 |
uint64_t phys;
|
|
|
908 |
uint32_t cnt;
|
|
|
909 |
PASS_RC(ata_bbt_translate(sector, count, &phys, &cnt), 0, 0);
|
|
|
910 |
uint32_t offset = phys - sector;
|
| 965 |
theseven |
911 |
if (offset != ata_last_offset && phys - ata_last_phys < 64) ata_reset();
|
| 643 |
theseven |
912 |
ata_last_offset = offset;
|
|
|
913 |
ata_last_phys = phys + cnt;
|
|
|
914 |
PASS_RC(ata_rw_sectors_internal(phys, cnt, buffer, write), 0, 0);
|
|
|
915 |
buffer += cnt * SECTOR_SIZE;
|
|
|
916 |
sector += cnt;
|
|
|
917 |
count -= cnt;
|
|
|
918 |
}
|
|
|
919 |
else PASS_RC(ata_rw_sectors_internal(sector, count, buffer, write), 0, 0);
|
|
|
920 |
return 0;
|
|
|
921 |
}
|
|
|
922 |
|
|
|
923 |
int ata_rw_sectors_internal(uint64_t sector, uint32_t count, void* buffer, bool write)
|
|
|
924 |
{
|
|
|
925 |
#endif
|
|
|
926 |
if (sector + count > ata_total_sectors) RET_ERR(0);
|
| 920 |
theseven |
927 |
if (!ata_powered) PASS_RC(ata_power_up(), 2, 1);
|
| 643 |
theseven |
928 |
ata_set_active();
|
|
|
929 |
if (ata_dma && write) clean_dcache();
|
|
|
930 |
else if (ata_dma) invalidate_dcache();
|
|
|
931 |
if (!ceata) ATA_COMMAND = BIT(1);
|
|
|
932 |
while (count)
|
|
|
933 |
{
|
|
|
934 |
uint32_t cnt = MIN(ata_lba48 ? 8192 : 32, count);
|
|
|
935 |
int rc = -1;
|
|
|
936 |
rc = ata_rw_chunk(sector, cnt, buffer, write);
|
| 965 |
theseven |
937 |
if (rc && ata_error_srst) ata_reset();
|
| 643 |
theseven |
938 |
if (rc && ata_retries)
|
|
|
939 |
{
|
|
|
940 |
void* buf = buffer;
|
|
|
941 |
uint64_t sect;
|
|
|
942 |
for (sect = sector; sect < sector + cnt; sect++)
|
|
|
943 |
{
|
|
|
944 |
rc = -1;
|
|
|
945 |
int tries = ata_retries;
|
|
|
946 |
while (tries-- && rc)
|
|
|
947 |
{
|
|
|
948 |
rc = ata_rw_chunk(sect, 1, buf, write);
|
| 965 |
theseven |
949 |
if (rc && ata_error_srst) ata_reset();
|
| 643 |
theseven |
950 |
}
|
|
|
951 |
if (rc) break;
|
|
|
952 |
buf += SECTOR_SIZE;
|
|
|
953 |
}
|
|
|
954 |
}
|
| 920 |
theseven |
955 |
PASS_RC(rc, 2, 2);
|
| 643 |
theseven |
956 |
buffer += SECTOR_SIZE * cnt;
|
|
|
957 |
sector += cnt;
|
|
|
958 |
count -= cnt;
|
|
|
959 |
}
|
|
|
960 |
ata_set_active();
|
|
|
961 |
return 0;
|
|
|
962 |
}
|
|
|
963 |
|
| 835 |
theseven |
964 |
static void ata_thread(void* arg0, void* arg1, void* arg2, void* arg3)
|
| 643 |
theseven |
965 |
{
|
|
|
966 |
while (true)
|
|
|
967 |
{
|
|
|
968 |
mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
|
|
969 |
if (TIME_AFTER(USEC_TIMER, ata_last_activity_value + ata_sleep_timeout) && ata_powered)
|
|
|
970 |
ata_power_down();
|
|
|
971 |
mutex_unlock(&ata_mutex);
|
|
|
972 |
sleep(1000000);
|
|
|
973 |
}
|
|
|
974 |
}
|
|
|
975 |
|
|
|
976 |
/* API Functions */
|
|
|
977 |
int ata_soft_reset()
|
|
|
978 |
{
|
|
|
979 |
int rc;
|
|
|
980 |
mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
| 920 |
theseven |
981 |
if (!ata_powered) PASS_RC(ata_power_up(), 1, 0);
|
| 643 |
theseven |
982 |
ata_set_active();
|
|
|
983 |
if (ceata) rc = ceata_soft_reset();
|
|
|
984 |
else
|
|
|
985 |
{
|
|
|
986 |
ata_write_cbr(&ATA_PIO_DAD, BIT(1) | BIT(2));
|
|
|
987 |
sleep(10);
|
|
|
988 |
ata_write_cbr(&ATA_PIO_DAD, 0);
|
| 965 |
theseven |
989 |
rc = ata_wait_for_rdy(3000000);
|
| 643 |
theseven |
990 |
}
|
| 965 |
theseven |
991 |
ata_set_active();
|
|
|
992 |
mutex_unlock(&ata_mutex);
|
|
|
993 |
PASS_RC(rc, 1, 1);
|
|
|
994 |
return 0;
|
|
|
995 |
}
|
|
|
996 |
|
|
|
997 |
int ata_hard_reset()
|
|
|
998 |
{
|
|
|
999 |
mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
|
|
1000 |
PASS_RC(ata_power_up(), 0, 0);
|
|
|
1001 |
ata_set_active();
|
|
|
1002 |
mutex_unlock(&ata_mutex);
|
|
|
1003 |
return 0;
|
|
|
1004 |
}
|
|
|
1005 |
|
|
|
1006 |
int ata_reset()
|
|
|
1007 |
{
|
|
|
1008 |
int rc;
|
|
|
1009 |
mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
|
|
1010 |
if (!ata_powered) PASS_RC(ata_power_up(), 2, 0);
|
|
|
1011 |
ata_set_active();
|
|
|
1012 |
rc = ata_soft_reset();
|
| 643 |
theseven |
1013 |
if (IS_ERR(rc))
|
|
|
1014 |
{
|
| 965 |
theseven |
1015 |
rc = ata_hard_reset();
|
|
|
1016 |
if (IS_ERR(rc))
|
|
|
1017 |
{
|
|
|
1018 |
rc = ERR_RC((rc << 2) | 1);
|
|
|
1019 |
ata_power_down();
|
|
|
1020 |
sleep(3000000);
|
|
|
1021 |
int rc2 = ata_power_up();
|
|
|
1022 |
if (IS_ERR(rc2)) rc = ERR_RC((rc << 2) | 2);
|
|
|
1023 |
}
|
|
|
1024 |
else rc = 1;
|
| 643 |
theseven |
1025 |
}
|
|
|
1026 |
ata_set_active();
|
|
|
1027 |
mutex_unlock(&ata_mutex);
|
| 965 |
theseven |
1028 |
return rc;
|
| 643 |
theseven |
1029 |
}
|
|
|
1030 |
|
| 966 |
theseven |
1031 |
int ata_read_taskfile(struct ata_raw_cmd_t* cmd)
|
|
|
1032 |
{
|
|
|
1033 |
mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
|
|
1034 |
if (!ata_powered) PASS_RC(ata_power_up(), 1, 0);
|
|
|
1035 |
ata_set_active();
|
|
|
1036 |
cmd->result_valid = false;
|
|
|
1037 |
if (ceata)
|
|
|
1038 |
{
|
|
|
1039 |
PASS_RC_MTX(ceata_read_multiple_register(0, ceata_taskfile, 16), 1, 1, &ata_mutex);
|
|
|
1040 |
cmd->feature = ceata_taskfile[0x9];
|
|
|
1041 |
cmd->count = ceata_taskfile[0xa];
|
|
|
1042 |
cmd->lba_low = ceata_taskfile[0xb];
|
|
|
1043 |
cmd->lba_mid = ceata_taskfile[0xc];
|
|
|
1044 |
cmd->lba_high = ceata_taskfile[0xd];
|
|
|
1045 |
cmd->device = ceata_taskfile[0xe];
|
|
|
1046 |
cmd->command = ceata_taskfile[0xf];
|
|
|
1047 |
if (cmd->lba48)
|
|
|
1048 |
{
|
|
|
1049 |
cmd->feature |= ceata_taskfile[0x1] << 8;
|
|
|
1050 |
cmd->count |= ceata_taskfile[0x2] << 8;
|
|
|
1051 |
cmd->lba_low |= ceata_taskfile[0x3] << 8;
|
|
|
1052 |
cmd->lba_mid |= ceata_taskfile[0x4] << 8;
|
|
|
1053 |
cmd->lba_high |= ceata_taskfile[0x5] << 8;
|
|
|
1054 |
}
|
|
|
1055 |
}
|
|
|
1056 |
else
|
|
|
1057 |
{
|
|
|
1058 |
cmd->feature = ata_read_cbr(&ATA_PIO_FED);
|
|
|
1059 |
cmd->count = ata_read_cbr(&ATA_PIO_SCR);
|
|
|
1060 |
cmd->lba_low = ata_read_cbr(&ATA_PIO_LLR);
|
|
|
1061 |
cmd->lba_mid = ata_read_cbr(&ATA_PIO_LMR);
|
|
|
1062 |
cmd->lba_high = ata_read_cbr(&ATA_PIO_LHR);
|
|
|
1063 |
cmd->device = ata_read_cbr(&ATA_PIO_DVR);
|
|
|
1064 |
cmd->command = ata_read_cbr(&ATA_PIO_CSD);
|
|
|
1065 |
if (cmd->lba48)
|
|
|
1066 |
{
|
|
|
1067 |
ata_write_cbr(&ATA_PIO_DAD, BIT(7));
|
|
|
1068 |
cmd->feature |= ata_read_cbr(&ATA_PIO_FED) << 8;
|
|
|
1069 |
cmd->count |= ata_read_cbr(&ATA_PIO_SCR) << 8;
|
|
|
1070 |
cmd->lba_low |= ata_read_cbr(&ATA_PIO_LLR) << 8;
|
|
|
1071 |
cmd->lba_mid |= ata_read_cbr(&ATA_PIO_LMR) << 8;
|
|
|
1072 |
cmd->lba_high |= ata_read_cbr(&ATA_PIO_LHR) << 8;
|
|
|
1073 |
ata_write_cbr(&ATA_PIO_DAD, 0);
|
|
|
1074 |
}
|
|
|
1075 |
}
|
|
|
1076 |
cmd->result_valid = true;
|
|
|
1077 |
ata_set_active();
|
|
|
1078 |
mutex_unlock(&ata_mutex);
|
|
|
1079 |
return 0;
|
|
|
1080 |
}
|
|
|
1081 |
|
|
|
1082 |
int ata_raw_cmd(struct ata_raw_cmd_t* cmd)
|
|
|
1083 |
{
|
|
|
1084 |
mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
|
|
1085 |
if (!ata_powered) PASS_RC(ata_power_up(), 3, 0);
|
|
|
1086 |
ata_set_active();
|
|
|
1087 |
int rc = 0, rc2 = 0;
|
|
|
1088 |
cmd->result_valid = false;
|
|
|
1089 |
if (ceata)
|
|
|
1090 |
{
|
|
|
1091 |
memset(ceata_taskfile, 0, 16);
|
|
|
1092 |
if (cmd->lba48)
|
|
|
1093 |
{
|
|
|
1094 |
ceata_taskfile[0x1] = cmd->feature >> 8;
|
|
|
1095 |
ceata_taskfile[0x2] = cmd->count >> 8;
|
|
|
1096 |
ceata_taskfile[0x3] = cmd->lba_low >> 8;
|
|
|
1097 |
ceata_taskfile[0x4] = cmd->lba_mid >> 8;
|
|
|
1098 |
ceata_taskfile[0x5] = cmd->lba_high >> 8;
|
|
|
1099 |
}
|
|
|
1100 |
ceata_taskfile[0x9] = cmd->feature & 0xff;
|
|
|
1101 |
ceata_taskfile[0xa] = cmd->count & 0xff;
|
|
|
1102 |
ceata_taskfile[0xb] = cmd->lba_low & 0xff;
|
|
|
1103 |
ceata_taskfile[0xc] = cmd->lba_mid & 0xff;
|
|
|
1104 |
ceata_taskfile[0xd] = cmd->lba_high & 0xff;
|
|
|
1105 |
ceata_taskfile[0xe] = cmd->device;
|
|
|
1106 |
ceata_taskfile[0xf] = cmd->command;
|
|
|
1107 |
PASS_RC_MTX(ceata_wait_idle(), 3, 1, &ata_mutex);
|
|
|
1108 |
PASS_RC_MTX(ceata_write_multiple_register(0, ceata_taskfile, 16), 3, 2, &ata_mutex);
|
|
|
1109 |
if (cmd->transfer)
|
|
|
1110 |
rc = ceata_rw_multiple_block(cmd->send, cmd->buffer, cmd->size, cmd->blksize, CEATA_COMMAND_TIMEOUT);
|
|
|
1111 |
else rc = ceata_wait_idle();
|
|
|
1112 |
if (IS_ERR(rc)) rc = ERR_RC((rc << 3) | 3);
|
|
|
1113 |
rc2 = ata_read_taskfile(cmd);
|
|
|
1114 |
if (IS_ERR(rc2) && !IS_ERR(rc)) rc = ERR_RC((rc2 << 3) | 4);
|
|
|
1115 |
}
|
|
|
1116 |
else
|
|
|
1117 |
{
|
|
|
1118 |
PASS_RC_MTX(ata_wait_for_rdy(100000), 3, 1, &ata_mutex);
|
|
|
1119 |
ata_write_cbr(&ATA_PIO_DVR, 0);
|
|
|
1120 |
if (cmd->lba48)
|
|
|
1121 |
{
|
|
|
1122 |
ata_write_cbr(&ATA_PIO_FED, cmd->feature >> 8);
|
|
|
1123 |
ata_write_cbr(&ATA_PIO_SCR, cmd->count >> 8);
|
|
|
1124 |
ata_write_cbr(&ATA_PIO_LLR, cmd->lba_low >> 8);
|
|
|
1125 |
ata_write_cbr(&ATA_PIO_LMR, cmd->lba_mid >> 8);
|
|
|
1126 |
ata_write_cbr(&ATA_PIO_LHR, cmd->lba_high >> 8);
|
|
|
1127 |
}
|
|
|
1128 |
ata_write_cbr(&ATA_PIO_FED, cmd->feature & 0xff);
|
|
|
1129 |
ata_write_cbr(&ATA_PIO_SCR, cmd->count & 0xff);
|
|
|
1130 |
ata_write_cbr(&ATA_PIO_LLR, cmd->lba_low & 0xff);
|
|
|
1131 |
ata_write_cbr(&ATA_PIO_LMR, cmd->lba_mid & 0xff);
|
|
|
1132 |
ata_write_cbr(&ATA_PIO_LHR, cmd->lba_high & 0xff);
|
|
|
1133 |
ata_write_cbr(&ATA_PIO_DVR, cmd->device);
|
|
|
1134 |
ata_write_cbr(&ATA_PIO_CSD, cmd->command);
|
|
|
1135 |
sleep(cmd->delay);
|
|
|
1136 |
if (cmd->transfer)
|
|
|
1137 |
{
|
|
|
1138 |
if (cmd->dma)
|
|
|
1139 |
{
|
|
|
1140 |
rc = ata_wait_for_start_of_transfer(500000);
|
|
|
1141 |
if (IS_ERR(rc)) rc = ERR_RC((rc << 3) | 2);
|
|
|
1142 |
else
|
|
|
1143 |
{
|
|
|
1144 |
if (cmd->send)
|
|
|
1145 |
{
|
|
|
1146 |
clean_dcache();
|
|
|
1147 |
ATA_SBUF_START = cmd->buffer;
|
|
|
1148 |
ATA_SBUF_SIZE = cmd->size * cmd->blksize;
|
|
|
1149 |
ATA_CFG |= BIT(4);
|
|
|
1150 |
}
|
|
|
1151 |
else
|
|
|
1152 |
{
|
|
|
1153 |
invalidate_dcache();
|
|
|
1154 |
ATA_TBUF_START = cmd->buffer;
|
|
|
1155 |
ATA_TBUF_SIZE = cmd->size * cmd->blksize;
|
|
|
1156 |
ATA_CFG &= ~BIT(4);
|
|
|
1157 |
}
|
|
|
1158 |
ATA_XFR_NUM = cmd->blksize * cmd->size - 1;
|
|
|
1159 |
ATA_CFG |= ata_dma_flags;
|
|
|
1160 |
ATA_CFG &= ~(BIT(7) | BIT(8));
|
|
|
1161 |
wakeup_wait(&ata_wakeup, TIMEOUT_NONE);
|
|
|
1162 |
ATA_IRQ = BITRANGE(0, 4);
|
|
|
1163 |
ATA_IRQ_MASK = BIT(0);
|
|
|
1164 |
ATA_COMMAND = BIT(0);
|
|
|
1165 |
if (wakeup_wait(&ata_wakeup, 500000) == THREAD_TIMEOUT) rc = ERR_RC(3);
|
|
|
1166 |
ATA_COMMAND = BIT(1);
|
|
|
1167 |
ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12));
|
|
|
1168 |
}
|
|
|
1169 |
}
|
|
|
1170 |
else
|
|
|
1171 |
{
|
|
|
1172 |
ATA_CFG &= ~ata_dma_flags;
|
|
|
1173 |
while (cmd->size--)
|
|
|
1174 |
{
|
|
|
1175 |
rc = ata_wait_for_start_of_transfer(500000);
|
|
|
1176 |
if (IS_ERR(rc))
|
|
|
1177 |
{
|
|
|
1178 |
rc = ERR_RC((rc << 3) | 4);
|
|
|
1179 |
break;
|
|
|
1180 |
}
|
|
|
1181 |
int i;
|
|
|
1182 |
if (cmd->send)
|
|
|
1183 |
for (i = 0; i < (cmd->blksize >> 1); i++)
|
|
|
1184 |
ata_write_cbr(&ATA_PIO_DTR, ((uint16_t*)cmd->buffer)[i]);
|
|
|
1185 |
else
|
|
|
1186 |
for (i = 0; i < (cmd->blksize >> 1); i++)
|
|
|
1187 |
((uint16_t*)cmd->buffer)[i] = ata_read_cbr(&ATA_PIO_DTR);
|
|
|
1188 |
cmd->buffer += cmd->blksize;
|
|
|
1189 |
}
|
|
|
1190 |
}
|
|
|
1191 |
if (!IS_ERR(rc))
|
|
|
1192 |
{
|
|
|
1193 |
rc = ata_wait_for_end_of_transfer(100000);
|
|
|
1194 |
if (IS_ERR(rc)) rc = ERR_RC((rc << 3) | 5);
|
|
|
1195 |
}
|
|
|
1196 |
}
|
|
|
1197 |
else
|
|
|
1198 |
{
|
|
|
1199 |
rc = ata_wait_for_rdy(500000);
|
|
|
1200 |
if (IS_ERR(rc)) rc = ERR_RC((rc << 3) | 6);
|
|
|
1201 |
}
|
|
|
1202 |
ata_read_taskfile(cmd); // Cannot fail for PATA
|
|
|
1203 |
}
|
|
|
1204 |
ata_set_active();
|
|
|
1205 |
mutex_unlock(&ata_mutex);
|
|
|
1206 |
return rc;
|
|
|
1207 |
}
|
|
|
1208 |
|
| 643 |
theseven |
1209 |
int ata_read_sectors(IF_MD2(int drive,) unsigned long start, int incount,
|
|
|
1210 |
void* inbuf)
|
|
|
1211 |
{
|
|
|
1212 |
mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
|
|
1213 |
int rc = ata_rw_sectors(start, incount, inbuf, false);
|
|
|
1214 |
mutex_unlock(&ata_mutex);
|
|
|
1215 |
return rc;
|
|
|
1216 |
}
|
|
|
1217 |
|
|
|
1218 |
int ata_write_sectors(IF_MD2(int drive,) unsigned long start, int count,
|
|
|
1219 |
const void* outbuf)
|
|
|
1220 |
{
|
|
|
1221 |
mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
|
|
1222 |
int rc = ata_rw_sectors(start, count, (void*)((uint32_t)outbuf), true);
|
|
|
1223 |
mutex_unlock(&ata_mutex);
|
|
|
1224 |
return rc;
|
|
|
1225 |
}
|
|
|
1226 |
|
|
|
1227 |
void ata_spindown(int seconds)
|
|
|
1228 |
{
|
|
|
1229 |
ata_sleep_timeout = seconds * 1000000;
|
|
|
1230 |
}
|
|
|
1231 |
|
|
|
1232 |
void ata_sleep(void)
|
|
|
1233 |
{
|
| 646 |
theseven |
1234 |
ata_last_activity_value = USEC_TIMER - ata_sleep_timeout + 200000;
|
| 643 |
theseven |
1235 |
}
|
|
|
1236 |
|
|
|
1237 |
void ata_sleepnow(void)
|
|
|
1238 |
{
|
| 646 |
theseven |
1239 |
mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
|
|
1240 |
ata_power_down();
|
|
|
1241 |
mutex_unlock(&ata_mutex);
|
| 643 |
theseven |
1242 |
}
|
|
|
1243 |
|
|
|
1244 |
void ata_close(void)
|
|
|
1245 |
{
|
| 646 |
theseven |
1246 |
ata_sleepnow();
|
| 643 |
theseven |
1247 |
}
|
|
|
1248 |
|
|
|
1249 |
void ata_spin(void)
|
|
|
1250 |
{
|
| 646 |
theseven |
1251 |
ata_set_active();
|
| 643 |
theseven |
1252 |
}
|
|
|
1253 |
|
|
|
1254 |
void ata_get_info(IF_MD2(int drive,) struct storage_info *info)
|
|
|
1255 |
{
|
|
|
1256 |
(*info).sector_size = SECTOR_SIZE;
|
|
|
1257 |
#ifdef ATA_HAVE_BBT
|
|
|
1258 |
(*info).num_sectors = ata_virtual_sectors;
|
|
|
1259 |
#else
|
|
|
1260 |
(*info).num_sectors = ata_total_sectors;
|
|
|
1261 |
#endif
|
|
|
1262 |
(*info).vendor = "Apple";
|
|
|
1263 |
(*info).product = "iPod Classic";
|
|
|
1264 |
(*info).revision = "1.0";
|
|
|
1265 |
(*info).driverinfo = &drvinfo;
|
|
|
1266 |
}
|
|
|
1267 |
|
|
|
1268 |
long ata_last_disk_activity(void)
|
|
|
1269 |
{
|
|
|
1270 |
return ata_last_activity_value;
|
|
|
1271 |
}
|
|
|
1272 |
|
|
|
1273 |
#ifdef ATA_HAVE_BBT
|
|
|
1274 |
void ata_bbt_disable()
|
|
|
1275 |
{
|
|
|
1276 |
mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
|
|
1277 |
if (ata_bbt) free(ata_bbt);
|
|
|
1278 |
ata_bbt = NULL;
|
|
|
1279 |
ata_virtual_sectors = ata_total_sectors;
|
|
|
1280 |
mutex_unlock(&ata_mutex);
|
|
|
1281 |
}
|
|
|
1282 |
|
| 920 |
theseven |
1283 |
int ata_bbt_reload()
|
| 643 |
theseven |
1284 |
{
|
|
|
1285 |
mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
|
|
1286 |
ata_bbt_disable();
|
| 965 |
theseven |
1287 |
PASS_RC(ata_power_up(), 1, 0);
|
| 643 |
theseven |
1288 |
uint32_t* buf = (uint32_t*)memalign(0x10, 0x1000);
|
|
|
1289 |
if (buf)
|
|
|
1290 |
{
|
|
|
1291 |
if (IS_ERR(ata_bbt_read_sectors(0, 1, buf)))
|
|
|
1292 |
ata_virtual_sectors = ata_total_sectors;
|
|
|
1293 |
else if (!memcmp(buf, "emBIbbth", 8))
|
|
|
1294 |
{
|
| 965 |
theseven |
1295 |
if (ata_identify_data[82] & BIT(5)) PASS_RC(ata_set_feature(0x02, 0), 1, 1);
|
| 643 |
theseven |
1296 |
ata_virtual_sectors = (((uint64_t)buf[0x1fd]) << 32) | buf[0x1fc];
|
|
|
1297 |
uint32_t count = buf[0x1ff];
|
|
|
1298 |
ata_bbt = (typeof(ata_bbt))memalign(0x10, 0x1000 * count);
|
|
|
1299 |
if (!ata_bbt)
|
|
|
1300 |
{
|
|
|
1301 |
cprintf(CONSOLE_BOOT, "ATA: Failed to allocate memory for BBT! (%d bytes)",
|
|
|
1302 |
0x1000 * count);
|
|
|
1303 |
ata_virtual_sectors = ata_total_sectors;
|
|
|
1304 |
}
|
|
|
1305 |
else
|
|
|
1306 |
{
|
|
|
1307 |
uint32_t i;
|
|
|
1308 |
uint32_t cnt;
|
|
|
1309 |
for (i = 0; i < count; i += cnt)
|
|
|
1310 |
{
|
|
|
1311 |
uint32_t phys = buf[0x200 + i];
|
|
|
1312 |
for (cnt = 1; cnt < count; cnt++)
|
|
|
1313 |
if (buf[0x200 + i + cnt] != phys + cnt)
|
|
|
1314 |
break;
|
|
|
1315 |
if (IS_ERR(ata_bbt_read_sectors(phys, cnt, ata_bbt[i << 6])))
|
|
|
1316 |
{
|
|
|
1317 |
free(ata_bbt);
|
|
|
1318 |
ata_virtual_sectors = ata_total_sectors;
|
|
|
1319 |
break;
|
|
|
1320 |
}
|
|
|
1321 |
}
|
| 814 |
theseven |
1322 |
if (ata_bbt) reownalloc(ata_bbt, KERNEL_OWNER(KERNEL_OWNER_ATA_BBT));
|
| 643 |
theseven |
1323 |
}
|
|
|
1324 |
}
|
|
|
1325 |
else ata_virtual_sectors = ata_total_sectors;
|
|
|
1326 |
free(buf);
|
|
|
1327 |
}
|
|
|
1328 |
else ata_virtual_sectors = ata_total_sectors;
|
|
|
1329 |
mutex_unlock(&ata_mutex);
|
| 965 |
theseven |
1330 |
return 0;
|
| 643 |
theseven |
1331 |
}
|
|
|
1332 |
#endif
|
|
|
1333 |
|
|
|
1334 |
int ata_init(void)
|
|
|
1335 |
{
|
| 968 |
theseven |
1336 |
// Remove this, as it isn't strictly required and causes a race condition.
|
|
|
1337 |
// The clickwheel dispatcher can run ata_lock_exclusive before ata_init is run.
|
|
|
1338 |
// BSS is initialized to zeroes, which are interpreted as an unlocked mutex anyway.
|
|
|
1339 |
//mutex_init(&ata_mutex);
|
| 643 |
theseven |
1340 |
wakeup_init(&ata_wakeup);
|
|
|
1341 |
wakeup_init(&mmc_wakeup);
|
|
|
1342 |
wakeup_init(&mmc_comp_wakeup);
|
|
|
1343 |
ceata = PDAT(11) & BIT(1);
|
|
|
1344 |
ata_powered = false;
|
|
|
1345 |
ata_total_sectors = 0;
|
|
|
1346 |
#ifdef ATA_HAVE_BBT
|
| 920 |
theseven |
1347 |
PASS_RC(ata_bbt_reload(), 0, 0);
|
| 643 |
theseven |
1348 |
#endif
|
|
|
1349 |
thread_create(&ata_thread_handle, "ATA idle monitor", ata_thread, ata_stack,
|
| 835 |
theseven |
1350 |
sizeof(ata_stack), OS_THREAD, 1, true, NULL, NULL, NULL, NULL);
|
| 643 |
theseven |
1351 |
return 0;
|
|
|
1352 |
}
|
|
|
1353 |
|
|
|
1354 |
int ata_num_drives(int first_drive)
|
|
|
1355 |
{
|
|
|
1356 |
/* We don't care which logical drive number(s) we have been assigned */
|
|
|
1357 |
(void)first_drive;
|
|
|
1358 |
|
|
|
1359 |
return 1;
|
|
|
1360 |
}
|
|
|
1361 |
|
|
|
1362 |
void INT_ATA()
|
|
|
1363 |
{
|
|
|
1364 |
uint32_t ata_irq = ATA_IRQ;
|
|
|
1365 |
ATA_IRQ = ata_irq;
|
|
|
1366 |
if (ata_irq & ATA_IRQ_MASK) wakeup_signal(&ata_wakeup);
|
|
|
1367 |
ATA_IRQ_MASK = 0;
|
|
|
1368 |
}
|
|
|
1369 |
|
|
|
1370 |
void INT_MMC()
|
|
|
1371 |
{
|
|
|
1372 |
uint32_t irq = SDCI_IRQ;
|
|
|
1373 |
if (irq & SDCI_IRQ_DAT_DONE_INT) wakeup_signal(&mmc_wakeup);
|
|
|
1374 |
if (irq & SDCI_IRQ_IOCARD_IRQ_INT) wakeup_signal(&mmc_comp_wakeup);
|
|
|
1375 |
SDCI_IRQ = irq;
|
|
|
1376 |
}
|