summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sparmann <theseven@rockbox.org>2011-02-27 22:47:55 +0000
committerMichael Sparmann <theseven@rockbox.org>2011-02-27 22:47:55 +0000
commit30fb680a4dc7b8f1fed9002a47dc2154c7f72d0a (patch)
tree3f685583a92719314cf722fb8a8737947bb968c1
parent59c5e791a13765e75dacc2b97e93450c374b3b14 (diff)
downloadrockbox-30fb680a4dc7b8f1fed9002a47dc2154c7f72d0a.zip
rockbox-30fb680a4dc7b8f1fed9002a47dc2154c7f72d0a.tar.gz
rockbox-30fb680a4dc7b8f1fed9002a47dc2154c7f72d0a.tar.bz2
rockbox-30fb680a4dc7b8f1fed9002a47dc2154c7f72d0a.tar.xz
iPod Classic CE-ATA Support (Part 4 of 4: S5L8702 ATA driver)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29448 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/SOURCES4
-rw-r--r--firmware/export/config/ipod6g.h11
-rw-r--r--firmware/export/s5l8702.h210
-rw-r--r--firmware/target/arm/s5l8700/app.lds2
-rw-r--r--firmware/target/arm/s5l8702/app.lds2
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/ata-ipod6g.c197
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/ata-target.h47
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/mmcdefs-target.h345
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c1142
-rw-r--r--firmware/target/arm/s5l8702/system-s5l8702.c6
10 files changed, 1702 insertions, 264 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index b2b353b..e0186af 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -209,7 +209,7 @@ target/arm/ata-nand-telechips.c
#if (CONFIG_STORAGE & STORAGE_NAND) && (CONFIG_NAND == NAND_SAMSUNG)
target/arm/s5l8700/ata-nand-s5l8700.c
#endif
-#if (CONFIG_STORAGE & STORAGE_ATA)
+#if (CONFIG_STORAGE & STORAGE_ATA) && !defined(IPOD_6G)
drivers/ata.c
#endif
#if (CONFIG_STORAGE & STORAGE_SD)
@@ -1551,6 +1551,7 @@ target/arm/s5l8700/ipodnano2g/adc-nano2g.c
#ifdef IPOD_6G
#ifndef SIMULATOR
target/arm/ipod/button-clickwheel.c
+target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c
target/arm/s5l8702/ipod6g/cscodec-ipod6g.c
target/arm/s5l8702/ipod6g/backlight-ipod6g.c
target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c
@@ -1559,7 +1560,6 @@ target/arm/s5l8702/kernel-s5l8702.c
target/arm/s5l8702/system-s5l8702.c
target/arm/s5l8702/ipod6g/lcd-ipod6g.c
target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S
-target/arm/s5l8702/ipod6g/ata-ipod6g.c
#if 0 //TODO
target/arm/s5l8702/postmortemstub.S
#endif
diff --git a/firmware/export/config/ipod6g.h b/firmware/export/config/ipod6g.h
index 6ab89e5..e783612 100644
--- a/firmware/export/config/ipod6g.h
+++ b/firmware/export/config/ipod6g.h
@@ -185,13 +185,20 @@
/* Define this if you can read an absolute wheel position */
#define HAVE_WHEEL_POSITION
+//#define HAVE_ATA_BBT
+//#define ATA_BBT_PAGES 3072
+
+#define SECTOR_SIZE 4096
+
+#define STORAGE_NEEDS_ALIGN
+
/* define this if the device has larger sectors when accessed via USB */
/* (only relevant in disk.c, fat.c now always supports large virtual sectors) */
-#define MAX_LOG_SECTOR_SIZE 4096
+//#define MAX_LOG_SECTOR_SIZE 4096
/* define this if the hard drive uses large physical sectors (ATA-7 feature) */
/* and doesn't handle them in the drive firmware */
-#define MAX_PHYS_SECTOR_SIZE 4096
+//#define MAX_PHYS_SECTOR_SIZE 4096
/* Define this if you have adjustable CPU frequency */
#define HAVE_ADJUSTABLE_CPU_FREQ
diff --git a/firmware/export/s5l8702.h b/firmware/export/s5l8702.h
index 076e661..ebd3eda 100644
--- a/firmware/export/s5l8702.h
+++ b/firmware/export/s5l8702.h
@@ -568,9 +568,9 @@ struct dma_lli
/////ATA/////
-#define ATA_CCONTROL (*((uint32_t volatile*)(0x38700000)))
-#define ATA_CSTATUS (*((uint32_t volatile*)(0x38700004)))
-#define ATA_CCOMMAND (*((uint32_t volatile*)(0x38700008)))
+#define ATA_CONTROL (*((uint32_t volatile*)(0x38700000)))
+#define ATA_STATUS (*((uint32_t volatile*)(0x38700004)))
+#define ATA_COMMAND (*((uint32_t volatile*)(0x38700008)))
#define ATA_SWRST (*((uint32_t volatile*)(0x3870000c)))
#define ATA_IRQ (*((uint32_t volatile*)(0x38700010)))
#define ATA_IRQ_MASK (*((uint32_t volatile*)(0x38700014)))
@@ -586,15 +586,15 @@ struct dma_lli
#define ATA_SBUF_SIZE (*((uint32_t volatile*)(0x38700048)))
#define ATA_CADR_TBUF (*((void* volatile*)(0x3870004c)))
#define ATA_CADR_SBUF (*((void* volatile*)(0x38700050)))
-#define ATA_DATA ((uint32_t volatile*)(0x38700054))
-#define ATA_ERROR ((uint32_t volatile*)(0x38700058))
-#define ATA_NSECTOR ((uint32_t volatile*)(0x3870005c))
-#define ATA_SECTOR ((uint32_t volatile*)(0x38700060))
-#define ATA_LCYL ((uint32_t volatile*)(0x38700064))
-#define ATA_HCYL ((uint32_t volatile*)(0x38700068))
-#define ATA_SELECT ((uint32_t volatile*)(0x3870006c))
-#define ATA_COMMAND ((uint32_t volatile*)(0x38700070))
-#define ATA_CONTROL ((uint32_t volatile*)(0x38700074))
+#define ATA_PIO_DTR (*((uint32_t volatile*)(0x38700054)))
+#define ATA_PIO_FED (*((uint32_t volatile*)(0x38700058)))
+#define ATA_PIO_SCR (*((uint32_t volatile*)(0x3870005c)))
+#define ATA_PIO_LLR (*((uint32_t volatile*)(0x38700060)))
+#define ATA_PIO_LMR (*((uint32_t volatile*)(0x38700064)))
+#define ATA_PIO_LHR (*((uint32_t volatile*)(0x38700068)))
+#define ATA_PIO_DVR (*((uint32_t volatile*)(0x3870006c)))
+#define ATA_PIO_CSD (*((uint32_t volatile*)(0x38700070)))
+#define ATA_PIO_DAD (*((uint32_t volatile*)(0x38700074)))
#define ATA_PIO_READY (*((uint32_t volatile*)(0x38700078)))
#define ATA_PIO_RDATA (*((uint32_t volatile*)(0x3870007c)))
#define ATA_BUS_FIFO_STATUS (*((uint32_t volatile*)(0x38700080)))
@@ -602,6 +602,190 @@ struct dma_lli
#define ATA_DMA_ADDR (*((void* volatile*)(0x38700088)))
+/////SDCI/////
+#define SDCI_CTRL (*((uint32_t volatile*)(0x38b00000)))
+#define SDCI_DCTRL (*((uint32_t volatile*)(0x38b00004)))
+#define SDCI_CMD (*((uint32_t volatile*)(0x38b00008)))
+#define SDCI_ARGU (*((uint32_t volatile*)(0x38b0000c)))
+#define SDCI_STATE (*((uint32_t volatile*)(0x38b00010)))
+#define SDCI_STAC (*((uint32_t volatile*)(0x38b00014)))
+#define SDCI_DSTA (*((uint32_t volatile*)(0x38b00018)))
+#define SDCI_FSTA (*((uint32_t volatile*)(0x38b0001c)))
+#define SDCI_RESP0 (*((uint32_t volatile*)(0x38b00020)))
+#define SDCI_RESP1 (*((uint32_t volatile*)(0x38b00024)))
+#define SDCI_RESP2 (*((uint32_t volatile*)(0x38b00028)))
+#define SDCI_RESP3 (*((uint32_t volatile*)(0x38b0002c)))
+#define SDCI_CDIV (*((uint32_t volatile*)(0x38b00030)))
+#define SDCI_SDIO_CSR (*((uint32_t volatile*)(0x38b00034)))
+#define SDCI_IRQ (*((uint32_t volatile*)(0x38b00038)))
+#define SDCI_IRQ_MASK (*((uint32_t volatile*)(0x38b0003c)))
+#define SDCI_DATA (*((uint32_t volatile*)(0x38b00040)))
+#define SDCI_DMAADDR (*((void* volatile*)(0x38b00044)))
+#define SDCI_DMASIZE (*((uint32_t volatile*)(0x38b00048)))
+#define SDCI_DMACOUNT (*((uint32_t volatile*)(0x38b0004c)))
+#define SDCI_RESET (*((uint32_t volatile*)(0x38b0006c)))
+
+#define SDCI_CTRL_SDCIEN BIT(0)
+#define SDCI_CTRL_CARD_TYPE_MASK BIT(1)
+#define SDCI_CTRL_CARD_TYPE_SD 0
+#define SDCI_CTRL_CARD_TYPE_MMC BIT(1)
+#define SDCI_CTRL_BUS_WIDTH_MASK BITRANGE(2, 3)
+#define SDCI_CTRL_BUS_WIDTH_1BIT 0
+#define SDCI_CTRL_BUS_WIDTH_4BIT BIT(2)
+#define SDCI_CTRL_BUS_WIDTH_8BIT BIT(3)
+#define SDCI_CTRL_DMA_EN BIT(4)
+#define SDCI_CTRL_L_ENDIAN BIT(5)
+#define SDCI_CTRL_DMA_REQ_CON_MASK BIT(6)
+#define SDCI_CTRL_DMA_REQ_CON_NEMPTY 0
+#define SDCI_CTRL_DMA_REQ_CON_FULL BIT(6)
+#define SDCI_CTRL_CLK_SEL_MASK BIT(7)
+#define SDCI_CTRL_CLK_SEL_PCLK 0
+#define SDCI_CTRL_CLK_SEL_SDCLK BIT(7)
+#define SDCI_CTRL_BIT_8 BIT(8)
+#define SDCI_CTRL_BIT_14 BIT(14)
+
+#define SDCI_DCTRL_TXFIFORST BIT(0)
+#define SDCI_DCTRL_RXFIFORST BIT(1)
+#define SDCI_DCTRL_TRCONT_MASK BITRANGE(4, 5)
+#define SDCI_DCTRL_TRCONT_TX BIT(4)
+#define SDCI_DCTRL_BUS_TEST_MASK BITRANGE(6, 7)
+#define SDCI_DCTRL_BUS_TEST_TX BIT(6)
+#define SDCI_DCTRL_BUS_TEST_RX BIT(7)
+
+#define SDCI_CDIV_CLKDIV_MASK BITRANGE(0, 7)
+#define SDCI_CDIV_CLKDIV(x) ((x) >> 1)
+#define SDCI_CDIV_CLKDIV_2 BIT(0)
+#define SDCI_CDIV_CLKDIV_4 BIT(1)
+#define SDCI_CDIV_CLKDIV_8 BIT(2)
+#define SDCI_CDIV_CLKDIV_16 BIT(3)
+#define SDCI_CDIV_CLKDIV_32 BIT(4)
+#define SDCI_CDIV_CLKDIV_64 BIT(5)
+#define SDCI_CDIV_CLKDIV_128 BIT(6)
+#define SDCI_CDIV_CLKDIV_256 BIT(7)
+
+#define SDCI_CMD_CMD_NUM_MASK BITRANGE(0, 5)
+#define SDCI_CMD_CMD_NUM_SHIFT 0
+#define SDCI_CMD_CMD_NUM(x) (x)
+#define SDCI_CMD_CMD_TYPE_MASK BITRANGE(6, 7)
+#define SDCI_CMD_CMD_TYPE_BC 0
+#define SDCI_CMD_CMD_TYPE_BCR BIT(6)
+#define SDCI_CMD_CMD_TYPE_AC BIT(7)
+#define SDCI_CMD_CMD_TYPE_ADTC (BIT(6) | BIT(7))
+#define SDCI_CMD_CMD_RD_WR BIT(8)
+#define SDCI_CMD_RES_TYPE_MASK BITRANGE(16, 18)
+#define SDCI_CMD_RES_TYPE_NONE 0
+#define SDCI_CMD_RES_TYPE_R1 BIT(16)
+#define SDCI_CMD_RES_TYPE_R2 BIT(17)
+#define SDCI_CMD_RES_TYPE_R3 (BIT(16) | BIT(17))
+#define SDCI_CMD_RES_TYPE_R4 BIT(18)
+#define SDCI_CMD_RES_TYPE_R5 (BIT(16) | BIT(18))
+#define SDCI_CMD_RES_TYPE_R6 (BIT(17) | BIT(18))
+#define SDCI_CMD_RES_BUSY BIT(19)
+#define SDCI_CMD_RES_SIZE_MASK BIT(20)
+#define SDCI_CMD_RES_SIZE_48 0
+#define SDCI_CMD_RES_SIZE_136 BIT(20)
+#define SDCI_CMD_NCR_NID_MASK BIT(21)
+#define SDCI_CMD_NCR_NID_NCR 0
+#define SDCI_CMD_NCR_NID_NID BIT(21)
+#define SDCI_CMD_CMDSTR BIT(31)
+
+#define SDCI_STATE_DAT_STATE_MASK BITRANGE(0, 3)
+#define SDCI_STATE_DAT_STATE_IDLE 0
+#define SDCI_STATE_DAT_STATE_DAT_RCV BIT(0)
+#define SDCI_STATE_DAT_STATE_CRC_RCV BIT(1)
+#define SDCI_STATE_DAT_STATE_DAT_END (BIT(0) | BIT(1))
+#define SDCI_STATE_DAT_STATE_DAT_SET BIT(2)
+#define SDCI_STATE_DAT_STATE_DAT_OUT (BIT(0) | BIT(2))
+#define SDCI_STATE_DAT_STATE_CRC_TIME (BIT(1) | BIT(2))
+#define SDCI_STATE_DAT_STATE_CRC_OUT (BIT(0) | BIT(1) | BIT(2))
+#define SDCI_STATE_DAT_STATE_ENDB_OUT BIT(3)
+#define SDCI_STATE_DAT_STATE_ENDB_STOD (BIT(0) | BIT(3))
+#define SDCI_STATE_DAT_STATE_DAT_CRCR (BIT(1) | BIT(3))
+#define SDCI_STATE_DAT_STATE_CARD_PRG (BIT(0) | BIT(1) | BIT(3))
+#define SDCI_STATE_DAT_STATE_DAT_BUSY (BIT(2) | BIT(3))
+#define SDCI_STATE_CMD_STATE_MASK (BIT(4) | BIT(5) | BIT(6))
+#define SDCI_STATE_CMD_STATE_CMD_IDLE 0
+#define SDCI_STATE_CMD_STATE_CMD_CMDO BIT(4)
+#define SDCI_STATE_CMD_STATE_CMD_CRCO BIT(5)
+#define SDCI_STATE_CMD_STATE_CMD_TOUT (BIT(4) | BIT(5))
+#define SDCI_STATE_CMD_STATE_CMD_RESR BIT(6)
+#define SDCI_STATE_CMD_STATE_CMD_INTV (BIT(4) | BIT(6))
+
+#define SDCI_STAC_CLR_CMDEND BIT(2)
+#define SDCI_STAC_CLR_BIT_3 BIT(3)
+#define SDCI_STAC_CLR_RESEND BIT(4)
+#define SDCI_STAC_CLR_DATEND BIT(6)
+#define SDCI_STAC_CLR_DAT_CRCEND BIT(7)
+#define SDCI_STAC_CLR_CRC_STAEND BIT(8)
+#define SDCI_STAC_CLR_RESTOUTE BIT(15)
+#define SDCI_STAC_CLR_RESENDE BIT(16)
+#define SDCI_STAC_CLR_RESINDE BIT(17)
+#define SDCI_STAC_CLR_RESCRCE BIT(18)
+#define SDCI_STAC_CLR_WR_DATCRCE BIT(22)
+#define SDCI_STAC_CLR_RD_DATCRCE BIT(23)
+#define SDCI_STAC_CLR_RD_DATENDE0 BIT(24)
+#define SDCI_STAC_CLR_RD_DATENDE1 BIT(25)
+#define SDCI_STAC_CLR_RD_DATENDE2 BIT(26)
+#define SDCI_STAC_CLR_RD_DATENDE3 BIT(27)
+#define SDCI_STAC_CLR_RD_DATENDE4 BIT(28)
+#define SDCI_STAC_CLR_RD_DATENDE5 BIT(29)
+#define SDCI_STAC_CLR_RD_DATENDE6 BIT(30)
+#define SDCI_STAC_CLR_RD_DATENDE7 BIT(31)
+
+#define SDCI_DSTA_CMDRDY BIT(0)
+#define SDCI_DSTA_CMDPRO BIT(1)
+#define SDCI_DSTA_CMDEND BIT(2)
+#define SDCI_DSTA_RESPRO BIT(3)
+#define SDCI_DSTA_RESEND BIT(4)
+#define SDCI_DSTA_DATPRO BIT(5)
+#define SDCI_DSTA_DATEND BIT(6)
+#define SDCI_DSTA_DAT_CRCEND BIT(7)
+#define SDCI_DSTA_CRC_STAEND BIT(8)
+#define SDCI_DSTA_DAT_BUSY BIT(9)
+#define SDCI_DSTA_SDCLK_HOLD BIT(12)
+#define SDCI_DSTA_DAT0_STATUS BIT(13)
+#define SDCI_DSTA_WP_DECT_INPUT BIT(14)
+#define SDCI_DSTA_RESTOUTE BIT(15)
+#define SDCI_DSTA_RESENDE BIT(16)
+#define SDCI_DSTA_RESINDE BIT(17)
+#define SDCI_DSTA_RESCRCE BIT(18)
+#define SDCI_DSTA_WR_CRC_STATUS_MASK BITRANGE(19, 21)
+#define SDCI_DSTA_WR_CRC_STATUS_OK BIT(20)
+#define SDCI_DSTA_WR_CRC_STATUS_TXERR (BIT(19) | BIT(21))
+#define SDCI_DSTA_WR_CRC_STATUS_CARDERR (BIT(19) | BIT(20) | BIT(21))
+#define SDCI_DSTA_WR_DATCRCE BIT(22)
+#define SDCI_DSTA_RD_DATCRCE BIT(23)
+#define SDCI_DSTA_RD_DATENDE0 BIT(24)
+#define SDCI_DSTA_RD_DATENDE1 BIT(25)
+#define SDCI_DSTA_RD_DATENDE2 BIT(26)
+#define SDCI_DSTA_RD_DATENDE3 BIT(27)
+#define SDCI_DSTA_RD_DATENDE4 BIT(28)
+#define SDCI_DSTA_RD_DATENDE5 BIT(29)
+#define SDCI_DSTA_RD_DATENDE6 BIT(30)
+#define SDCI_DSTA_RD_DATENDE7 BIT(31)
+
+#define SDCI_FSTA_RX_FIFO_EMPTY BIT(0)
+#define SDCI_FSTA_RX_FIFO_FULL BIT(1)
+#define SDCI_FSTA_TX_FIFO_EMPTY BIT(2)
+#define SDCI_FSTA_TX_FIFO_FULL BIT(3)
+
+#define SDCI_SDIO_CSR_SDIO_RW_EN BIT(0)
+#define SDCI_SDIO_CSR_SDIO_INT_EN BIT(1)
+#define SDCI_SDIO_CSR_SDIO_RW_REQ BIT(2)
+#define SDCI_SDIO_CSR_SDIO_RW_STOP BIT(3)
+#define SDCI_SDIO_CSR_SDIO_INT_PERIOD_MASK BIT(4)
+#define SDCI_SDIO_CSR_SDIO_INT_PERIOD_MORE 0
+#define SDCI_SDIO_CSR_SDIO_INT_PERIOD_XACT BIT(4)
+
+#define SDCI_IRQ_DAT_DONE_INT BIT(0)
+#define SDCI_IRQ_IOCARD_IRQ_INT BIT(1)
+#define SDCI_IRQ_READ_WAIT_INT BIT(2)
+
+#define SDCI_IRQ_MASK_MASK_DAT_DONE_INT BIT(0)
+#define SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT BIT(1)
+#define SDCI_IRQ_MASK_MASK_READ_WAIT_INT BIT(2)
+
+
/////CLICKWHEEL/////
#define WHEEL00 (*((uint32_t volatile*)(0x3C200000)))
#define WHEEL04 (*((uint32_t volatile*)(0x3C200004)))
@@ -638,6 +822,8 @@ struct dma_lli
#define IRQ_DMAC1 17
#define IRQ_WHEEL 23
#define IRQ_ATA 29
+#define IRQ_MMC 44
#endif
+
diff --git a/firmware/target/arm/s5l8700/app.lds b/firmware/target/arm/s5l8700/app.lds
index 2f8ef6a..aa37add 100644
--- a/firmware/target/arm/s5l8700/app.lds
+++ b/firmware/target/arm/s5l8700/app.lds
@@ -100,7 +100,7 @@ SECTIONS
*(.stack)
stackbegin = .;
_stackbegin = .;
- . += 0x4000;
+ . += 0x2000;
stackend = .;
_stackend = .;
_irqstackbegin = .;
diff --git a/firmware/target/arm/s5l8702/app.lds b/firmware/target/arm/s5l8702/app.lds
index fafdea4..ec66e5d 100644
--- a/firmware/target/arm/s5l8702/app.lds
+++ b/firmware/target/arm/s5l8702/app.lds
@@ -95,7 +95,7 @@ SECTIONS
*(.stack)
stackbegin = .;
_stackbegin = .;
- . += 0x4000;
+ . += 0x2000;
stackend = .;
_stackend = .;
_irqstackbegin = .;
diff --git a/firmware/target/arm/s5l8702/ipod6g/ata-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/ata-ipod6g.c
deleted file mode 100644
index f1577ee..0000000
--- a/firmware/target/arm/s5l8702/ipod6g/ata-ipod6g.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id: ata-meg-fx.c 27935 2010-08-28 23:12:11Z funman $
- *
- * Copyright (C) 2011 by Michael Sparmann
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "config.h"
-#include "cpu.h"
-#include "kernel.h"
-#include "thread.h"
-#include "system.h"
-#include "power.h"
-#include "panic.h"
-#include "pmu-target.h"
-#include "ata.h"
-#include "ata-target.h"
-#include "s5l8702.h"
-
-
-static struct wakeup ata_wakeup;
-
-#ifdef HAVE_ATA_DMA
-static uint32_t ata_dma_flags;
-#endif
-
-
-void ata_reset(void)
-{
- ATA_SWRST = 1;
- sleep(HZ / 100);
- ATA_SWRST = 0;
- sleep(HZ / 10);
-}
-
-void ata_enable(bool on)
-{
- if (on)
- {
- PWRCON(0) &= ~(1 << 5);
- ATA_CFG = 0x41;
- sleep(HZ / 100);
- ATA_CFG = 0x40;
- sleep(HZ / 20);
- ata_reset();
- ATA_CCONTROL = 1;
- sleep(HZ / 5);
- ATA_PIO_TIME = 0x191f7;
- *ATA_HCYL = 0;
- while (!(ATA_PIO_READY & 2)) yield();
- }
- else
- {
- ATA_CCONTROL = 0;
- while (!(ATA_CCONTROL & 2)) yield();
- PWRCON(1) |= 1 << 5;
- }
-}
-
-bool ata_is_coldstart(void)
-{
- return false;
-}
-
-void ata_device_init(void)
-{
- VIC0INTENABLE = 1 << IRQ_ATA;
-}
-
-uint16_t ata_read_cbr(uint32_t volatile* reg)
-{
- while (!(ATA_PIO_READY & 2));
- volatile uint32_t __attribute__((unused)) dummy = *reg;
- while (!(ATA_PIO_READY & 1));
- return ATA_PIO_RDATA;
-}
-
-void ata_write_cbr(uint32_t volatile* reg, uint16_t data)
-{
- while (!(ATA_PIO_READY & 2));
- *reg = data;
-}
-
-void ata_set_pio_timings(int mode)
-{
- if (mode >= 4) ATA_PIO_TIME = 0x7083;
- if (mode >= 3) ATA_PIO_TIME = 0x2072;
- else ATA_PIO_TIME = 0x11f3;
-}
-
-#ifdef HAVE_ATA_DMA
-static void ata_set_mdma_timings(unsigned int mode)
-{
- if (mode >= 2) ATA_MDMA_TIME = 0x5072;
- if (mode >= 1) ATA_MDMA_TIME = 0x7083;
- else ATA_MDMA_TIME = 0x1c175;
-}
-
-static void ata_set_udma_timings(unsigned int mode)
-{
- if (mode >= 4) ATA_UDMA_TIME = 0x2010a52;
- if (mode >= 3) ATA_UDMA_TIME = 0x2020a52;
- if (mode >= 2) ATA_UDMA_TIME = 0x3030a52;
- if (mode >= 1) ATA_UDMA_TIME = 0x3050a52;
- else ATA_UDMA_TIME = 0x5071152;
-}
-
-void ata_dma_set_mode(unsigned char mode)
-{
- unsigned int modeidx = mode & 0x07;
- unsigned int dmamode = mode & 0xf8;
-
- if (dmamode == 0x40 && modeidx <= ATA_MAX_UDMA)
- {
- /* Using Ultra DMA */
- ata_set_udma_timings(dmamode);
- ata_dma_flags = 0x60c;
- }
- else if (dmamode == 0x20 && modeidx <= ATA_MAX_MWDMA)
- {
- /* Using Multiword DMA */
- ata_set_mdma_timings(dmamode);
- ata_dma_flags = 0x408;
- }
- else
- {
- /* Don't understand this - force PIO. */
- ata_dma_flags = 0;
- }
-}
-
-bool ata_dma_setup(void *addr, unsigned long bytes, bool write)
-{
- if ((((int)addr) & 0xf) || (((int)bytes) & 0xf) || !ata_dma_flags)
- return false;
-
- if (write) clean_dcache();
- else invalidate_dcache();
- ATA_CCOMMAND = 2;
-
- if (write)
- {
- ATA_SBUF_START = addr;
- ATA_SBUF_SIZE = bytes;
- ATA_CFG |= 0x10;
- }
- else
- {
- ATA_TBUF_START = addr;
- ATA_TBUF_SIZE = bytes;
- ATA_CFG &= ~0x10;
- }
- ATA_XFR_NUM = bytes - 1;
-
- return true;
-}
-
-bool ata_dma_finish(void)
-{
- ATA_CFG |= ata_dma_flags;
- ATA_CFG &= ~0x180;
- wakeup_wait(&ata_wakeup, TIMEOUT_NOBLOCK);
- ATA_IRQ = 0x1f;
- ATA_IRQ_MASK = 1;
- ATA_CCOMMAND = 1;
- if (wakeup_wait(&ata_wakeup, HZ / 2) != OBJ_WAIT_SUCCEEDED)
- {
- ATA_CCOMMAND = 2;
- ATA_CFG &= ~0x100c;
- return false;
- }
- ATA_CCOMMAND = 2;
- ATA_CFG &= ~0x100c;
- return true;
-}
-#endif /* HAVE_ATA_DMA */
-
-void INT_ATA(void)
-{
- uint32_t ata_irq = ATA_IRQ;
- ATA_IRQ = ata_irq;
- if (ata_irq & ATA_IRQ_MASK) wakeup_signal(&ata_wakeup);
- ATA_IRQ_MASK = 0;
-}
diff --git a/firmware/target/arm/s5l8702/ipod6g/ata-target.h b/firmware/target/arm/s5l8702/ipod6g/ata-target.h
deleted file mode 100644
index e2e7bd2..0000000
--- a/firmware/target/arm/s5l8702/ipod6g/ata-target.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id: ata-target.h 25525 2010-04-07 20:01:21Z torne $
- *
- * Copyright (C) 2011 by Michael Sparmann
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#ifndef ATA_TARGET_H
-#define ATA_TARGET_H
-
-#include "inttypes.h"
-#include "s5l8702.h"
-
-#ifdef BOOTLOADER
-#define ATA_DRIVER_CLOSE
-#endif
-
-#define ATA_SWAP_IDENTIFY(word) (swap16(word))
-
-void ata_reset(void);
-void ata_device_init(void);
-bool ata_is_coldstart(void);
-uint16_t ata_read_cbr(uint32_t volatile* reg);
-void ata_write_cbr(uint32_t volatile* reg, uint16_t data);
-
-#define ATA_OUT8(reg, data) ata_write_cbr(reg, data)
-#define ATA_OUT16(reg, data) ata_write_cbr(reg, data)
-#define ATA_IN8(reg) ata_read_cbr(reg)
-#define ATA_IN16(reg) ata_read_cbr(reg)
-
-#define ATA_SET_DEVICE_FEATURES
-void ata_set_pio_timings(int mode);
-
-#endif
diff --git a/firmware/target/arm/s5l8702/ipod6g/mmcdefs-target.h b/firmware/target/arm/s5l8702/ipod6g/mmcdefs-target.h
new file mode 100644
index 0000000..50e5912
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/mmcdefs-target.h
@@ -0,0 +1,345 @@
+//
+//
+// Copyright 2010 TheSeven
+//
+//
+// This file is part of emCORE.
+//
+// emCORE is free software: you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation, either version 2 of the
+// License, or (at your option) any later version.
+//
+// emCORE is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with emCORE. If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#ifndef __CONSTANTS_MMC_H__
+#define __CONSTANTS_MMC_H__
+
+
+#ifndef MIN
+#define MIN(a, b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a, b) (((a)>(b))?(a):(b))
+#endif
+
+#define BIT(x) (1 << (x))
+#define BITRANGE(x, y) ((0xfffffffful >> (31 + (x) - (y))) << (x))
+
+#define ERR_RC(val) (BIT(31) | (val))
+#define IS_ERR(val) (val & BIT(31))
+#define RET_ERR(val) \
+{ \
+ return ERR_RC(val); \
+}
+#define RET_ERR_MTX(val, mutex) \
+{ \
+ mutex_unlock(mutex); \
+ return ERR_RC(val); \
+}
+#define PASS_RC(expr, bits, val) \
+{ \
+ int PASS_RC_rc = (expr); \
+ if (IS_ERR(PASS_RC_rc)) \
+ return ERR_RC((PASS_RC_rc << (bits)) | (val)); \
+}
+#define PASS_RC_MTX(expr, bits, val, mutex) \
+{ \
+ int PASS_RC_MTX_rc = (expr); \
+ if (IS_ERR(PASS_RC_MTX_rc)) \
+ { \
+ mutex_unlock(mutex); \
+ return ERR_RC((PASS_RC_MTX_rc << (bits)) | (val)); \
+ } \
+}
+
+#define TIMEOUT_EXPIRED(a,b) TIME_AFTER(USEC_TIMER,a + b)
+#define udelay(duration) \
+{ \
+ long timestamp = USEC_TIMER; \
+ while (!TIMEOUT_EXPIRED(timestamp, (long)(duration))); \
+}
+
+
+#define MMC_CMD_GO_IDLE_STATE 0
+#define MMC_CMD_SEND_OP_COND 1
+#define MMC_CMD_ALL_SEND_CID 2
+#define MMC_CMD_SET_RELATIVE_ADDR 3
+#define MMC_CMD_SET_DSR 4
+#define MMC_CMD_SLEEP_AWAKE 5
+#define MMC_CMD_SWITCH 6
+#define MMC_CMD_SELECT_CARD 7
+#define MMC_CMD_SEND_EXT_CSD 8
+#define MMC_CMD_SEND_CSD 9
+#define MMC_CMD_SEND_CID 10
+#define MMC_CMD_READ_DAT_UNTIL_STOP 11
+#define MMC_CMD_STOP_TRANSMISSION 12
+#define MMC_CMD_SEND_STATUS 13
+#define MMC_CMD_BUSTEST_R 14
+#define MMC_CMD_GO_INAVTIVE_STATE 15
+#define MMC_CMD_SET_BLOCKLEN 16
+#define MMC_CMD_READ_SINGLE_BLOCK 17
+#define MMC_CMD_READ_MULTIPLE_BLOCK 18
+#define MMC_CMD_BUSTEST_W 19
+#define MMC_CMD_WRITE_DAT_UNTIL_STOP 20
+#define MMC_CMD_SET_BLOCK_COUNT 23
+#define MMC_CMD_WRITE_BLOCK 24
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
+#define MMC_CMD_PROGRAM_CID 26
+#define MMC_CMD_PROGRAM_CSD 27
+#define MMC_CMD_SET_WRITE_PROT 28
+#define MMC_CMD_CLR_WRITE_PROT 29
+#define MMC_CMD_SEND_WRITE_PROT 30
+#define MMC_CMD_ERASE_GROUP_START 35
+#define MMC_CMD_ERASE_GROUP_END 36
+#define MMC_CMD_ERASE 38
+#define MMC_CMD_FAST_IO 39
+#define MMC_CMD_GO_IRQ_STATE 40
+#define MMC_CMD_LOCK_UNLOCK 42
+#define MMC_CMD_APP_CMD 55
+#define MMC_CMD_GEN_CMD 56
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG 60
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK 61
+
+#define MMC_CMD_SEND_OP_COND_OCR_MASK BITRANGE(0, 31)
+#define MMC_CMD_SEND_OP_COND_OCR_SHIFT 0
+#define MMC_CMD_SEND_OP_COND_OCR(x) (x)
+
+#define MMC_CMD_SET_RELATIVE_ADDR_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SET_RELATIVE_ADDR_RCA_SHIFT 16
+#define MMC_CMD_SET_RELATIVE_ADDR_RCA(x) ((x) << 16)
+
+#define MMC_CMD_SET_DSR_DSR_MASK BITRANGE(16, 31)
+#define MMC_CMD_SET_DSR_DSR_SHIFT 16
+#define MMC_CMD_SET_DSR_DSR(x) ((x) << 16)
+
+#define MMC_CMD_SLEEP_AWAKE_SLEEP_AWAKE_MASK BIT(15)
+#define MMC_CMD_SLEEP_AWAKE_SLEEP_AWAKE_AWAKE 0
+#define MMC_CMD_SLEEP_AWAKE_SLEEP_AWAKE_SLEEP BIT(15)
+#define MMC_CMD_SLEEP_AWAKE_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SLEEP_AWAKE_RCA_SHIFT 16
+#define MMC_CMD_SLEEP_AWAKE_RCA(x) ((x) << 16)
+
+#define MMC_CMD_SWITCH_ACCESS_MASK BITRANGE(24, 25);
+#define MMC_CMD_SWITCH_ACCESS_CMDSET 0
+#define MMC_CMD_SWITCH_ACCESS_SET_BITS BIT(24)
+#define MMC_CMD_SWITCH_ACCESS_CLEAR_BITS BIT(25)
+#define MMC_CMD_SWITCH_ACCESS_WRITE_BYTE (BIT(24) | BIT(25))
+#define MMC_CMD_SWTICH_INDEX_MASK BITRANGE(16, 23);
+#define MMC_CMD_SWITCH_INDEX_SHIFT 16
+#define MMC_CMD_SWITCH_INDEX(x) ((x) << 16)
+#define MMC_CMD_SWTICH_VALUE_MASK BITRANGE(8, 15);
+#define MMC_CMD_SWITCH_VALUE_SHIFT 8
+#define MMC_CMD_SWITCH_VALUE(x) ((x) << 8)
+#define MMC_CMD_SWTICH_CMDSET_MASK BITRANGE(0, 2);
+#define MMC_CMD_SWITCH_CMDSET_STANDARD_MMC 0
+
+#define MMC_CMD_SELECT_CARD_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SELECT_CARD_RCA_SHIFT 16
+#define MMC_CMD_SELECT_CARD_RCA(x) ((x) << 16)
+
+#define MMC_CMD_SEND_CSD_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SEND_CSD_RCA_SHIFT 16
+#define MMC_CMD_SEND_CSD_RCA(x) ((x) << 16)
+
+#define MMC_CMD_SEND_CID_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SEND_CID_RCA_SHIFT 16
+#define MMC_CMD_SEND_CID_RCA(x) ((x) << 16)
+
+#define MMC_CMD_READ_DAT_UNTIL_STOP_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_READ_DAT_UNTIL_STOP_ADDRESS_SHIFT 0
+#define MMC_CMD_READ_DAT_UNTIL_STOP_ADDRESS(x) (x)
+
+#define MMC_CMD_SEND_STATUS_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SEND_STATUS_RCA_SHIFT 16
+#define MMC_CMD_SEND_STATUS_RCA(x) ((x) << 16)
+
+#define MMC_CMD_GO_INACTIVE_STATE_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_GO_INACTIVE_STATE_RCA_SHIFT 16
+#define MMC_CMD_GO_INACTIVE_STATE_RCA(x) ((x) << 16)
+
+#define MMC_CMD_SET_BLOCKLEN_LENGTH_MASK BITRANGE(0, 31)
+#define MMC_CMD_SET_BLOCKLEN_LENGTH_SHIFT 0
+#define MMC_CMD_SET_BLOCKLEN_LENGTH(x) (x)
+
+#define MMC_CMD_READ_SINGLE_BLOCK_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_READ_SINGLE_BLOCK_ADDRESS_SHIFT 0
+#define MMC_CMD_READ_SINGLE_BLOCK_ADDRESS(x) (x)
+
+#define MMC_CMD_READ_MULTIPLE_BLOCK_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_READ_MULTIPLE_BLOCK_ADDRESS_SHIFT 0
+#define MMC_CMD_READ_MULTIPLE_BLOCK_ADDRESS(x) (x)
+
+#define MMC_CMD_WRITE_DAT_UNTIL_STOP_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_WRITE_DAT_UNTIL_STOP_ADDRESS_SHIFT 0
+#define MMC_CMD_WRITE_DAT_UNTIL_STOP_ADDRESS(x) (x)
+
+#define MMC_CMD_SET_BLOCK_COUNT_RELIABLE BIT(31)
+#define MMC_CMD_SET_BLOCK_COUNT_COUNT_MASK BITRANGE(0, 15)
+#define MMC_CMD_SET_BLOCK_COUNT_COUNT_SHIFT 0
+#define MMC_CMD_SET_BLOCK_COUNT_COUNT(x) (x)
+
+#define MMC_CMD_WRITE_BLOCK_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_WRITE_BLOCK_ADDRESS_SHIFT 0
+#define MMC_CMD_WRITE_BLOCK_ADDRESS(x) (x)
+
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK_ADDRESS_SHIFT 0
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK_ADDRESS(x) (x)
+
+#define MMC_CMD_SET_WRITE_PROT_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_SET_WRITE_PROT_ADDRESS_SHIFT 0
+#define MMC_CMD_SET_WRITE_PROT_ADDRESS(x) (x)
+
+#define MMC_CMD_CLR_WRITE_PROT_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_CLR_WRITE_PROT_ADDRESS_SHIFT 0
+#define MMC_CMD_CLR_WRITE_PROT_ADDRESS(x) (x)
+
+#define MMC_CMD_SEND_WRITE_PROT_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_SEND_WRITE_PROT_ADDRESS_SHIFT 0
+#define MMC_CMD_SEND_WRITE_PROT_ADDRESS(x) (x)
+
+#define MMC_CMD_ERASE_GROUP_START_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_ERASE_GROUP_START_ADDRESS_SHIFT 0
+#define MMC_CMD_ERASE_GROUP_START_ADDRESS(x) (x)
+
+#define MMC_CMD_ERASE_GROUP_END_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_ERASE_GROUP_END_ADDRESS_SHIFT 0
+#define MMC_CMD_ERASE_GROUP_END_ADDRESS(x) (x)
+
+#define MMC_CMD_FAST_IO_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_FAST_IO_RCA_SHIFT 16
+#define MMC_CMD_FAST_IO_RCA(x) ((x) << 16)
+#define MMC_CMD_FAST_IO_DIRECTION_MASK BIT(15)
+#define MMC_CMD_FAST_IO_DIRECTION_READ 0
+#define MMC_CMD_FAST_IO_DIRECTION_WRITE BIT(15)
+#define MMC_CMD_FAST_IO_ADDRESS_MASK BITRANGE(8, 14)
+#define MMC_CMD_FAST_IO_ADDRESS_SHIFT 8
+#define MMC_CMD_FAST_IO_ADDRESS(x) ((x) << 8)
+#define MMC_CMD_FAST_IO_DATA_MASK BITRANGE(0, 7)
+#define MMC_CMD_FAST_IO_DATA_SHIFT 0
+#define MMC_CMD_FAST_IO_DATA(x) (x)
+
+#define MMC_CMD_APP_CMD_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_APP_CMD_RCA_SHIFT 16
+#define MMC_CMD_APP_CMD_RCA(x) ((x) << 16)
+
+#define MMC_CMD_GEN_CMD_DIRECTION_MASK BIT(0)
+#define MMC_CMD_GEN_CMD_DIRECTION_READ 0
+#define MMC_CMD_GEN_CMD_DIRECTION_WRITE BIT(0)
+
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_MASK BIT(31)
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_READ 0
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_WRITE BIT(31)
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS_MASK BITRANGE(16, 23)
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS_SHIFT 16
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(x) ((x) << 16)
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT_MASK BITRANGE(0, 7)
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT_SHIFT 0
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(x) (x)
+
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_MASK BIT(31)
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_READ 0
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_WRITE BIT(31)
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT_MASK BITRANGE(0, 15)
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT_SHIFT 0
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT(x) (x)
+
+#define MMC_CMD_SWITCH_FIELD_ERASE_GROUP_DEF 175
+#define MMC_CMD_SWITCH_FIELD_BOOT_BUS_WIDTH 177
+#define MMC_CMD_SWITCH_FIELD_BOOT_CONFIG 179
+#define MMC_CMD_SWITCH_FIELD_ERASED_MEM_CONT 181
+#define MMC_CMD_SWITCH_FIELD_BUS_WIDTH 183
+#define MMC_CMD_SWITCH_FIELD_HS_TIMING 185
+#define MMC_CMD_SWITCH_FIELD_POWER_CLASS 187
+#define MMC_CMD_SWITCH_FIELD_CMD_SET_REV 189
+#define MMC_CMD_SWITCH_FIELD_CMD_SET 191
+#define MMC_CMD_SWITCH_FIELD_EXT_CSD_REV 192
+#define MMC_CMD_SWITCH_FIELD_CSD_STRUCTURE 194
+#define MMC_CMD_SWITCH_FIELD_CARD_TYPE 196
+#define MMC_CMD_SWITCH_FIELD_PWR_CL_52_195 200
+#define MMC_CMD_SWITCH_FIELD_PWR_CL_26_195 201
+#define MMC_CMD_SWITCH_FIELD_PWR_CL_52_360 202
+#define MMC_CMD_SWITCH_FIELD_PWR_CL_26_360 203
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_R_4_26 205
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_W_4_26 206
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_R_8_26_4_52 207
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_W_8_26_4_52 208
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_R_8_52 209
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_W_8_52 210
+#define MMC_CMD_SWITCH_FIELD_SEC_COUNT_0 212
+#define MMC_CMD_SWITCH_FIELD_SEC_COUNT_1 213
+#define MMC_CMD_SWITCH_FIELD_SEC_COUNT_2 214
+#define MMC_CMD_SWITCH_FIELD_SEC_COUNT_3 215
+#define MMC_CMD_SWITCH_FIELD_S_A_TIMEOUT 217
+#define MMC_CMD_SWITCH_FIELD_S_C_VCCQ 219
+#define MMC_CMD_SWITCH_FIELD_S_C_VCC 220
+#define MMC_CMD_SWITCH_FIELD_HC_WP_GRP_SIZE 221
+#define MMC_CMD_SWITCH_FIELD_REL_WR_SEC_C 222
+#define MMC_CMD_SWITCH_FIELD_ERASE_TIMEOUT_MULT 223
+#define MMC_CMD_SWITCH_FIELD_HC_ERASE_GRP_SIZE 224
+#define MMC_CMD_SWITCH_FIELD_ACC_SIZE 225
+#define MMC_CMD_SWITCH_FIELD_BOOT_SIZE_MULTI 226
+#define MMC_CMD_SWITCH_FIELD_S_CMD_SET 504
+
+#define MMC_CMD_SWITCH_FIELD_BUS_WIDTH_1BIT 0
+#define MMC_CMD_SWITCH_FIELD_BUS_WIDTH_4BIT 1
+#define MMC_CMD_SWITCH_FIELD_BUS_WIDTH_8BIT 2
+
+#define MMC_CMD_SWITCH_FIELD_HS_TIMING_LOW_SPEED 0
+#define MMC_CMD_SWITCH_FIELD_HS_TIMING_HIGH_SPEED 1
+
+#define MMC_STATUS_APP_CMD BIT(5)
+#define MMC_STATUS_SWITCH_ERROR BIT(7)
+#define MMC_STATUS_READY_FOR_DATA BIT(8)
+#define MMC_STATUS_CURRENT_STATE_MASK BITRANGE(9, 12)
+#define MMC_STATUS_CURRENT_STATE_IDLE 0
+#define MMC_STATUS_CURRENT_STATE_READY BIT(9)
+#define MMC_STATUS_CURRENT_STATE_IDENT BIT(10)
+#define MMC_STATUS_CURRENT_STATE_STBY (BIT(9) | BIT(10))
+#define MMC_STATUS_CURRENT_STATE_TRAN BIT(11)
+#define MMC_STATUS_CURRENT_STATE_DATA (BIT(9) | BIT(11))
+#define MMC_STATUS_CURRENT_STATE_RCV (BIT(10) | BIT(11))
+#define MMC_STATUS_CURRENT_STATE_PRG (BIT(9) | BIT(10) | BIT(11))
+#define MMC_STATUS_CURRENT_STATE_DIS BIT(12)
+#define MMC_STATUS_CURRENT_STATE_BTST (BIT(9) | BIT(12))
+#define MMC_STATUS_CURRENT_STATE_SLP (BIT(10) | BIT(12))
+#define MMC_STATUS_ERASE_RESET BIT(13)
+#define MMC_STATUS_WP_ERASE_SKIP BIT(15)
+#define MMC_STATUS_CID_CSD_OVERWRITE BIT(16)
+#define MMC_STATUS_OVERRUN BIT(17)
+#define MMC_STATUS_UNDERRUN BIT(18)
+#define MMC_STATUS_ERROR BIT(19)
+#define MMC_STATUS_CC_ERROR BIT(20)
+#define MMC_STATUS_CARD_ECC_FAILED BIT(21)
+#define MMC_STATUS_ILLEGAL_COMMAND BIT(22)
+#define MMC_STATUS_COM_CRC_ERROR BIT(23)
+#define MMC_STATUS_LOCK_UNLOCK_FAILED BIT(24)
+#define MMC_STATUS_CARD_IS_LOCKED BIT(25)
+#define MMC_STATUS_WP_VIOLATION BIT(26)
+#define MMC_STATUS_ERASE_PARAM BIT(27)
+#define MMC_STATUS_ERASE_SEQ_ERROR BIT(28)
+#define MMC_STATUS_BLOCK_LEN_ERROR BIT(29)
+#define MMC_STATUS_ADDRESS_MISALIGN BIT(30)
+#define MMC_STATUS_ADDRESS_OUT_OF_RANGE BIT(31)
+
+#define MMC_OCR_170_195 BIT(7)
+#define MMC_OCR_200_260 BITRANGE(8, 14)
+#define MMC_OCR_270_360 BITRANGE(15, 23)
+#define MMC_OCR_ACCESS_MODE_MASK BITRANGE(29, 30)
+#define MMC_OCR_ACCESS_MODE_BYTE 0
+#define MMC_OCR_ACCESS_MODE_SECTOR BIT(30)
+#define MMC_OCR_POWER_UP_DONE BIT(31)
+
+
+#endif
diff --git a/firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c
new file mode 100644
index 0000000..66e02d6
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c
@@ -0,0 +1,1142 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2007 Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+#include "thread.h"
+#include "disk.h"
+#include "storage.h"
+#include "timer.h"
+#include "kernel.h"
+#include "string.h"
+#include "power.h"
+#include "panic.h"
+#include "mmu-arm.h"
+#include "mmcdefs-target.h"
+#include "s5l8702.h"
+#include "led.h"
+#include "ata_idle_notify.h"
+
+
+#ifndef ATA_RETRIES
+#define ATA_RETRIES 3
+#endif
+
+
+#define CEATA_POWERUP_TIMEOUT 20000000
+#define CEATA_COMMAND_TIMEOUT 1000000
+#define CEATA_DAT_NONBUSY_TIMEOUT 5000000
+#define CEATA_MMC_RCA 1
+
+
+/** static, private data **/
+static uint8_t ceata_taskfile[16] __attribute__((aligned(16)));
+uint16_t ata_identify_data[0x100] __attribute__((aligned(16)));
+bool ceata;
+bool ata_lba48;
+bool ata_dma;
+uint64_t ata_total_sectors;
+struct mutex ata_mutex;
+static struct wakeup ata_wakeup;
+static uint32_t ata_dma_flags;
+static long ata_last_activity_value = -1;
+static long ata_sleep_timeout = 20 * HZ;
+static uint32_t ata_stack[(DEFAULT_STACK_SIZE + 0x400) / 4];
+static bool ata_powered;
+static const int ata_retries = ATA_RETRIES;
+static const bool ata_error_srst = true;
+static struct wakeup mmc_wakeup;
+static struct wakeup mmc_comp_wakeup;
+static int spinup_time = 0;
+static int dma_mode = 0;
+
+
+#ifdef ATA_HAVE_BBT
+char ata_bbtbuf[ATA_BBT_PAGES * 64];
+uint16_t (*ata_bbt)[0x20];
+uint64_t ata_virtual_sectors;
+uint32_t ata_last_offset;
+uint64_t ata_last_phys;
+
+int ata_bbt_read_sectors(uint32_t sector, uint32_t count, void* buffer)
+{
+ if (ata_last_phys != sector - 1 && ata_last_phys > sector - 64) ata_soft_reset();
+ int rc = ata_rw_sectors_internal(sector, count, buffer, false);
+ if (rc) rc = ata_rw_sectors_internal(sector, count, buffer, false);
+ ata_last_phys = sector + count - 1;
+ ata_last_offset = 0;
+ if (IS_ERR(rc))
+ panicf("ATA: Error %08X while reading BBT (sector %d, count %d)\n",
+ rc, sector, count);
+ return rc;
+}
+#endif
+
+
+static uint16_t ata_read_cbr(uint32_t volatile* reg)
+{
+ while (!(ATA_PIO_READY & 2));
+ volatile uint32_t dummy __attribute__((unused)) = *reg;
+ while (!(ATA_PIO_READY & 1));
+ return ATA_PIO_RDATA;
+}
+
+static void ata_write_cbr(uint32_t volatile* reg, uint16_t data)
+{
+ while (!(ATA_PIO_READY & 2));
+ *reg = data;
+}
+
+static int ata_wait_for_not_bsy(long timeout)
+{
+ long startusec = USEC_TIMER;
+ while (true)
+ {
+ uint8_t csd = ata_read_cbr(&ATA_PIO_CSD);
+ if (!(csd & BIT(7))) return 0;
+ if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(0);
+ }
+}
+
+static int ata_wait_for_rdy(long timeout)
+{
+ long startusec = USEC_TIMER;
+ PASS_RC(ata_wait_for_not_bsy(timeout), 1, 0);
+ while (true)
+ {
+ uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
+ if (dad & BIT(6)) return 0;
+ if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(1);
+ }
+}
+
+static int ata_wait_for_start_of_transfer(long timeout)
+{
+ long startusec = USEC_TIMER;
+ PASS_RC(ata_wait_for_not_bsy(timeout), 2, 0);
+ while (true)
+ {
+ uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
+ if (dad & BIT(0)) RET_ERR(1);
+ if ((dad & (BIT(7) | BIT(3))) == BIT(3)) return 0;
+ if (TIMEOUT_EXPIRED(startusec, timeout)) RET_ERR(2);
+ }
+}
+
+static int ata_wait_for_end_of_transfer(long timeout)
+{
+ PASS_RC(ata_wait_for_not_bsy(timeout), 2, 0);
+ uint8_t dad = ata_read_cbr(&ATA_PIO_DAD);
+ if (dad & BIT(0)) RET_ERR(1);
+ if ((dad & (BIT(3) | BITRANGE(5, 7))) == BIT(6)) return 0;
+ RET_ERR(2);
+}
+
+int mmc_dsta_check_command_success(bool disable_crc)
+{
+ int rc = 0;
+ uint32_t dsta = SDCI_DSTA;
+ if (dsta & SDCI_DSTA_RESTOUTE) rc |= 1;
+ if (dsta & SDCI_DSTA_RESENDE) rc |= 2;
+ if (dsta & SDCI_DSTA_RESINDE) rc |= 4;
+ if (!disable_crc)
+ if (dsta & SDCI_DSTA_RESCRCE)
+ rc |= 8;
+ if (rc) RET_ERR(rc);
+ return 0;
+}
+
+bool mmc_send_command(uint32_t cmd, uint32_t arg, uint32_t* result, int timeout)
+{
+ long starttime = USEC_TIMER;
+ while ((SDCI_STATE & SDCI_STATE_CMD_STATE_MASK) != SDCI_STATE_CMD_STATE_CMD_IDLE)
+ {
+ if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(0);
+ yield();
+ }
+ SDCI_STAC = SDCI_STAC_CLR_CMDEND | SDCI_STAC_CLR_BIT_3
+ | SDCI_STAC_CLR_RESEND | SDCI_STAC_CLR_DATEND
+ | SDCI_STAC_CLR_DAT_CRCEND | SDCI_STAC_CLR_CRC_STAEND
+ | SDCI_STAC_CLR_RESTOUTE | SDCI_STAC_CLR_RESENDE
+ | SDCI_STAC_CLR_RESINDE | SDCI_STAC_CLR_RESCRCE
+ | SDCI_STAC_CLR_WR_DATCRCE | SDCI_STAC_CLR_RD_DATCRCE
+ | SDCI_STAC_CLR_RD_DATENDE0 | SDCI_STAC_CLR_RD_DATENDE1
+ | SDCI_STAC_CLR_RD_DATENDE2 | SDCI_STAC_CLR_RD_DATENDE3
+ | SDCI_STAC_CLR_RD_DATENDE4 | SDCI_STAC_CLR_RD_DATENDE5
+ | SDCI_STAC_CLR_RD_DATENDE6 | SDCI_STAC_CLR_RD_DATENDE7;
+ SDCI_ARGU = arg;
+ SDCI_CMD = cmd;
+ if (!(SDCI_DSTA & SDCI_DSTA_CMDRDY)) RET_ERR(1);
+ SDCI_CMD = cmd | SDCI_CMD_CMDSTR;
+ long sleepbase = USEC_TIMER;
+ while (TIMEOUT_EXPIRED(sleepbase, 1000)) yield();
+ while (!(SDCI_DSTA & SDCI_DSTA_CMDEND))
+ {
+ if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(2);
+ yield();
+ }
+ if ((cmd & SDCI_CMD_RES_TYPE_MASK) != SDCI_CMD_RES_TYPE_NONE)
+ {
+ while (!(SDCI_DSTA & SDCI_DSTA_RESEND))
+ {
+ if (TIMEOUT_EXPIRED(starttime, timeout)) RET_ERR(3);
+ yield();
+ }
+ if (cmd & SDCI_CMD_RES_BUSY)
+ while (SDCI_DSTA & SDCI_DSTA_DAT_BUSY)
+ {
+ if (TIMEOUT_EXPIRED(starttime, CEATA_DAT_NONBUSY_TIMEOUT)) RET_ERR(4);
+ yield();
+ }
+ }
+ bool nocrc = (cmd & SDCI_CMD_RES_SIZE_MASK) == SDCI_CMD_RES_SIZE_136;
+ PASS_RC(mmc_dsta_check_command_success(nocrc), 3, 5);
+ if (result) *result = SDCI_RESP0;
+ return 0;
+}
+
+int mmc_get_card_status(uint32_t* result)
+{
+ return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_STATUS)
+ | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+ MMC_CMD_SEND_STATUS_RCA(CEATA_MMC_RCA), result, CEATA_COMMAND_TIMEOUT);
+}
+
+int mmc_init(void)
+{
+ sleep(HZ / 10);
+ PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_GO_IDLE_STATE)
+ | SDCI_CMD_CMD_TYPE_BC | SDCI_CMD_RES_TYPE_NONE
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID,
+ 0, NULL, CEATA_COMMAND_TIMEOUT), 3, 0);
+ long startusec = USEC_TIMER;
+ uint32_t result;
+ do
+ {
+ if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(1);
+ sleep(HZ / 100);
+ PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_OP_COND)
+ | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R3
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID,
+ MMC_CMD_SEND_OP_COND_OCR(MMC_OCR_270_360),
+ NULL, CEATA_COMMAND_TIMEOUT), 3, 2);
+ result = SDCI_RESP0;
+ }
+ while (!(result & MMC_OCR_POWER_UP_DONE));
+ PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_ALL_SEND_CID)
+ | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R2
+ | SDCI_CMD_RES_SIZE_136 | SDCI_CMD_NCR_NID_NID,
+ 0, NULL, CEATA_COMMAND_TIMEOUT), 3, 3);
+ PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SET_RELATIVE_ADDR)
+ | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R1
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+ MMC_CMD_SET_RELATIVE_ADDR_RCA(CEATA_MMC_RCA),
+ NULL, CEATA_COMMAND_TIMEOUT), 3, 4);
+ PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SELECT_CARD)
+ | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+ MMC_CMD_SELECT_CARD_RCA(CEATA_MMC_RCA),
+ NULL, CEATA_COMMAND_TIMEOUT), 3, 5);
+ PASS_RC(mmc_get_card_status(&result), 3, 6);
+ if ((result & MMC_STATUS_CURRENT_STATE_MASK) != MMC_STATUS_CURRENT_STATE_TRAN) RET_ERR(7);
+ return 0;
+}
+
+int mmc_fastio_write(uint32_t addr, uint32_t data)
+{
+ return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO)
+ | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+ MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_WRITE
+ | MMC_CMD_FAST_IO_ADDRESS(addr) | MMC_CMD_FAST_IO_DATA(data),
+ NULL, CEATA_COMMAND_TIMEOUT);
+}
+
+int mmc_fastio_read(uint32_t addr, uint32_t* data)
+{
+ return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO)
+ | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+ MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_READ
+ | MMC_CMD_FAST_IO_ADDRESS(addr), data, CEATA_COMMAND_TIMEOUT);
+}
+
+int ceata_soft_reset(void)
+{
+ PASS_RC(mmc_fastio_write(6, 4), 2, 0);
+ sleep(HZ / 100);
+ PASS_RC(mmc_fastio_write(6, 0), 2, 1);
+ sleep(HZ / 100);
+ long startusec = USEC_TIMER;
+ uint32_t status;
+ do
+ {
+ PASS_RC(mmc_fastio_read(0xf, &status), 2, 2);
+ if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(3);
+ sleep(HZ / 100);
+ }
+ while (status & 0x80);
+ return 0;
+}
+
+int mmc_dsta_check_data_success(void)
+{
+ int rc = 0;
+ uint32_t dsta = SDCI_DSTA;
+ if (dsta & (SDCI_DSTA_WR_DATCRCE | SDCI_DSTA_RD_DATCRCE))
+ {
+ if (dsta & SDCI_DSTA_WR_DATCRCE) rc |= 1;
+ if (dsta & SDCI_DSTA_RD_DATCRCE) rc |= 2;
+ if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_TXERR) rc |= 4;
+ else if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_CARDERR) rc |= 8;
+ }
+ if (dsta & (SDCI_DSTA_RD_DATENDE0 | SDCI_DSTA_RD_DATENDE1 | SDCI_DSTA_RD_DATENDE2
+ | SDCI_DSTA_RD_DATENDE3 | SDCI_DSTA_RD_DATENDE4 | SDCI_DSTA_RD_DATENDE5
+ | SDCI_DSTA_RD_DATENDE6 | SDCI_DSTA_RD_DATENDE7))
+ rc |= 16;
+ if (rc) RET_ERR(rc);
+ return 0;
+}
+
+void mmc_discard_irq(void)
+{
+ SDCI_IRQ = SDCI_IRQ_DAT_DONE_INT | SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT
+ | SDCI_IRQ_MASK_MASK_READ_WAIT_INT;
+ wakeup_wait(&mmc_wakeup, 0);
+}
+
+int ceata_read_multiple_register(uint32_t addr, void* dest, uint32_t size)
+{
+ if (size > 0x10) RET_ERR(0);
+ mmc_discard_irq();
+ SDCI_DMASIZE = size;
+ SDCI_DMACOUNT = 1;
+ SDCI_DMAADDR = dest;
+ SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST;
+ invalidate_dcache();
+ PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG)
+ | SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_RES_TYPE_R1
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+ MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_READ
+ | MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc)
+ | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc),
+ NULL, CEATA_COMMAND_TIMEOUT), 2, 1);
+ if (wakeup_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) == OBJ_WAIT_TIMEDOUT) RET_ERR(2);
+ PASS_RC(mmc_dsta_check_data_success(), 2, 3);
+ return 0;
+}
+
+int ceata_write_multiple_register(uint32_t addr, void* dest, uint32_t size)
+{
+ uint32_t i;
+ if (size > 0x10) RET_ERR(0);
+ mmc_discard_irq();
+ SDCI_DMASIZE = size;
+ SDCI_DMACOUNT = 0;
+ SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST;
+ PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG)
+ | SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR
+ | SDCI_CMD_RES_BUSY | SDCI_CMD_RES_TYPE_R1
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+ MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_WRITE
+ | MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc)
+ | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc),
+ NULL, CEATA_COMMAND_TIMEOUT), 3, 1);
+ SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX;
+ for (i = 0; i < size / 4; i++) SDCI_DATA = ((uint32_t*)dest)[i];
+ long startusec = USEC_TIMER;
+ if (wakeup_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) == OBJ_WAIT_TIMEDOUT) RET_ERR(2);
+ while ((SDCI_STATE & SDCI_STATE_DAT_STATE_MASK) != SDCI_STATE_DAT_STATE_IDLE)
+ {
+ if (TIMEOUT_EXPIRED(startusec, CEATA_COMMAND_TIMEOUT)) RET_ERR(3);
+ yield();
+ }
+ PASS_RC(mmc_dsta_check_data_success(), 3, 4);
+ return 0;
+}
+
+int ceata_init(int buswidth)
+{
+ uint32_t result;
+ PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SWITCH) | SDCI_CMD_RES_BUSY
+ | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+ MMC_CMD_SWITCH_ACCESS_WRITE_BYTE
+ | MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_HS_TIMING)
+ | MMC_CMD_SWITCH_VALUE(MMC_CMD_SWITCH_FIELD_HS_TIMING_HIGH_SPEED),
+ &result, CEATA_COMMAND_TIMEOUT), 3, 0);
+ if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(1);
+ if (buswidth > 1)
+ {
+ int setting;
+ if (buswidth == 4) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_4BIT;
+ else if (buswidth == 8) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_8BIT;
+ else setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_1BIT;
+ PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SWITCH) | SDCI_CMD_RES_BUSY
+ | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+ MMC_CMD_SWITCH_ACCESS_WRITE_BYTE
+ | MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_BUS_WIDTH)
+ | MMC_CMD_SWITCH_VALUE(setting),
+ &result, CEATA_COMMAND_TIMEOUT), 3, 2);
+ if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(3);
+ if (buswidth == 4)
+ SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_4BIT;
+ else if (buswidth == 8)
+ SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_8BIT;
+ }
+ PASS_RC(ceata_soft_reset(), 3, 4);
+ PASS_RC(ceata_read_multiple_register(0, ceata_taskfile, 0x10), 3, 5);
+ if (ceata_taskfile[0xc] != 0xce || ceata_taskfile[0xd] != 0xaa) RET_ERR(6);
+ PASS_RC(mmc_fastio_write(6, 0), 3, 7);
+ return 0;
+}
+
+int ceata_check_error(void)
+{
+ uint32_t status, error;
+ PASS_RC(mmc_fastio_read(0xf, &status), 2, 0);
+ if (status & 1)
+ {
+ PASS_RC(mmc_fastio_read(0x9, &error), 2, 1);
+ RET_ERR((error << 2) | 2);
+ }
+ return 0;
+}
+
+int ceata_wait_idle(void)
+{
+ long startusec = USEC_TIMER;
+ while (true)
+ {
+ uint32_t status;
+ PASS_RC(mmc_fastio_read(0xf, &status), 1, 0);
+ if (!(status & 0x88)) return 0;
+ if (TIMEOUT_EXPIRED(startusec, CEATA_DAT_NONBUSY_TIMEOUT)) RET_ERR(1);
+ sleep(HZ / 20);
+ }
+}
+
+int ceata_cancel_command(void)
+{
+ *((uint32_t volatile*)0x3cf00200) = 0x9000e;
+ udelay(1);
+ *((uint32_t volatile*)0x3cf00200) = 0x9000f;
+ udelay(1);
+ *((uint32_t volatile*)0x3cf00200) = 0x90003;
+ udelay(1);
+ PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_STOP_TRANSMISSION)
+ | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+ 0, NULL, CEATA_COMMAND_TIMEOUT), 1, 0);
+ PASS_RC(ceata_wait_idle(), 1, 1);
+ return 0;
+}
+
+int ceata_rw_multiple_block(bool write, void* buf, uint32_t count, long timeout)
+{
+ mmc_discard_irq();
+ uint32_t responsetype;
+ uint32_t cmdtype;
+ uint32_t direction;
+ if (write)
+ {
+ cmdtype = SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR;
+ responsetype = SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY;
+ direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_WRITE;
+ }
+ else
+ {
+ cmdtype = SDCI_CMD_CMD_TYPE_ADTC;
+ responsetype = SDCI_CMD_RES_TYPE_R1;
+ direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_READ;
+ }
+ SDCI_DMASIZE = 0x200;
+ SDCI_DMAADDR = buf;
+ SDCI_DMACOUNT = count;
+ SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST;
+ invalidate_dcache();
+ PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_BLOCK)
+ | SDCI_CMD_CMD_TYPE_ADTC | cmdtype | responsetype
+ | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+ direction | MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT(count),
+ NULL, CEATA_COMMAND_TIMEOUT), 4, 0);
+ if (write) SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX;
+ if (wakeup_wait(&mmc_wakeup, timeout) == OBJ_WAIT_TIMEDOUT)
+ {
+ PASS_RC(ceata_cancel_command(), 4, 1);
+ RET_ERR(2);
+ }
+ PASS_RC(mmc_dsta_check_data_success(), 4, 3);
+ if (wakeup_wait(&mmc_comp_wakeup, timeout) == OBJ_WAIT_TIMEDOUT)
+ {
+ PASS_RC(ceata_cancel_command(), 4, 4);
+ RET_ERR(4);
+ }
+ PASS_RC(ceata_check_error(), 4, 5);
+ return 0;
+}
+
+int ata_identify(uint16_t* buf)
+{
+ int i;
+ if (ceata)
+ {
+ memset(ceata_taskfile, 0, 16);
+ ceata_taskfile[0xf] = 0xec;
+ PASS_RC(ceata_wait_idle(), 2, 0);
+ PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1);
+ PASS_RC(ceata_rw_multiple_block(false, buf, 1, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 2, 2);
+ }
+ else
+ {
+ PASS_RC(ata_wait_for_not_bsy(10000000), 1, 0);
+ ata_write_cbr(&ATA_PIO_DVR, 0);
+ ata_write_cbr(&ATA_PIO_CSD, 0xec);
+ PASS_RC(ata_wait_for_start_of_transfer(10000000), 1, 1);
+ for (i = 0; i < 0x100; i++)
+ {
+ uint16_t word = ata_read_cbr(&ATA_PIO_DTR);
+ buf[i] = (word >> 8) | (word << 8);
+ }
+ }
+ return 0;
+}
+
+void ata_set_active(void)
+{
+ ata_last_activity_value = current_tick;
+}
+
+bool ata_disk_is_active(void)
+{
+ return ata_powered;
+}
+
+int ata_set_feature(uint32_t feature, uint32_t param)
+{
+ PASS_RC(ata_wait_for_rdy(500000), 1, 0);
+ ata_write_cbr(&ATA_PIO_DVR, 0);
+ ata_write_cbr(&ATA_PIO_FED, 3);
+ ata_write_cbr(&ATA_PIO_SCR, param);
+ ata_write_cbr(&ATA_PIO_CSD, feature);
+ PASS_RC(ata_wait_for_rdy(500000), 1, 1);
+ return 0;
+}
+
+int ata_power_up(void)
+{
+ ata_set_active();
+ if (ata_powered) return 0;
+ ide_power_enable(true);
+ long spinup_start = current_tick;
+ if (ceata)
+ {
+ PWRCON(0) &= ~(1 << 9);
+ SDCI_RESET = 0xa5;
+ sleep(HZ / 100);
+ *((uint32_t volatile*)0x3cf00380) = 0;
+ *((uint32_t volatile*)0x3cf0010c) = 0xff;
+ SDCI_CTRL = SDCI_CTRL_SDCIEN | SDCI_CTRL_CLK_SEL_SDCLK
+ | SDCI_CTRL_BIT_8 | SDCI_CTRL_BIT_14;
+ SDCI_CDIV = SDCI_CDIV_CLKDIV(260);
+ *((uint32_t volatile*)0x3cf00200) = 0xb000f;
+ SDCI_IRQ_MASK = SDCI_IRQ_MASK_MASK_DAT_DONE_INT | SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT;
+ PASS_RC(mmc_init(), 2, 0);
+ SDCI_CDIV = SDCI_CDIV_CLKDIV(4);
+ sleep(HZ / 100);
+ PASS_RC(ceata_init(8), 2, 1);
+ PASS_RC(ata_identify(ata_identify_data), 2, 2);
+ dma_mode = 0x44;
+ }
+ else
+ {
+ PWRCON(0) &= ~(1 << 5);
+ ATA_CFG = BIT(0);
+ sleep(HZ / 100);
+ ATA_CFG = 0;
+ sleep(HZ / 100);
+ ATA_SWRST = BIT(0);
+ sleep(HZ / 100);
+ ATA_SWRST = 0;
+ sleep(HZ / 10);
+ ATA_CONTROL = BIT(0);
+ sleep(HZ / 5);
+ ATA_PIO_TIME = 0x191f7;
+ ATA_PIO_LHR = 0;
+ while (!(ATA_PIO_READY & BIT(1))) yield();
+ PASS_RC(ata_identify(ata_identify_data), 2, 0);
+ uint32_t piotime = 0x11f3;
+ uint32_t mdmatime = 0x1c175;
+ uint32_t udmatime = 0x5071152;
+ uint32_t param = 0;
+ ata_dma_flags = 0;
+ ata_lba48 = ata_identify_data[83] & BIT(10) ? true : false;
+ if (ata_identify_data[53] & BIT(1))
+ {
+ if (ata_identify_data[64] & BIT(1)) piotime = 0x2072;
+ else if (ata_identify_data[64] & BIT(0)) piotime = 0x7083;
+ }
+ if (ata_identify_data[63] & BIT(2))
+ {
+ mdmatime = 0x5072;
+ param = 0x22;
+ }
+ else if (ata_identify_data[63] & BIT(1))
+ {
+ mdmatime = 0x7083;
+ param = 0x21;
+ }
+ if (ata_identify_data[63] & BITRANGE(0, 2))
+ {
+ ata_dma_flags = BIT(3) | BIT(10);
+ param |= 0x20;
+ }
+ if (ata_identify_data[53] & BIT(2))
+ {
+ if (ata_identify_data[88] & BIT(4))
+ {
+ udmatime = 0x2010a52;
+ param = 0x44;
+ }
+ else if (ata_identify_data[88] & BIT(3))
+ {
+ udmatime = 0x2020a52;
+ param = 0x43;
+ }
+ else if (ata_identify_data[88] & BIT(2))
+ {
+ udmatime = 0x3030a52;
+ param = 0x42;
+ }
+ else if (ata_identify_data[88] & BIT(1))
+ {
+ udmatime = 0x3050a52;
+ param = 0x41;
+ }
+ if (ata_identify_data[88] & BITRANGE(0, 4))
+ {
+ ata_dma_flags = BIT(2) | BIT(3) | BIT(9) | BIT(10);
+ param |= 0x40;
+ }
+ }
+ ata_dma = param ? true : false;
+ dma_mode = param;
+ PASS_RC(ata_set_feature(0xef, param), 2, 1);
+ if (ata_identify_data[82] & BIT(5)) PASS_RC(ata_set_feature(0x02, 0), 2, 2);
+ if (ata_identify_data[82] & BIT(6)) PASS_RC(ata_set_feature(0x55, 0), 2, 3);
+ ATA_PIO_TIME = piotime;
+ ATA_MDMA_TIME = mdmatime;
+ ATA_UDMA_TIME = udmatime;
+ }
+ spinup_time = current_tick - spinup_start;
+ if (ata_lba48)
+ ata_total_sectors = ata_identify_data[100]
+ | (((uint64_t)ata_identify_data[101]) << 16)
+ | (((uint64_t)ata_identify_data[102]) << 32)
+ | (((uint64_t)ata_identify_data[103]) << 48);
+ else ata_total_sectors = ata_identify_data[60] | (((uint32_t)ata_identify_data[61]) << 16);
+ ata_total_sectors >>= 3;
+ ata_powered = true;
+ ata_set_active();
+ return 0;
+}
+
+void ata_power_down(void)
+{
+ if (!ata_powered) return;
+ ata_powered = false;
+ if (ceata)
+ {
+ memset(ceata_taskfile, 0, 16);
+ ceata_taskfile[0xf] = 0xe0;
+ ceata_wait_idle();
+ ceata_write_multiple_register(0, ceata_taskfile, 16);
+ sleep(HZ);
+ PWRCON(0) |= (1 << 9);
+ }
+ else
+ {
+ ata_wait_for_rdy(1000000);
+ ata_write_cbr(&ATA_PIO_DVR, 0);
+ ata_write_cbr(&ATA_PIO_CSD, 0xe0);
+ ata_wait_for_rdy(1000000);
+ sleep(HZ / 30);
+ ATA_CONTROL = 0;
+ while (!(ATA_CONTROL & BIT(1))) yield();
+ PWRCON(0) |= (1 << 5);
+ }
+ ide_power_enable(false);
+}
+
+int ata_rw_chunk_internal(uint64_t sector, uint32_t cnt, void* buffer, bool write)
+{
+ if (ceata)
+ {
+ memset(ceata_taskfile, 0, 16);
+ ceata_taskfile[0x2] = cnt >> 5;
+ ceata_taskfile[0x3] = sector >> 21;
+ ceata_taskfile[0x4] = sector >> 29;
+ ceata_taskfile[0x5] = sector >> 37;
+ ceata_taskfile[0xa] = cnt << 3;
+ ceata_taskfile[0xb] = sector << 3;
+ ceata_taskfile[0xc] = sector >> 5;
+ ceata_taskfile[0xd] = sector >> 13;
+ ceata_taskfile[0xf] = write ? 0x35 : 0x25;
+ PASS_RC(ceata_wait_idle(), 2, 0);
+ PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1);
+ PASS_RC(ceata_rw_multiple_block(write, buffer, cnt << 3, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 2, 2);
+ }
+ else
+ {
+ PASS_RC(ata_wait_for_rdy(100000), 2, 0);
+ ata_write_cbr(&ATA_PIO_DVR, 0);
+ if (ata_lba48)
+ {
+ ata_write_cbr(&ATA_PIO_SCR, cnt >> 5);
+ ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff);
+ ata_write_cbr(&ATA_PIO_LHR, (sector >> 37) & 0xff);
+ ata_write_cbr(&ATA_PIO_LMR, (sector >> 29) & 0xff);
+ ata_write_cbr(&ATA_PIO_LLR, (sector >> 21) & 0xff);
+ ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff);
+ ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff);
+ ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff);
+ ata_write_cbr(&ATA_PIO_DVR, BIT(6));
+ if (write) ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0x35 : 0x39);
+ else ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0x25 : 0x29);
+ }
+ else
+ {
+ ata_write_cbr(&ATA_PIO_SCR, (cnt << 3) & 0xff);
+ ata_write_cbr(&ATA_PIO_LHR, (sector >> 13) & 0xff);
+ ata_write_cbr(&ATA_PIO_LMR, (sector >> 5) & 0xff);
+ ata_write_cbr(&ATA_PIO_LLR, (sector << 3) & 0xff);
+ ata_write_cbr(&ATA_PIO_DVR, BIT(6) | ((sector >> 21) & 0xf));
+ if (write) ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0xca : 0x30);
+ else ata_write_cbr(&ATA_PIO_CSD, ata_dma ? 0xc8 : 0xc4);
+ }
+ if (ata_dma)
+ {
+ PASS_RC(ata_wait_for_start_of_transfer(500000), 2, 1);
+ if (write)
+ {
+ ATA_SBUF_START = buffer;
+ ATA_SBUF_SIZE = SECTOR_SIZE * cnt;
+ ATA_CFG |= BIT(4);
+ }
+ else
+ {
+ ATA_TBUF_START = buffer;
+ ATA_TBUF_SIZE = SECTOR_SIZE * cnt;
+ ATA_CFG &= ~BIT(4);
+ }
+ ATA_XFR_NUM = SECTOR_SIZE * cnt - 1;
+ ATA_CFG |= ata_dma_flags;
+ ATA_CFG &= ~(BIT(7) | BIT(8));
+ wakeup_wait(&ata_wakeup, 0);
+ ATA_IRQ = BITRANGE(0, 4);
+ ATA_IRQ_MASK = BIT(0);
+ ATA_COMMAND = BIT(0);
+ if (wakeup_wait(&ata_wakeup, 500000 * HZ / 1000000) == OBJ_WAIT_TIMEDOUT)
+ {
+ ATA_COMMAND = BIT(1);
+ ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12));
+ RET_ERR(2);
+ }
+ ATA_COMMAND = BIT(1);
+ ATA_CFG &= ~(BITRANGE(2, 3) | BIT(12));
+ }
+ else
+ {
+ cnt *= SECTOR_SIZE / 512;
+ while (cnt--)
+ {
+ int i;
+ PASS_RC(ata_wait_for_start_of_transfer(500000), 2, 1);
+ if (write)
+ for (i = 0; i < 256; i++)
+ ata_write_cbr(&ATA_PIO_DTR, ((uint16_t*)buffer)[i]);
+ else
+ for (i = 0; i < 256; i++)
+ ((uint16_t*)buffer)[i] = ata_read_cbr(&ATA_PIO_DTR);
+ buffer += 512;
+ }
+ }
+ PASS_RC(ata_wait_for_end_of_transfer(100000), 2, 3);
+ }
+ return 0;
+}
+
+int ata_rw_chunk(uint64_t sector, uint32_t cnt, void* buffer, bool write)
+{
+ led(true);
+ int rc = ata_rw_chunk_internal(sector, cnt, buffer, write);
+ led(false);
+ return rc;
+}
+
+#ifdef ATA_HAVE_BBT
+int ata_bbt_translate(uint64_t sector, uint32_t count, uint64_t* phys, uint32_t* physcount)
+{
+ if (sector + count > ata_virtual_sectors) RET_ERR(0);
+ if (!ata_bbt)
+ {
+ *phys = sector;
+ *physcount = count;
+ return 0;
+ }
+ if (!count)
+ {
+ *phys = 0;
+ *physcount = 0;
+ return 0;
+ }
+ uint32_t offset;
+ uint32_t l0idx = sector >> 15;
+ uint32_t l0offs = sector & 0x7fff;
+ *physcount = MIN(count, 0x8000 - l0offs);
+ uint32_t l0data = ata_bbt[0][l0idx << 1];
+ uint32_t base = ata_bbt[0][(l0idx << 1) | 1] << 12;
+ if (l0data < 0x8000) offset = l0data + base;
+ else
+ {
+ uint32_t l1idx = (sector >> 10) & 0x1f;
+ uint32_t l1offs = sector & 0x3ff;
+ *physcount = MIN(count, 0x400 - l1offs);
+ uint32_t l1data = ata_bbt[l0data & 0x7fff][l1idx];
+ if (l1data < 0x8000) offset = l1data + base;
+ else
+ {
+ uint32_t l2idx = (sector >> 5) & 0x1f;
+ uint32_t l2offs = sector & 0x1f;
+ *physcount = MIN(count, 0x20 - l2offs);
+ uint32_t l2data = ata_bbt[l1data & 0x7fff][l2idx];
+ if (l2data < 0x8000) offset = l2data + base;
+ else
+ {
+ uint32_t l3idx = sector & 0x1f;
+ uint32_t l3data = ata_bbt[l2data & 0x7fff][l3idx];
+ for (*physcount = 1; *physcount < count && l3idx + *physcount < 0x20; *physcount++)
+ if (ata_bbt[l2data & 0x7fff][l3idx + *physcount] != l3data)
+ break;
+ offset = l3data + base;
+ }
+ }
+ }
+ *phys = sector + offset;
+ return 0;
+}
+#endif
+
+int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool write)
+{
+ if (((uint32_t)buffer) & 0xf)
+ panicf("ATA: Misaligned data buffer at %08X (sector %lu, count %lu)",
+ (unsigned int)buffer, (long unsigned int)sector, (long unsigned int)count);
+#ifdef ATA_HAVE_BBT
+ if (sector + count > ata_virtual_sectors) RET_ERR(0);
+ if (ata_bbt)
+ while (count)
+ {
+ uint64_t phys;
+ uint32_t cnt;
+ PASS_RC(ata_bbt_translate(sector, count, &phys, &cnt), 0, 0);
+ uint32_t offset = phys - sector;
+ if (offset != ata_last_offset && phys - ata_last_phys < 64) ata_soft_reset();
+ ata_last_offset = offset;
+ ata_last_phys = phys + cnt;
+ PASS_RC(ata_rw_sectors_internal(phys, cnt, buffer, write), 0, 0);
+ buffer += cnt * SECTOR_SIZE;
+ sector += cnt;
+ count -= cnt;
+ }
+ else PASS_RC(ata_rw_sectors_internal(sector, count, buffer, write), 0, 0);
+ return 0;
+}
+
+int ata_rw_sectors_internal(uint64_t sector, uint32_t count, void* buffer, bool write)
+{
+#endif
+ if (sector + count > ata_total_sectors) RET_ERR(0);
+ if (!ata_powered) ata_power_up();
+ ata_set_active();
+ if (ata_dma && write) clean_dcache();
+ else if (ata_dma) invalidate_dcache();
+ if (!ceata) ATA_COMMAND = BIT(1);
+ while (count)
+ {
+ uint32_t cnt = MIN(ata_lba48 ? 8192 : 32, count);
+ int rc = -1;
+ rc = ata_rw_chunk(sector, cnt, buffer, write);
+ if (rc && ata_error_srst) ata_soft_reset();
+ if (rc && ata_retries)
+ {
+ void* buf = buffer;
+ uint64_t sect;
+ for (sect = sector; sect < sector + cnt; sect++)
+ {
+ rc = -1;
+ int tries = ata_retries;
+ while (tries-- && rc)
+ {
+ rc = ata_rw_chunk(sect, 1, buf, write);
+ if (rc && ata_error_srst) ata_soft_reset();
+ }
+ if (rc) break;
+ buf += SECTOR_SIZE;
+ }
+ }
+ PASS_RC(rc, 1, 1);
+ buffer += SECTOR_SIZE * cnt;
+ sector += cnt;
+ count -= cnt;
+ }
+ ata_set_active();
+ return 0;
+}
+
+static void ata_thread(void)
+{
+ while (true)
+ {
+ mutex_lock(&ata_mutex);
+ if (TIME_AFTER(current_tick, ata_last_activity_value + ata_sleep_timeout) && ata_powered)
+ {
+ call_storage_idle_notifys(false);
+ ata_power_down();
+ }
+ mutex_unlock(&ata_mutex);
+ sleep(HZ / 2);
+ }
+}
+
+/* API Functions */
+int ata_soft_reset(void)
+{
+ int rc;
+ mutex_lock(&ata_mutex);
+ if (!ata_powered) ata_power_up();
+ ata_set_active();
+ if (ceata) rc = ceata_soft_reset();
+ else
+ {
+ ata_write_cbr(&ATA_PIO_DAD, BIT(1) | BIT(2));
+ udelay(10);
+ ata_write_cbr(&ATA_PIO_DAD, 0);
+ rc = ata_wait_for_rdy(20000000);
+ }
+ if (IS_ERR(rc))
+ {
+ ata_power_down();
+ sleep(HZ * 3);
+ ata_power_up();
+ }
+ ata_set_active();
+ mutex_unlock(&ata_mutex);
+ return rc;
+}
+
+int ata_read_sectors(IF_MD2(int drive,) unsigned long start, int incount,
+ void* inbuf)
+{
+ mutex_lock(&ata_mutex);
+ int rc = ata_rw_sectors(start, incount, inbuf, false);
+ mutex_unlock(&ata_mutex);
+ return rc;
+}
+
+int ata_write_sectors(IF_MD2(int drive,) unsigned long start, int count,
+ const void* outbuf)
+{
+ mutex_lock(&ata_mutex);
+ int rc = ata_rw_sectors(start, count, (void*)((uint32_t)outbuf), true);
+ mutex_unlock(&ata_mutex);
+ return rc;
+}
+
+void ata_spindown(int seconds)
+{
+ ata_sleep_timeout = seconds * HZ;
+}
+
+void ata_sleep(void)
+{
+ ata_last_activity_value = current_tick - ata_sleep_timeout + HZ / 5;
+}
+
+void ata_sleepnow(void)
+{
+ mutex_lock(&ata_mutex);
+ ata_power_down();
+ mutex_unlock(&ata_mutex);
+}
+
+void ata_close(void)
+{
+ ata_sleepnow();
+}
+
+void ata_spin(void)
+{
+ ata_set_active();
+}
+
+void ata_get_info(IF_MD2(int drive,) struct storage_info *info)
+{
+ (*info).sector_size = SECTOR_SIZE;
+#ifdef ATA_HAVE_BBT
+ (*info).num_sectors = ata_virtual_sectors;
+#else
+ (*info).num_sectors = ata_total_sectors;
+#endif
+ (*info).vendor = "Apple";
+ (*info).product = "iPod Classic";
+ (*info).revision = "1.0";
+}
+
+long ata_last_disk_activity(void)
+{
+ return ata_last_activity_value;
+}
+
+#ifdef ATA_HAVE_BBT
+void ata_bbt_disable(void)
+{
+ mutex_lock(&ata_mutex);
+ if (ata_bbt) free(ata_bbt);
+ ata_bbt = NULL;
+ ata_virtual_sectors = ata_total_sectors;
+ mutex_unlock(&ata_mutex);
+}
+
+void ata_bbt_reload(void)
+{
+ mutex_lock(&ata_mutex);
+ ata_bbt_disable();
+ ata_power_up();
+ uint32_t* buf = (uint32_t*)(ata_bbt_buf + sizeof(ata_bbt_buf) - SECTOR_SIZE);
+ if (buf)
+ {
+ if (IS_ERR(ata_bbt_read_sectors(0, 1, buf)))
+ ata_virtual_sectors = ata_total_sectors;
+ else if (!memcmp(buf, "emBIbbth", 8))
+ {
+ ata_virtual_sectors = (((uint64_t)buf[0x1fd]) << 32) | buf[0x1fc];
+ uint32_t count = buf[0x1ff];
+ if (count > ATA_BBT_PAGES / 64)
+ panicf("ATA: BBT too big! (space: %d, size: %d)", ATA_BBT_PAGES, count * 64);
+ uint32_t i;
+ uint32_t cnt;
+ ata_bbt = (typeof(ata_bbt))ata_bbt_buf;
+ for (i = 0; i < count; i += cnt)
+ {
+ uint32_t phys = buf[0x200 + i];
+ for (cnt = 1; cnt < count; cnt++)
+ if (buf[0x200 + i + cnt] != phys + cnt)
+ break;
+ if (IS_ERR(ata_bbt_read_sectors(phys, cnt, ata_bbt[i << 6])))
+ {
+ ata_virtual_sectors = ata_total_sectors;
+ break;
+ }
+ }
+ }
+ else ata_virtual_sectors = ata_total_sectors;
+ }
+ else ata_virtual_sectors = ata_total_sectors;
+ mutex_unlock(&ata_mutex);
+}
+#endif
+
+int ata_init(void)
+{
+ mutex_init(&ata_mutex);
+ wakeup_init(&ata_wakeup);
+ wakeup_init(&mmc_wakeup);
+ wakeup_init(&mmc_comp_wakeup);
+ ceata = PDAT(11) & BIT(1);
+ if (ceata)
+ {
+ ata_lba48 = true;
+ ata_dma = true;
+ PCON(8) = 0x33333333;
+ PCON(9) = (PCON(9) & ~0xff) | 0x33;
+ PCON(11) |= 0xf;
+ *((uint32_t volatile*)0x38a00000) = 0;
+ *((uint32_t volatile*)0x38700000) = 0;
+ }
+ else
+ {
+ PCON(7) = 0x44444444;
+ PCON(8) = 0x44444444;
+ PCON(9) = 0x44444444;
+ PCON(10) = (PCON(10) & ~0xffff) | 0x4444;
+ }
+ ata_powered = false;
+ ata_total_sectors = 0;
+ ata_power_up();
+#ifdef ATA_HAVE_BBT
+ ata_bbt_reload();
+#endif
+ create_thread(ata_thread, ata_stack,
+ sizeof(ata_stack), 0, "ATA idle monitor"
+ IF_PRIO(, PRIORITY_USER_INTERFACE)
+ IF_COP(, CPU));
+ return 0;
+}
+
+int ata_num_drives(int first_drive)
+{
+ /* We don't care which logical drive number(s) we have been assigned */
+ (void)first_drive;
+
+ return 1;
+}
+
+unsigned short* ata_get_identify(void)
+{
+ return ata_identify_data;
+}
+
+int ata_spinup_time(void)
+{
+ return spinup_time;
+}
+
+int ata_get_dma_mode(void)
+{
+ return dma_mode;
+}
+
+void INT_ATA(void)
+{
+ uint32_t ata_irq = ATA_IRQ;
+ ATA_IRQ = ata_irq;
+ if (ata_irq & ATA_IRQ_MASK) wakeup_signal(&ata_wakeup);
+ ATA_IRQ_MASK = 0;
+}
+
+void INT_MMC(void)
+{
+ uint32_t irq = SDCI_IRQ;
+ if (irq & SDCI_IRQ_DAT_DONE_INT) wakeup_signal(&mmc_wakeup);
+ if (irq & SDCI_IRQ_IOCARD_IRQ_INT) wakeup_signal(&mmc_comp_wakeup);
+ SDCI_IRQ = irq;
+}
diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c
index 4a8f47e..e264e61 100644
--- a/firmware/target/arm/s5l8702/system-s5l8702.c
+++ b/firmware/target/arm/s5l8702/system-s5l8702.c
@@ -97,7 +97,7 @@ default_interrupt(INT_IRQ40);
default_interrupt(INT_IRQ41);
default_interrupt(INT_IRQ42);
default_interrupt(INT_IRQ43);
-default_interrupt(INT_IRQ44);
+default_interrupt(INT_MMC);
default_interrupt(INT_IRQ45);
default_interrupt(INT_IRQ46);
default_interrupt(INT_IRQ47);
@@ -169,7 +169,7 @@ static void (* const irqvector[])(void) =
INT_DMAC0,INT_DMAC1,INT_IRQ18,INT_USB_FUNC,INT_IRQ20,INT_IRQ21,INT_IRQ22,INT_WHEEL,
INT_IRQ24,INT_IRQ25,INT_IRQ26,INT_IRQ27,INT_IRQ28,INT_ATA,INT_IRQ30,INT_IRQ31,
INT_IRQ32,INT_IRQ33,INT_IRQ34,INT_IRQ35,INT_IRQ36,INT_IRQ37,INT_IRQ38,INT_IRQ39,
- INT_IRQ40,INT_IRQ41,INT_IRQ42,INT_IRQ43,INT_IRQ55,INT_IRQ56,INT_IRQ57,INT_IRQ58,
+ INT_IRQ40,INT_IRQ41,INT_IRQ42,INT_IRQ43,INT_MMC,INT_IRQ45,INT_IRQ46,INT_IRQ47,
INT_IRQ48,INT_IRQ49,INT_IRQ50,INT_IRQ51,INT_IRQ52,INT_IRQ53,INT_IRQ54,INT_IRQ55,
INT_IRQ56,INT_IRQ57,INT_IRQ58,INT_IRQ59,INT_IRQ60,INT_IRQ61,INT_IRQ62,INT_IRQ63
};
@@ -218,6 +218,8 @@ void system_init(void)
{
pmu_init();
VIC0INTENABLE = 1 << IRQ_WHEEL;
+ VIC0INTENABLE = 1 << IRQ_ATA;
+ VIC1INTENABLE = 1 << (IRQ_MMC - 32);
}
void system_reboot(void)