| Index: embios/trunk/target/ipodnano3g/s5l8702.h |
| — | — | @@ -533,6 +533,41 @@ |
| 534 | 534 | #define LCDWDATA (*((uint32_t volatile*)(0x38300040)))
|
| 535 | 535 |
|
| 536 | 536 |
|
| | 537 | +/////ATA/////
|
| | 538 | +#define ATA_CONTROL (*((uint32_t volatile*)(0x38700000)))
|
| | 539 | +#define ATA_STATUS (*((uint32_t volatile*)(0x38700004)))
|
| | 540 | +#define ATA_COMMAND (*((uint32_t volatile*)(0x38700008)))
|
| | 541 | +#define ATA_SWRST (*((uint32_t volatile*)(0x3870000c)))
|
| | 542 | +#define ATA_IRQ (*((uint32_t volatile*)(0x38700010)))
|
| | 543 | +#define ATA_IRQ_MASK (*((uint32_t volatile*)(0x38700014)))
|
| | 544 | +#define ATA_CFG (*((uint32_t volatile*)(0x38700018)))
|
| | 545 | +#define ATA_MDMA_TIME (*((uint32_t volatile*)(0x38700028)))
|
| | 546 | +#define ATA_PIO_TIME (*((uint32_t volatile*)(0x3870002c)))
|
| | 547 | +#define ATA_UDMA_TIME (*((uint32_t volatile*)(0x38700030)))
|
| | 548 | +#define ATA_XFR_NUM (*((uint32_t volatile*)(0x38700034)))
|
| | 549 | +#define ATA_XFR_CNT (*((uint32_t volatile*)(0x38700038)))
|
| | 550 | +#define ATA_TBUF_START (*((void* volatile*)(0x3870003c)))
|
| | 551 | +#define ATA_TBUF_SIZE (*((uint32_t volatile*)(0x38700040)))
|
| | 552 | +#define ATA_SBUF_START (*((void* volatile*)(0x38700044)))
|
| | 553 | +#define ATA_SBUF_SIZE (*((uint32_t volatile*)(0x38700048)))
|
| | 554 | +#define ATA_CADR_TBUF (*((void* volatile*)(0x3870004c)))
|
| | 555 | +#define ATA_CADR_SBUF (*((void* volatile*)(0x38700050)))
|
| | 556 | +#define ATA_PIO_DTR (*((uint32_t volatile*)(0x38700054)))
|
| | 557 | +#define ATA_PIO_FED (*((uint32_t volatile*)(0x38700058)))
|
| | 558 | +#define ATA_PIO_SCR (*((uint32_t volatile*)(0x3870005c)))
|
| | 559 | +#define ATA_PIO_LLR (*((uint32_t volatile*)(0x38700060)))
|
| | 560 | +#define ATA_PIO_LMR (*((uint32_t volatile*)(0x38700064)))
|
| | 561 | +#define ATA_PIO_LHR (*((uint32_t volatile*)(0x38700068)))
|
| | 562 | +#define ATA_PIO_DVR (*((uint32_t volatile*)(0x3870006c)))
|
| | 563 | +#define ATA_PIO_CSD (*((uint32_t volatile*)(0x38700070)))
|
| | 564 | +#define ATA_PIO_DAD (*((uint32_t volatile*)(0x38700074)))
|
| | 565 | +#define ATA_PIO_READY (*((uint32_t volatile*)(0x38700078)))
|
| | 566 | +#define ATA_PIO_RDATA (*((uint32_t volatile*)(0x3870007c)))
|
| | 567 | +#define ATA_BUS_FIFO_STATUS (*((uint32_t volatile*)(0x38700080)))
|
| | 568 | +#define ATA_FIFO_STATUS (*((uint32_t volatile*)(0x38700084)))
|
| | 569 | +#define ATA_DMA_ADDR (*((void* volatile*)(0x38700088)))
|
| | 570 | +
|
| | 571 | +
|
| 537 | 572 | /////CLOCK GATES/////
|
| 538 | 573 | #define CLOCKGATE_USB_1 2
|
| 539 | 574 | #define CLOCKGATE_USB_2 35
|
| — | — | @@ -544,6 +579,7 @@ |
| 545 | 580 | #define IRQ_DMAC(d) 16 + d
|
| 546 | 581 | #define IRQ_DMAC0 16
|
| 547 | 582 | #define IRQ_DMAC1 17
|
| | 583 | +#define IRQ_ATA 29
|
| 548 | 584 |
|
| 549 | 585 |
|
| 550 | 586 | #endif
|
| Index: embios/trunk/target/ipodnano3g/interrupt.c |
| — | — | @@ -78,7 +78,7 @@ |
| 79 | 79 | default_interrupt(INT_IRQ26);
|
| 80 | 80 | default_interrupt(INT_IRQ27);
|
| 81 | 81 | default_interrupt(INT_IRQ28);
|
| 82 | | -default_interrupt(INT_IRQ29);
|
| | 82 | +default_interrupt(INT_ATA);
|
| 83 | 83 | default_interrupt(INT_IRQ30);
|
| 84 | 84 | default_interrupt(INT_IRQ31);
|
| 85 | 85 | default_interrupt(INT_IRQ32);
|
| — | — | @@ -179,7 +179,7 @@ |
| 180 | 180 | INT_IRQ0,INT_IRQ1,INT_IRQ2,INT_IRQ3,INT_IRQ4,INT_IRQ5,INT_IRQ6,INT_IRQ7,
|
| 181 | 181 | INT_TIMER,INT_IRQ9,INT_IRQ10,INT_IRQ11,INT_IRQ12,INT_IRQ13,INT_IRQ14,INT_IRQ15,
|
| 182 | 182 | INT_DMAC0,INT_DMAC1,INT_IRQ18,INT_USB_FUNC,INT_IRQ20,INT_IRQ21,INT_IRQ22,INT_IRQ23,
|
| 183 | | - INT_IRQ24,INT_IRQ25,INT_IRQ26,INT_IRQ27,INT_IRQ28,INT_IRQ29,INT_IRQ30,INT_IRQ31,
|
| | 183 | + INT_IRQ24,INT_IRQ25,INT_IRQ26,INT_IRQ27,INT_IRQ28,INT_ATA,INT_IRQ30,INT_IRQ31,
|
| 184 | 184 | INT_IRQ32,INT_IRQ33,INT_IRQ34,INT_IRQ35,INT_IRQ36,INT_IRQ37,INT_IRQ38,INT_IRQ39,
|
| 185 | 185 | INT_IRQ40,INT_IRQ41,INT_IRQ42,INT_IRQ43,INT_IRQ55,INT_IRQ56,INT_IRQ57,INT_IRQ58,
|
| 186 | 186 | INT_IRQ48,INT_IRQ49,INT_IRQ50,INT_IRQ51,INT_IRQ52,INT_IRQ53,INT_IRQ54,INT_IRQ55,
|
| — | — | @@ -231,6 +231,9 @@ |
| 232 | 232 | VIC0INTENABLE = 1 << IRQ_TIMER;
|
| 233 | 233 | VIC0INTENABLE = 1 << IRQ_DMAC0;
|
| 234 | 234 | VIC0INTENABLE = 1 << IRQ_DMAC1;
|
| | 235 | +#ifdef TARGET_ipodclassic
|
| | 236 | + VIC0INTENABLE = 1 << IRQ_ATA;
|
| | 237 | +#endif
|
| 235 | 238 | }
|
| 236 | 239 |
|
| 237 | 240 | void interrupt_shutdown(void)
|
| Index: embios/trunk/target/ipodclassic/storage_ata.c |
| — | — | @@ -0,0 +1,452 @@ |
| | 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 "timer.h"
|
| | 27 | +#include "../ipodnano3g/s5l8702.h"
|
| | 28 | +
|
| | 29 | +/** static, private data **/
|
| | 30 | +uint16_t ata_identify_data[0x100];
|
| | 31 | +bool ata_lba48;
|
| | 32 | +bool ata_dma;
|
| | 33 | +uint64_t ata_total_sectors;
|
| | 34 | +static struct mutex ata_mutex;
|
| | 35 | +static struct wakeup ata_wakeup;
|
| | 36 | +static uint32_t ata_dma_flags;
|
| | 37 | +static long ata_last_activity_value = -1;
|
| | 38 | +static long ata_sleep_timeout = 20000000;
|
| | 39 | +static uint32_t ata_stack[0x80];
|
| | 40 | +static bool ata_powered;
|
| | 41 | +
|
| | 42 | +
|
| | 43 | +static uint16_t ata_read_cbr(uint32_t volatile* reg)
|
| | 44 | +{
|
| | 45 | + while (!(ATA_PIO_READY & 2)) sleep(0);
|
| | 46 | + volatile uint32_t dummy = *reg;
|
| | 47 | + while (!(ATA_PIO_READY & 1)) sleep(0);
|
| | 48 | + return ATA_PIO_RDATA;
|
| | 49 | +}
|
| | 50 | +
|
| | 51 | +static void ata_write_cbr(uint32_t volatile* reg, uint16_t data)
|
| | 52 | +{
|
| | 53 | + while (!(ATA_PIO_READY & 2)) sleep(0);
|
| | 54 | + *reg = data;
|
| | 55 | +}
|
| | 56 | +
|
| | 57 | +static int ata_wait_for_not_bsy(long timeout)
|
| | 58 | +{
|
| | 59 | + long startusec = USEC_TIMER;
|
| | 60 | + while (true)
|
| | 61 | + {
|
| | 62 | + uint8_t csd = ata_read_cbr(&ATA_PIO_CSD);
|
| | 63 | + if (!(csd & BIT(7))) return 0;
|
| | 64 | + if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(0);
|
| | 65 | + sleep(100);
|
| | 66 | + }
|
| | 67 | +}
|
| | 68 | +
|
| | 69 | +static int ata_wait_for_rdy(long timeout)
|
| | 70 | +{
|
| | 71 | + long startusec = USEC_TIMER;
|
| | 72 | + PASS_RC(ata_wait_for_not_bsy(timeout), 1, 0);
|
| | 73 | + while (true)
|
| | 74 | + {
|
| | 75 | + uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
|
| | 76 | + if (dad & BIT(6)) return 0;
|
| | 77 | + if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(1);
|
| | 78 | + sleep(100);
|
| | 79 | + }
|
| | 80 | +}
|
| | 81 | +
|
| | 82 | +static int ata_wait_for_start_of_transfer(long timeout)
|
| | 83 | +{
|
| | 84 | + long startusec = USEC_TIMER;
|
| | 85 | + PASS_RC(ata_wait_for_not_bsy(timeout), 2, 0);
|
| | 86 | + while (true)
|
| | 87 | + {
|
| | 88 | + uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
|
| | 89 | + if (dad & BIT(0)) RET_ERR(1);
|
| | 90 | + if ((dad & (BIT(7) | BIT(3))) == BIT(3)) return 0;
|
| | 91 | + if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(2);
|
| | 92 | + sleep(100);
|
| | 93 | + }
|
| | 94 | +}
|
| | 95 | +
|
| | 96 | +static int ata_wait_for_end_of_transfer(long timeout)
|
| | 97 | +{
|
| | 98 | + PASS_RC(ata_wait_for_not_bsy(timeout), 2, 0);
|
| | 99 | + uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
|
| | 100 | + if (dad & BIT(0)) RET_ERR(1);
|
| | 101 | + if ((dad & (BIT(3) | BITRANGE(5, 7))) == BIT(6)) return 0;
|
| | 102 | + RET_ERR(2);
|
| | 103 | +}
|
| | 104 | +
|
| | 105 | +int ata_identify(uint16_t* buf)
|
| | 106 | +{
|
| | 107 | + int i;
|
| | 108 | + PASS_RC(ata_wait_for_not_bsy(10000000), 1, 0);
|
| | 109 | + ata_write_cbr(&ATA_PIO_DVR, 0);
|
| | 110 | + ata_write_cbr(&ATA_PIO_CSD, 0xec);
|
| | 111 | + PASS_RC(ata_wait_for_start_of_transfer(10000000), 1, 1);
|
| | 112 | + for (i = 0; i < 0x100; i++)
|
| | 113 | + {
|
| | 114 | + uint16_t word = ata_read_cbr(&ATA_PIO_DTR);
|
| | 115 | + buf[i] = (word >> 8) | (word << 8);
|
| | 116 | + }
|
| | 117 | +}
|
| | 118 | +
|
| | 119 | +void ata_set_active(void)
|
| | 120 | +{
|
| | 121 | + ata_last_activity_value = USEC_TIMER;
|
| | 122 | +}
|
| | 123 | +
|
| | 124 | +int ata_power_up()
|
| | 125 | +{
|
| | 126 | + ata_set_active();
|
| | 127 | + i2c_sendbyte(0, 0xe6, 0x1b, 1);
|
| | 128 | + clockgate_enable(5, true);
|
| | 129 | + ATA_CFG = BIT(0);
|
| | 130 | + sleep(1000);
|
| | 131 | + ATA_CFG = 0;
|
| | 132 | + sleep(6000);
|
| | 133 | + ATA_SWRST = BIT(0);
|
| | 134 | + sleep(500);
|
| | 135 | + ATA_SWRST = 0;
|
| | 136 | + sleep(90000);
|
| | 137 | + ATA_CONTROL = BIT(0);
|
| | 138 | + sleep(200000);
|
| | 139 | + ATA_PIO_TIME = 0x191f7;
|
| | 140 | + ATA_PIO_LHR = 0;
|
| | 141 | + while (!(ATA_PIO_READY & BIT(1))) sleep(100);
|
| | 142 | + PASS_RC(ata_identify(ata_identify_data), 2, 0);
|
| | 143 | + uint32_t piotime = 0x11f3;
|
| | 144 | + uint32_t mdmatime = 0x1c175;
|
| | 145 | + uint32_t udmatime = 0x5071152;
|
| | 146 | + uint32_t param = 0;
|
| | 147 | + ata_dma_flags = 0;
|
| | 148 | + ata_lba48 = ata_identify_data[83] & BIT(10) ? true : false;
|
| | 149 | + if (ata_lba48)
|
| | 150 | + ata_total_sectors = ata_identify_data[100]
|
| | 151 | + | (((uint64_t)ata_identify_data[101]) << 16)
|
| | 152 | + | (((uint64_t)ata_identify_data[102]) << 32)
|
| | 153 | + | (((uint64_t)ata_identify_data[103]) << 48);
|
| | 154 | + else ata_total_sectors = ata_identify_data[60] | (((uint32_t)ata_identify_data[61]) << 16);
|
| | 155 | + if (ata_identify_data[53] & BIT(1))
|
| | 156 | + {
|
| | 157 | + if (ata_identify_data[64] & BIT(1)) piotime = 0x2072;
|
| | 158 | + else if (ata_identify_data[64] & BIT(0)) piotime = 0x7083;
|
| | 159 | + }
|
| | 160 | + if (ata_identify_data[63] & BIT(2))
|
| | 161 | + {
|
| | 162 | + mdmatime = 0x5072;
|
| | 163 | + param = 0x22;
|
| | 164 | + }
|
| | 165 | + else if (ata_identify_data[63] & BIT(1))
|
| | 166 | + {
|
| | 167 | + mdmatime = 0x7083;
|
| | 168 | + param = 0x21;
|
| | 169 | + }
|
| | 170 | + if (ata_identify_data[63] & BITRANGE(0, 2))
|
| | 171 | + {
|
| | 172 | + ata_dma_flags = BIT(3) | BIT(10);
|
| | 173 | + param |= 0x20;
|
| | 174 | + }
|
| | 175 | + if (ata_identify_data[53] & BIT(2))
|
| | 176 | + {
|
| | 177 | + if (ata_identify_data[88] & BIT(4))
|
| | 178 | + {
|
| | 179 | + udmatime = 0x2010a52;
|
| | 180 | + param = 0x44;
|
| | 181 | + }
|
| | 182 | + else if (ata_identify_data[88] & BIT(3))
|
| | 183 | + {
|
| | 184 | + udmatime = 0x2020a52;
|
| | 185 | + param = 0x43;
|
| | 186 | + }
|
| | 187 | + else if (ata_identify_data[88] & BIT(2))
|
| | 188 | + {
|
| | 189 | + udmatime = 0x3030a52;
|
| | 190 | + param = 0x42;
|
| | 191 | + }
|
| | 192 | + else if (ata_identify_data[88] & BIT(1))
|
| | 193 | + {
|
| | 194 | + udmatime = 0x3050a52;
|
| | 195 | + param = 0x41;
|
| | 196 | + }
|
| | 197 | + if (ata_identify_data[88] & BITRANGE(0, 4))
|
| | 198 | + {
|
| | 199 | + ata_dma_flags = BIT(2) | BIT(3) | BIT(9) | BIT(10);
|
| | 200 | + param |= 0x40;
|
| | 201 | + }
|
| | 202 | + }
|
| | 203 | + ata_dma = param ? true : false;
|
| | 204 | + PASS_RC(ata_wait_for_rdy(500000), 2, 1);
|
| | 205 | + ata_write_cbr(&ATA_PIO_DVR, 0);
|
| | 206 | + ata_write_cbr(&ATA_PIO_FED, 3);
|
| | 207 | + ata_write_cbr(&ATA_PIO_SCR, param);
|
| | 208 | + ata_write_cbr(&ATA_PIO_CSD, 0xef);
|
| | 209 | + PASS_RC(ata_wait_for_rdy(500000), 2, 2);
|
| | 210 | + ATA_PIO_TIME = piotime;
|
| | 211 | + ATA_MDMA_TIME = mdmatime;
|
| | 212 | + ATA_UDMA_TIME = udmatime;
|
| | 213 | + ata_powered = true;
|
| | 214 | + ata_set_active();
|
| | 215 | + return 0;
|
| | 216 | +}
|
| | 217 | +
|
| | 218 | +void ata_power_down()
|
| | 219 | +{
|
| | 220 | + ata_powered = false;
|
| | 221 | + ata_wait_for_rdy(1000000);
|
| | 222 | + ata_write_cbr(&ATA_PIO_DVR, 0);
|
| | 223 | + ata_write_cbr(&ATA_PIO_CSD, 0xe0);
|
| | 224 | + ata_wait_for_rdy(1000000);
|
| | 225 | + sleep(30000);
|
| | 226 | + ATA_CONTROL = 0;
|
| | 227 | + while (!(ATA_CONTROL & BIT(1))) sleep(0);
|
| | 228 | + clockgate_enable(5, false);
|
| | 229 | + i2c_sendbyte(0, 0xe6, 0x1b, 0);
|
| | 230 | +}
|
| | 231 | +
|
| | 232 | +int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool write)
|
| | 233 | +{
|
| | 234 | + if (sector + count > ata_total_sectors) RET_ERR(0);
|
| | 235 | + if (!ata_powered) ata_power_up();
|
| | 236 | + ata_set_active();
|
| | 237 | + if (ata_dma && write) clean_dcache();
|
| | 238 | + else if (ata_dma) invalidate_dcache();
|
| | 239 | + ATA_COMMAND = BIT(1);
|
| | 240 | + while (count)
|
| | 241 | + {
|
| | 242 | + uint32_t cnt = MIN(64, count);
|
| | 243 | + PASS_RC(ata_wait_for_rdy(100000), 2, 0);
|
| | 244 | + ata_write_cbr(&ATA_PIO_DVR, 0);
|
| | 245 | + if (ata_lba48)
|
| | 246 | + {
|
| | 247 | + ata_write_cbr(&ATA_PIO_SCR, cnt >> 5);
|
| | 248 | + ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff);
|
| | 249 | + ata_write_cbr(&ATA_PIO_LHR, (sector >> 37) & 0xff);
|
| | 250 | + ata_write_cbr(&ATA_PIO_LMR, (sector >> 29) & 0xff);
|
| | 251 | + ata_write_cbr(&ATA_PIO_LLR, (sector >> 21) & 0xff);
|
| | 252 | + ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff);
|
| | 253 | + ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff);
|
| | 254 | + ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff);
|
| | 255 | + ata_write_cbr(&ATA_PIO_DVR, BIT(6));
|
| | 256 | + if (write) ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0x35 : 0x39);
|
| | 257 | + else ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0x25 : 0x29);
|
| | 258 | + }
|
| | 259 | + else
|
| | 260 | + {
|
| | 261 | + ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff);
|
| | 262 | + ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff);
|
| | 263 | + ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff);
|
| | 264 | + ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff);
|
| | 265 | + ata_write_cbr(&ATA_PIO_DVR, BIT(6) | ((sector >> 21) & 0xf));
|
| | 266 | + if (write) ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0xca : 0x30);
|
| | 267 | + else ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0xc8 : 0xc4);
|
| | 268 | + }
|
| | 269 | + sector += cnt;
|
| | 270 | + count -= cnt;
|
| | 271 | + if (ata_dma)
|
| | 272 | + {
|
| | 273 | + if (write)
|
| | 274 | + {
|
| | 275 | + ATA_SBUF_START = buffer;
|
| | 276 | + ATA_SBUF_SIZE = SECTOR_SIZE * cnt;
|
| | 277 | + ATA_CFG |= BIT(4);
|
| | 278 | + }
|
| | 279 | + else
|
| | 280 | + {
|
| | 281 | + ATA_TBUF_START = buffer;
|
| | 282 | + ATA_TBUF_SIZE = SECTOR_SIZE * cnt;
|
| | 283 | + ATA_CFG &= ~BIT(4);
|
| | 284 | + }
|
| | 285 | + ATA_XFR_NUM = SECTOR_SIZE * cnt - 1;
|
| | 286 | + ATA_CFG |= ata_dma_flags;
|
| | 287 | + ATA_CFG &= ~(BIT(7) | BIT(8));
|
| | 288 | + wakeup_wait(&ata_wakeup, TIMEOUT_NONE);
|
| | 289 | + ATA_IRQ = BITRANGE(0, 4);
|
| | 290 | + ATA_IRQ_MASK = BIT(0);
|
| | 291 | + ATA_COMMAND = BIT(0);
|
| | 292 | + if (wakeup_wait(&ata_wakeup, 3000000) == THREAD_TIMEOUT)
|
| | 293 | + {
|
| | 294 | + ATA_COMMAND = BIT(1);
|
| | 295 | + ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12));
|
| | 296 | + RET_ERR(2);
|
| | 297 | + }
|
| | 298 | + ATA_COMMAND = BIT(1);
|
| | 299 | + ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12));
|
| | 300 | + buffer += SECTOR_SIZE * cnt;
|
| | 301 | + }
|
| | 302 | + else
|
| | 303 | + {
|
| | 304 | + cnt *= SECTOR_SIZE / 512;
|
| | 305 | + while (cnt--)
|
| | 306 | + {
|
| | 307 | + int i;
|
| | 308 | + PASS_RC(ata_wait_for_start_of_transfer(3000000), 2, 1);
|
| | 309 | + if (write)
|
| | 310 | + for (i = 0; i < 256; i++)
|
| | 311 | + ata_write_cbr(&ATA_PIO_DTR, ((uint16_t*)buffer)[i]);
|
| | 312 | + else
|
| | 313 | + for (i = 0; i < 256; i++)
|
| | 314 | + ((uint16_t*)buffer)[i] = ata_read_cbr(&ATA_PIO_DTR);
|
| | 315 | + buffer += 512;
|
| | 316 | + }
|
| | 317 | + }
|
| | 318 | + PASS_RC(ata_wait_for_end_of_transfer(100000), 2, 3);
|
| | 319 | + }
|
| | 320 | + ata_set_active();
|
| | 321 | + return 0;
|
| | 322 | +}
|
| | 323 | +
|
| | 324 | +static void ata_thread(void)
|
| | 325 | +{
|
| | 326 | + while (true)
|
| | 327 | + {
|
| | 328 | + mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
| | 329 | + if (TIME_AFTER(USEC_TIMER, ata_last_activity_value + ata_sleep_timeout) && ata_powered)
|
| | 330 | + ata_power_down();
|
| | 331 | + mutex_unlock(&ata_mutex);
|
| | 332 | + sleep(1000000);
|
| | 333 | + }
|
| | 334 | +}
|
| | 335 | +
|
| | 336 | +/* API Functions */
|
| | 337 | +int ata_soft_reset()
|
| | 338 | +{
|
| | 339 | + mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
| | 340 | + if (!ata_powered) ata_power_up();
|
| | 341 | + ata_set_active();
|
| | 342 | + ata_write_cbr(&ATA_PIO_DAD, BIT(1) | BIT(2));
|
| | 343 | + sleep(10);
|
| | 344 | + ata_write_cbr(&ATA_PIO_DAD, 0);
|
| | 345 | + PASS_RC_MTX(ata_wait_for_rdy(5000000), 0, 0, &ata_mutex);
|
| | 346 | + ata_set_active();
|
| | 347 | + mutex_unlock(&ata_mutex);
|
| | 348 | +}
|
| | 349 | +
|
| | 350 | +int ata_read_sectors(IF_MD2(int drive,) unsigned long start, int incount,
|
| | 351 | + void* inbuf)
|
| | 352 | +{
|
| | 353 | + mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
| | 354 | + int tries = 5;
|
| | 355 | + int rc = -1;
|
| | 356 | + while (--tries && rc)
|
| | 357 | + {
|
| | 358 | + rc = ata_rw_sectors(start, incount, inbuf, false);
|
| | 359 | + if (rc) ata_soft_reset();
|
| | 360 | + }
|
| | 361 | + mutex_unlock(&ata_mutex);
|
| | 362 | + return rc;
|
| | 363 | +}
|
| | 364 | +
|
| | 365 | +int ata_write_sectors(IF_MD2(int drive,) unsigned long start, int count,
|
| | 366 | + const void* outbuf)
|
| | 367 | +{
|
| | 368 | + mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
| | 369 | + int tries = 5;
|
| | 370 | + int rc = -1;
|
| | 371 | + while (--tries && rc)
|
| | 372 | + {
|
| | 373 | + rc = ata_rw_sectors(start, count, (void*)((uint32_t)outbuf), true);
|
| | 374 | + if (rc) ata_soft_reset();
|
| | 375 | + }
|
| | 376 | + mutex_unlock(&ata_mutex);
|
| | 377 | + return rc;
|
| | 378 | +}
|
| | 379 | +
|
| | 380 | +void ata_spindown(int seconds) |
| | 381 | +{ |
| | 382 | + ata_sleep_timeout = seconds * 1000000; |
| | 383 | +} |
| | 384 | +
|
| | 385 | +void ata_sleep(void)
|
| | 386 | +{
|
| | 387 | + call_storage_idle_notifys(false); |
| | 388 | + mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
| | 389 | + ata_power_down();
|
| | 390 | + mutex_unlock(&ata_mutex);
|
| | 391 | +}
|
| | 392 | +
|
| | 393 | +void ata_sleepnow(void)
|
| | 394 | +{
|
| | 395 | + ata_sleep();
|
| | 396 | +}
|
| | 397 | +
|
| | 398 | +void ata_close(void)
|
| | 399 | +{
|
| | 400 | + ata_sleep();
|
| | 401 | +}
|
| | 402 | +
|
| | 403 | +void ata_spin(void)
|
| | 404 | +{
|
| | 405 | + ata_power_up();
|
| | 406 | +}
|
| | 407 | +
|
| | 408 | +void ata_get_info(IF_MD2(int drive,) struct storage_info *info)
|
| | 409 | +{
|
| | 410 | + (*info).sector_size = SECTOR_SIZE;
|
| | 411 | + (*info).num_sectors = ata_total_sectors;
|
| | 412 | + (*info).vendor = "Apple";
|
| | 413 | + (*info).product = "iPod Classic";
|
| | 414 | + (*info).revision = "1.0";
|
| | 415 | +}
|
| | 416 | +
|
| | 417 | +long ata_last_disk_activity(void)
|
| | 418 | +{
|
| | 419 | + return ata_last_activity_value;
|
| | 420 | +}
|
| | 421 | +
|
| | 422 | +int ata_init(void)
|
| | 423 | +{
|
| | 424 | + mutex_init(&ata_mutex);
|
| | 425 | + wakeup_init(&ata_wakeup);
|
| | 426 | + PCON(7) = 0x44444444;
|
| | 427 | + PCON(8) = 0x44444444;
|
| | 428 | + PCON(9) = 0x44444444;
|
| | 429 | + PCON(10) = (PCON(10) & ~0xffff) | 0x4444;
|
| | 430 | + ata_powered = false;
|
| | 431 | + ata_total_sectors = 0;
|
| | 432 | + thread_create("ATA idle monitor", ata_thread, ata_stack,
|
| | 433 | + sizeof(ata_stack), USER_THREAD, 1, true);
|
| | 434 | + return 0;
|
| | 435 | +}
|
| | 436 | +
|
| | 437 | +#ifdef CONFIG_STORAGE_MULTI
|
| | 438 | +int ata_num_drives(int first_drive)
|
| | 439 | +{
|
| | 440 | + /* We don't care which logical drive number(s) we have been assigned */
|
| | 441 | + (void)first_drive;
|
| | 442 | +
|
| | 443 | + return 1;
|
| | 444 | +}
|
| | 445 | +#endif
|
| | 446 | +
|
| | 447 | +void INT_ATA()
|
| | 448 | +{
|
| | 449 | + uint32_t ata_irq = ATA_IRQ;
|
| | 450 | + ATA_IRQ = ata_irq;
|
| | 451 | + if (ata_irq & ATA_IRQ_MASK) wakeup_signal(&ata_wakeup);
|
| | 452 | + ATA_IRQ_MASK = 0;
|
| | 453 | +}
|
| Index: embios/trunk/target/ipodclassic/target.h |
| — | — | @@ -60,12 +60,12 @@ |
| 61 | 61 |
|
| 62 | 62 | #define HAVE_BOOTFLASH
|
| 63 | 63 |
|
| 64 | | -//#define HAVE_STORAGE
|
| 65 | | -//#define HAVE_HDD_STORAGE
|
| 66 | | -//#define HAVE_STORAGE_FLUSH
|
| 67 | | -//#define HAVE_HOTSWAP
|
| 68 | | -//#define CONFIG_STORAGE STORAGE_ATA
|
| 69 | | -//#define SECTOR_SIZE 4096
|
| | 64 | +#define HAVE_STORAGE
|
| | 65 | +#define HAVE_HDD_STORAGE
|
| | 66 | +#define HAVE_STORAGE_FLUSH
|
| | 67 | +#define HAVE_HOTSWAP
|
| | 68 | +#define CONFIG_STORAGE STORAGE_ATA
|
| | 69 | +#define SECTOR_SIZE 4096
|
| 70 | 70 |
|
| 71 | 71 | //#define HAVE_TARGETINIT_LATE
|
| 72 | 72 |
|
| Index: embios/trunk/storage_ata.h |
| — | — | @@ -0,0 +1,54 @@ |
| | 2 | +/***************************************************************************
|
| | 3 | + * __________ __ ___.
|
| | 4 | + * Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
| | 5 | + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
| | 6 | + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
| | 7 | + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
| | 8 | + * \/ \/ \/ \/ \/
|
| | 9 | + * $Id$
|
| | 10 | + *
|
| | 11 | + * Copyright (C) 2002 by Alan Korr
|
| | 12 | + * Copyright (C) 2008 by Frank Gevaerts
|
| | 13 | + *
|
| | 14 | + * This program is free software; you can redistribute it and/or
|
| | 15 | + * modify it under the terms of the GNU General Public License
|
| | 16 | + * as published by the Free Software Foundation; either version 2
|
| | 17 | + * of the License, or (at your option) any later version.
|
| | 18 | + *
|
| | 19 | + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
| | 20 | + * KIND, either express or implied.
|
| | 21 | + *
|
| | 22 | + ****************************************************************************/
|
| | 23 | +#ifndef __STORAGE_ATA_H__
|
| | 24 | +#define __STORAGE_ATA_H__
|
| | 25 | +
|
| | 26 | +#include "global.h"
|
| | 27 | +#include "mv.h" /* for HAVE_MULTIDRIVE or not */
|
| | 28 | +
|
| | 29 | +struct storage_info;
|
| | 30 | +
|
| | 31 | +void ata_spindown(int seconds);
|
| | 32 | +void ata_sleep(void);
|
| | 33 | +void ata_sleepnow(void);
|
| | 34 | +bool ata_disk_is_active(void);
|
| | 35 | +int ata_soft_reset(void);
|
| | 36 | +int ata_init(void);
|
| | 37 | +void ata_close(void);
|
| | 38 | +int ata_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void* buf);
|
| | 39 | +int ata_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf);
|
| | 40 | +#ifdef HAVE_STORAGE_FLUSH
|
| | 41 | +int ata_flush(void);
|
| | 42 | +#endif
|
| | 43 | +void ata_spin(void);
|
| | 44 | +
|
| | 45 | +#ifdef STORAGE_GET_INFO
|
| | 46 | +void ata_get_info(IF_MD2(int drive,) struct storage_info *info);
|
| | 47 | +#endif
|
| | 48 | +
|
| | 49 | +long ata_last_disk_activity(void);
|
| | 50 | +
|
| | 51 | +#ifdef CONFIG_STORAGE_MULTI
|
| | 52 | +int ata_num_drives(int first_drive);
|
| | 53 | +#endif
|
| | 54 | +
|
| | 55 | +#endif |
| \ No newline at end of file |
| Index: embios/trunk/SOURCES |
| — | — | @@ -51,6 +51,10 @@ |
| 52 | 52 | usb/synopsysotg.c
|
| 53 | 53 | #endif
|
| 54 | 54 |
|
| | 55 | +#ifdef TARGET_ipodclassic
|
| | 56 | +target/ipodclassic/storage_ata.c
|
| | 57 | +#endif
|
| | 58 | +
|
| 55 | 59 | #ifdef ARM_ARCH
|
| 56 | 60 | arm/arm-support.S
|
| 57 | 61 | arm/contextswitch.S
|