From 30fb680a4dc7b8f1fed9002a47dc2154c7f72d0a Mon Sep 17 00:00:00 2001 From: Michael Sparmann Date: Sun, 27 Feb 2011 22:47:55 +0000 Subject: [PATCH] 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 --- firmware/SOURCES | 4 +- firmware/export/config/ipod6g.h | 11 +- firmware/export/s5l8702.h | 210 ++- firmware/target/arm/s5l8700/app.lds | 2 +- firmware/target/arm/s5l8702/app.lds | 2 +- .../target/arm/s5l8702/ipod6g/ata-ipod6g.c | 197 --- .../target/arm/s5l8702/ipod6g/ata-target.h | 47 - .../arm/s5l8702/ipod6g/mmcdefs-target.h | 345 +++++ .../arm/s5l8702/ipod6g/storage_ata-ipod6g.c | 1142 +++++++++++++++++ firmware/target/arm/s5l8702/system-s5l8702.c | 6 +- 10 files changed, 1702 insertions(+), 264 deletions(-) delete mode 100644 firmware/target/arm/s5l8702/ipod6g/ata-ipod6g.c delete mode 100644 firmware/target/arm/s5l8702/ipod6g/ata-target.h create mode 100644 firmware/target/arm/s5l8702/ipod6g/mmcdefs-target.h create mode 100644 firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c diff --git a/firmware/SOURCES b/firmware/SOURCES index b2b353bda2..e0186af966 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 6ab89e5869..e783612364 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 076e661fa4..ebd3eda2bb 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 2f8ef6a40f..aa37addbf6 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 fafdea4cd9..ec66e5d969 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 f1577ee857..0000000000 --- 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 e2e7bd298c..0000000000 --- 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 0000000000..50e591253e --- /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 . +// +// + + +#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 0000000000..66e02d65bb --- /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 4a8f47e59e..e264e61e22 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)