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