From 82602a7ff0be45499c24183f127da418ab35f50c Mon Sep 17 00:00:00 2001 From: "0xD15EA5E@gmail.com" <0xD15EA5E@gmail.com@be6c1b03-d731-4111-a574-e37d80d43941> Date: Tue, 25 Sep 2012 11:48:20 +0000 Subject: [PATCH] dml git-svn-id: svn://localhost/Users/andi/Downloads/code/DML@30 be6c1b03-d731-4111-a574-e37d80d43941 --- Card.c | 24 +- Config.c | 10 +- Config.h | 1 - DVDPatches.c | 18 -- HW.h | 1 - Patches.c | 5 +- Patches.h | 1 - bsdtypes.h | 6 +- dip.c | 6 +- global.h | 2 +- ipc.h | 67 ---- main.c | 1 - memory.h | 1 - sdhc.c | 854 +++++++++++++++++++++++++++++++++++++++++++++++++++ sdhc.h | 210 +++++++++++++ sdhcreg.h | 172 +++++++++++ sdhcvar.h | 62 ++++ sdmmc.c | 373 ++++++++++++++++++++++ sdmmc.h | 370 ++++++++++++++++++++++ sdmmcchip.h | 83 +++++ sdmmcreg.h | 232 ++++++++++++++ sdmmcvar.h | 182 +++++++++++ usb.h | 165 ---------- usbstorage.h | 73 ----- 24 files changed, 2576 insertions(+), 343 deletions(-) delete mode 100644 ipc.h create mode 100644 sdhc.c create mode 100644 sdhc.h create mode 100644 sdhcreg.h create mode 100644 sdhcvar.h create mode 100644 sdmmc.c create mode 100644 sdmmc.h create mode 100644 sdmmcchip.h create mode 100644 sdmmcreg.h create mode 100644 sdmmcvar.h delete mode 100644 usb.h delete mode 100644 usbstorage.h diff --git a/Card.c b/Card.c index 352ac9e..89f9721 100644 --- a/Card.c +++ b/Card.c @@ -1,12 +1,16 @@ #include "Card.h" FIL CardStat; +extern u32 FSTMode; +extern FIL GameFile; void CardInit( void ) { FILINFO f; u32 i,wrote; CARDStat CStat; + char GameID[0x20]; + memset32( (void*)CARD_BASE, 0xdeadbeef, 0x20 ); memset32( (void*)CARD_SHADOW, 0, 0x20 ); @@ -18,10 +22,20 @@ void CardInit( void ) f_chdir("/saves"); } - if( f_chdir((const TCHAR*)0) != FR_OK ) + if( FSTMode ) { - f_mkdir((const TCHAR*)0); - f_chdir((const TCHAR*)0); + FSTRead( (char*)GameID, 0x20, 0 ); + + } else { + + f_lseek( &GameFile, 0 ); + f_read( &GameFile, (char*)GameID, 0x20, &wrote ); + } + + if( f_chdir(GameID) != FR_OK ) + { + f_mkdir(GameID); + f_chdir(GameID); } switch( f_stat( "stats.bin", &f ) ) @@ -89,8 +103,8 @@ s32 CardFindEntryByName( char *Filename ) { f_lseek( &CardStat, sizeof(CARDStat) * i ); f_read( &CardStat, &CStat, sizeof(CARDStat), &read ); - - if( memcmp( Filename, CStat.fileName, strlen(Filename) ) == 0 ) + + if( strcmp( Filename, CStat.fileName ) == 0 ) { //dbgprintf("CardFindEntryByName(%d,%s,%s)\n", i, Filename, CStat.fileName ); return i; diff --git a/Config.c b/Config.c index 57e71f6..0e65f9d 100644 --- a/Config.c +++ b/Config.c @@ -9,15 +9,15 @@ void ConfigInit( DML_CFG *Cfg ) memset32( DMLCfg, 0, sizeof(DML_CFG) ); //If a loader supplied any options we use them otherwise use the code defines - if( Cfg->Magicbytes == 0xD1050CF6 && Cfg->Version == CONFIG_VERSION ) + if( Cfg->Magicbytes == 0xD1050CF6 ) { memcpy( DMLCfg, Cfg, sizeof( DML_CFG ) ); } else { - dbgprintf("No valid found in RAM\n"); + dbgprintf("No valid config found in RAM\n"); dbgprintf("Version:%08X\n", DMLCfg->Version ); - dbgprintf("Config:%08X\n", DMLCfg->Config ); + dbgprintf("Config :%08X\n", DMLCfg->Config ); DMLCfg->Config = 0; #ifdef CHEATHOOK @@ -41,9 +41,9 @@ void ConfigInit( DML_CFG *Cfg ) #ifdef PADHOOK DMLCfg->Config |= DML_CFG_PADHOOK; #endif - DMLCfg->VideoMode = DML_VID_DML_AUTO; - DMLCfg->Version = CONFIG_VERSION; DMLCfg->Magicbytes = 0xD1050CF6; + DMLCfg->Version = CONFIG_VERSION; + DMLCfg->VideoMode = DML_VID_DML_AUTO; } //Check if a memcard is inserted in Slot A diff --git a/Config.h b/Config.h index 4d5fd97..01d9459 100644 --- a/Config.h +++ b/Config.h @@ -3,7 +3,6 @@ #include "string.h" #include "global.h" -#include "ipc.h" #include "alloc.h" #include "vsprintf.h" #include "HW.h" diff --git a/DVDPatches.c b/DVDPatches.c index 5437d42..3bff736 100644 --- a/DVDPatches.c +++ b/DVDPatches.c @@ -3,26 +3,8 @@ #include "global.h" -#include "asm\DVDRead.h" -#include "asm\DVDReadAsync.h" -#include "asm\DVDReadAbsAsyncPrioAsync.h" -#include "asm\mDVDReadAbsAsyncPrio.h" -#include "asm\DVDReadAbsAsyncPrio.h" -#include "asm\LDVDReadAbsAsyncPrio.h" -#include "asm\DVDReadAbsAsyncPrioForBS.h" -#include "asm\mDVDReadAbsAsyncPrioShift.h" -#include "asm\DVDReadDiscIDAsync.h" #include "asm\DVDInquiryAsync.h" -#include "asm\__DVDInterruptHandler.h" -#include "asm\DVDLowReadShift.h" -#include "asm\DVDWaitReady.h" -#include "asm\dDVDReadAbs.h" #include "asm\DVDSeekAbsAsyncPrio.h" -#include "asm\DVDPrepareStreamAbsAsync.h" -#include "asm\DVDStopStreamAtEndAsync.h" -#include "asm\DVDCancelStreamAsync.h" -#include "asm\DVDGetStreamPlayAddrAsync.h" -#include "asm\DVDLowRead.h" #include "asm\padipc.h" #endif diff --git a/HW.h b/HW.h index 8b6a47f..e329488 100644 --- a/HW.h +++ b/HW.h @@ -4,7 +4,6 @@ #include "string.h" #include "global.h" #include "memory.h" -#include "ipc.h" #include "alloc.h" #include "dip.h" diff --git a/Patches.c b/Patches.c index d21295f..d323f0d 100644 --- a/Patches.c +++ b/Patches.c @@ -890,8 +890,11 @@ void DoPatches( char *ptr, u32 size, u32 SectionOffset ) if( FPatterns[j].Patch == (u8*)DVDGetDriveStatus ) { - if( !ConfigGetConfig( DML_CFG_NODISC ) ) + if( (read32(0) >> 8) != 0x474754 && // Chibi-Robo! + (read32(0) >> 8) != 0x475041 ) // Pokémon Channel break; + + dbgprintf("Patch:DVDGetDriveStatus\n"); } if( (FPatterns[j].Length >> 16) == 0xdead ) diff --git a/Patches.h b/Patches.h index fe64b2a..d6cafa5 100644 --- a/Patches.h +++ b/Patches.h @@ -3,7 +3,6 @@ #include "string.h" #include "global.h" -#include "ipc.h" #include "alloc.h" #include "ff.h" #include "vsprintf.h" diff --git a/bsdtypes.h b/bsdtypes.h index 9703b30..a17f7db 100644 --- a/bsdtypes.h +++ b/bsdtypes.h @@ -2,7 +2,11 @@ #define __BSDTYPES_H__ #include "global.h" -#include "errno.h" + +#define ENXIO 6 +#define EINVAL 22 +#define WSAETIMEDOUT 10060L +#define ETIMEDOUT WSAETIMEDOUT typedef u32 u_int; //typedef u32 u_int32_t; diff --git a/dip.c b/dip.c index 8173111..532b302 100644 --- a/dip.c +++ b/dip.c @@ -155,7 +155,8 @@ u32 DIUpdateRegisters( void ) switch( Offset ) { case 0x56B8E7E0: // AppSwitcher [EUR] - case 0x56C49600: // [USA] + case 0x56C49600: // [USA] v1.1 + case 0x56C4C980: // [USA] v1.0 { DMLCfg->Config &= ~(DML_CFG_CHEATS|DML_CFG_PADHOOK|DML_CFG_DEBUGGER|DML_CFG_DEBUGWAIT); @@ -163,7 +164,8 @@ u32 DIUpdateRegisters( void ) } break; case 0x5668FE20: // psov3.dol [EUR] - case 0x56750660: // [USA] + case 0x56750660: // [USA] v1.1 + case 0x56753EC0: // [USA] v1.0 { PSOHack = 1; } break; diff --git a/global.h b/global.h index 10af9cc..ae7a110 100644 --- a/global.h +++ b/global.h @@ -15,7 +15,7 @@ #define PADHOOK 1 #define CONFIG_VERSION 0x00000002 -#define DML_VERSION 0x00020002 +#define DML_VERSION 0x00020003 #define DI_SUCCESS 1 #define DI_ERROR 2 diff --git a/ipc.h b/ipc.h deleted file mode 100644 index e703c41..0000000 --- a/ipc.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __IPC_H__ -#define __IPC_H__ 1 - -struct ioctl_vector { - void *data; - unsigned int len; -} __attribute__((packed)); - -struct ipcmessage -{ - unsigned int command; // 0 - unsigned int result; // 4 - union - { - unsigned int fd; // 8 - }; - union - { - struct - { - char *device; // 12 - unsigned int mode; // 16 - unsigned int resultfd; // 20 - } open; - - struct - { - void *data; - unsigned int length; - } read, write; - - struct - { - int offset; - int origin; - } seek; - - struct - { - unsigned int command; - - unsigned int *buffer_in; - unsigned int length_in; - unsigned int *buffer_io; - unsigned int length_io; - } ioctl; - - struct - { - unsigned int command; // C - - unsigned int argc_in; // 10 - unsigned int argc_io; // 14 - struct ioctl_vector *argv; // 18 - } ioctlv; - }; -} __attribute__((packed)) ipcmessage; - -#define IOS_OPEN 0x01 -#define IOS_CLOSE 0x02 -#define IOS_READ 0x03 -#define IOS_WRITE 0x04 -#define IOS_SEEK 0x05 -#define IOS_IOCTL 0x06 -#define IOS_IOCTLV 0x07 - -#endif diff --git a/main.c b/main.c index 679dd02..1522509 100644 --- a/main.c +++ b/main.c @@ -7,7 +7,6 @@ Copyright (C) 2010-2012 crediar */ #include "string.h" #include "global.h" -#include "ipc.h" #include "alloc.h" #include "ff.h" #include "diskio.h" diff --git a/memory.h b/memory.h index c645c22..326b712 100644 --- a/memory.h +++ b/memory.h @@ -3,7 +3,6 @@ #include "string.h" #include "global.h" -#include "ipc.h" #include "utils.h" #include "hollywood.h" #include "vsprintf.h" diff --git a/sdhc.c b/sdhc.c new file mode 100644 index 0000000..d9c7461 --- /dev/null +++ b/sdhc.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) 2006 Uwe Stuehler + * Copyright (c) 2009 Sven Peter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * SD Host Controller driver based on the SD Host Controller Standard + * Simplified Specification Version 1.00 (www.sdcard.com). + */ + +#include "bsdtypes.h" +#include "sdmmc.h" +#include "sdhc.h" +#include "string.h" +#include "utils.h" +#include "memory.h" + +struct sdhc_host sc_host; + +//#define SDHC_DEBUG + +#define SDHC_COMMAND_TIMEOUT 500 +#define SDHC_TRANSFER_TIMEOUT 5000 + +#define sdhc_wait_intr(a,b,c) sdhc_wait_intr_debug(__func__, __LINE__, a, b, c) + +static inline u32 bus_space_read_4(bus_space_handle_t ioh, u32 reg) +{ + return read32(ioh + reg); +} + +static inline u16 bus_space_read_2(bus_space_handle_t ioh, u32 reg) +{ + u32 val; + if(reg & 3) + val = (read32((ioh + reg) & ~3) & 0xffff0000) >> 16; + else + val = (read32(ioh + reg) & 0xffff); + return val; +} + +static inline u8 bus_space_read_1(bus_space_handle_t ioh, u32 reg) +{ + u32 mask; + u32 addr; + u8 shift; + + shift = (reg & 3) * 8; + mask = (0xFF << shift); + addr = ioh + reg; + + return (read32(addr & ~3) & mask) >> shift; +} + +static inline void bus_space_write_4(bus_space_handle_t ioh, u32 r, u32 v) +{ + write32(ioh + r, v); +} + +static inline void bus_space_write_2(bus_space_handle_t ioh, u32 r, u16 v) +{ + if(r & 3) + mask32((ioh + r) & ~3, 0xffff0000, v << 16); + else + mask32((ioh + r), 0xffff, ((u32)v)); +} + +static inline void bus_space_write_1(bus_space_handle_t ioh, u32 r, u8 v) +{ + u32 mask; + u32 addr; + u8 shift; + + shift = (r & 3) * 8; + mask = (0xFF << shift); + addr = ioh + r; + + mask32(addr & ~3, mask, v << shift); + + +} + +/* flag values */ +#define SHF_USE_DMA 0x0001 + +#define HREAD1(hp, reg) \ + (bus_space_read_1((hp)->ioh, (reg))) +#define HREAD2(hp, reg) \ + (bus_space_read_2((hp)->ioh, (reg))) +#define HREAD4(hp, reg) \ + (bus_space_read_4((hp)->ioh, (reg))) +#define HWRITE1(hp, reg, val) \ + bus_space_write_1((hp)->ioh, (reg), (val)) +#define HWRITE2(hp, reg, val) \ + bus_space_write_2((hp)->ioh, (reg), (val)) +#define HWRITE4(hp, reg, val) \ + bus_space_write_4((hp)->ioh, (reg), (val)) +#define HCLR1(hp, reg, bits) \ + HWRITE1((hp), (reg), HREAD1((hp), (reg)) & ~(bits)) +#define HCLR2(hp, reg, bits) \ + HWRITE2((hp), (reg), HREAD2((hp), (reg)) & ~(bits)) +#define HSET1(hp, reg, bits) \ + HWRITE1((hp), (reg), HREAD1((hp), (reg)) | (bits)) +#define HSET2(hp, reg, bits) \ + HWRITE2((hp), (reg), HREAD2((hp), (reg)) | (bits)) + +int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *); +int sdhc_wait_state(struct sdhc_host *, u_int32_t, u_int32_t); +int sdhc_soft_reset(struct sdhc_host *, int); +void sdhc_reset_intr_status(struct sdhc_host *hp); +int sdhc_wait_intr_debug(const char *func, int line, struct sdhc_host *, int, int); +void sdhc_transfer_data(struct sdhc_host *, struct sdmmc_command *); +void sdhc_read_data(struct sdhc_host *, u_char *, int); +void sdhc_write_data(struct sdhc_host *, u_char *, int); +//#define SDHC_DEBUG 1 +#ifdef SDHC_DEBUG +int sdhcdebug = 0; +#define DPRINTF(n,s) do { if ((n) <= sdhcdebug) dbgprintf s; } while (0) +void sdhc_dump_regs(struct sdhc_host *); +#else +#define DPRINTF(n,s) do {} while(0) +#endif + +/* + * Called by attachment driver. For each SD card slot there is one SD + * host controller standard register set. (1.3) + */ +int +sdhc_host_found(bus_space_tag_t iot, bus_space_handle_t ioh, int usedma) +{ + u_int32_t caps; + int error = 1; + +#ifdef SDHC_DEBUG + u_int16_t version; + + version = bus_space_read_2(ioh, SDHC_HOST_CTL_VERSION); + dbgprintf("sdhc: SD Host Specification/Vendor Version "); + + switch(SDHC_SPEC_VERSION(version)) { + case 0x00: + dbgprintf("1.0/%u\n", SDHC_VENDOR_VERSION(version)); + break; + default: + dbgprintf(">1.0/%u\n", SDHC_VENDOR_VERSION(version)); + break; + } +#endif + + memset8(&sc_host, 0, sizeof(sc_host)); + + /* Fill in the new host structure. */ + sc_host.iot = iot; + sc_host.ioh = ioh; + sc_host.data_command = 0; + + /* + * Reset the host controller and enable interrupts. + */ + error = sdhc_host_reset(&sc_host); + + /* Determine host capabilities. */ + caps = HREAD4(&sc_host, SDHC_CAPABILITIES); + + /* Use DMA if the host system and the controller support it. */ + if (usedma && ISSET(caps, SDHC_DMA_SUPPORT)) + SET(sc_host.flags, SHF_USE_DMA); + + /* + * Determine the base clock frequency. (2.2.24) + */ + if (SDHC_BASE_FREQ_KHZ(caps) != 0) + sc_host.clkbase = SDHC_BASE_FREQ_KHZ(caps); + if (sc_host.clkbase == 0) { + /* The attachment driver must tell us. */ + //dbgprintf("sdhc: base clock frequency unknown\n"); + goto err; + } else if (sc_host.clkbase < 10000 || sc_host.clkbase > 63000) { + /* SDHC 1.0 supports only 10-63 MHz. */ + //dbgprintf("sdhc: base clock frequency out of range: %u MHz\n", sc_host.clkbase / 1000); + goto err; + } + + /* + * XXX Set the data timeout counter value according to + * capabilities. (2.2.15) + */ + + if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V)) + SET(sc_host.ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V); + if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V)) + SET(sc_host.ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V); + if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_3V)) + SET(sc_host.ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V); + /* + * Determine the maximum block length supported by the host + * controller. (2.2.24) + */ + //switch((caps >> SDHC_MAX_BLK_LEN_SHIFT) & SDHC_MAX_BLK_LEN_MASK) + //{ + // case SDHC_MAX_BLK_LEN_512: + // hp->maxblklen = 512; + // break; + // case SDHC_MAX_BLK_LEN_1024: + // hp->maxblklen = 1024; + // break; + // case SDHC_MAX_BLK_LEN_2048: + // hp->maxblklen = 2048; + // break; + // default: + // hp->maxblklen = 1; + // break; + //} + + /* + * Attach the generic SD/MMC bus driver. (The bus driver must + * not invoke any chipset functions before it is attached.) + */ + sdmmc_attach(&sc_host); + + return 0; + +err: + return (error); +} + +#ifndef LOADER +/* + * Shutdown hook established by or called from attachment driver. + */ +void +sdhc_shutdown(void) +{ + /* XXX chip locks up if we don't disable it before reboot. */ + (void)sdhc_host_reset(&sc_host); +} +#endif + +/* + * Reset the host controller. Called during initialization, when + * cards are removed, upon resume, and during error recovery. + */ +int +sdhc_host_reset(struct sdhc_host *hp) +{ + u_int16_t imask; + int error; + + /* Disable all interrupts. */ + HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, 0); + + /* + * Reset the entire host controller and wait up to 100ms for + * the controller to clear the reset bit. + */ + if ((error = sdhc_soft_reset(hp, SDHC_RESET_ALL)) != 0) + { + return (error); + } + + /* Set data timeout counter value to max for now. */ + HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX); + + /* Enable interrupts. */ + imask = +#ifndef LOADER + SDHC_CARD_REMOVAL | SDHC_CARD_INSERTION | +#endif + SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY | + SDHC_DMA_INTERRUPT | SDHC_BLOCK_GAP_EVENT | + SDHC_TRANSFER_COMPLETE | SDHC_COMMAND_COMPLETE; + + HWRITE2(hp, SDHC_NINTR_STATUS_EN, imask); + HWRITE2(hp, SDHC_EINTR_STATUS_EN, SDHC_EINTR_STATUS_MASK); + HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, imask); + HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, SDHC_EINTR_SIGNAL_MASK); + + return 0; +} + +/* + * Return non-zero if the card is currently inserted. + */ +int +sdhc_card_detect(struct sdhc_host *hp) +{ + return ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED) ? + 1 : 0; +} + +/* + * Set or change SD bus voltage and enable or disable SD bus power. + * Return zero on success. + */ +int +sdhc_bus_power(struct sdhc_host *hp, u_int32_t ocr) +{ + //dbgprintf("sdhc_bus_power(%u)\n", ocr); + /* Disable bus power before voltage change. */ + HWRITE1(hp, SDHC_POWER_CTL, 0); + + /* If power is disabled, reset the host and return now. */ + if (ocr == 0) { + (void)sdhc_host_reset(hp); + return 0; + } + + /* + * Enable bus power. Wait at least 1 ms (or 74 clocks) plus + * voltage ramp until power rises. + */ + HWRITE1(hp, SDHC_POWER_CTL, (SDHC_VOLTAGE_3_3V << SDHC_VOLTAGE_SHIFT) | + SDHC_BUS_POWER); + udelay(10000); + + /* + * The host system may not power the bus due to battery low, + * etc. In that case, the host controller should clear the + * bus power bit. + */ + if (!ISSET(HREAD1(hp, SDHC_POWER_CTL), SDHC_BUS_POWER)) + { + //dbgprintf("Host controller failed to enable bus power\n"); + return ENXIO; + } + + return 0; +} + +/* + * Return the smallest possible base clock frequency divisor value + * for the CLOCK_CTL register to produce `freq' (KHz). + */ +static int +sdhc_clock_divisor(struct sdhc_host *hp, u_int freq) +{ + int div; + + for (div = 1; div <= 256; div *= 2) + if ((hp->clkbase / div) <= freq) + return (div / 2); + /* No divisor found. */ + return -1; +} + +/* + * Set or change SDCLK frequency or disable the SD clock. + * Return zero on success. + */ +int +sdhc_bus_clock(struct sdhc_host *hp, int freq) +{ + int div; + int timo; + + //dbgprintf("%s(%d)\n", __FUNCTION__, freq); +#ifdef DIAGNOSTIC + /* Must not stop the clock if commands are in progress. */ + if (ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CMD_INHIBIT_MASK) && + sdhc_card_detect(hp)) + dbgprintf("sdhc_sdclk_frequency_select: command in progress\n"); +#endif + + /* Stop SD clock before changing the frequency. */ + HWRITE2(hp, SDHC_CLOCK_CTL, 0); + if (freq == SDMMC_SDCLK_OFF) + return 0; + + /* Set the minimum base clock frequency divisor. */ + if ((div = sdhc_clock_divisor(hp, freq)) < 0) { + /* Invalid base clock frequency or `freq' value. */ + return EINVAL; + } + HWRITE2(hp, SDHC_CLOCK_CTL, div << SDHC_SDCLK_DIV_SHIFT); + + /* Start internal clock. Wait 10ms for stabilization. */ + HSET2(hp, SDHC_CLOCK_CTL, SDHC_INTCLK_ENABLE); + for (timo = 1000; timo > 0; timo--) { + if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), SDHC_INTCLK_STABLE)) + break; + udelay(10); + } + if (timo == 0) { + //dbgprintf("sdhc: internal clock never stabilized\n"); + return ETIMEDOUT; + } + + /* Enable SD clock. */ + HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE); + + return 0; +} + +void +sdhc_card_intr_mask(struct sdhc_host *hp, int enable) +{ + if (enable) { + HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); + HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT); + } else { + HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT); + HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); + } +} + +void +sdhc_card_intr_ack(struct sdhc_host *hp) +{ + HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); +} + +int +sdhc_wait_state(struct sdhc_host *hp, u_int32_t mask, u_int32_t value) +{ + u_int32_t state; + int timeout; + + for (timeout = 500; timeout > 0; timeout--) { + if (((state = HREAD4(hp, SDHC_PRESENT_STATE)) & mask) == value) + return 0; + udelay(10000); + } + return ETIMEDOUT; +} + +void +sdhc_exec_command(struct sdhc_host *hp, struct sdmmc_command *cmd) +{ + int error; + + if (cmd->c_datalen > 0) + hp->data_command = 1; + + if (cmd->c_timeout == 0) { + if (cmd->c_datalen > 0) + cmd->c_timeout = SDHC_TRANSFER_TIMEOUT; + else + cmd->c_timeout = SDHC_COMMAND_TIMEOUT; + } + + hp->intr_status = 0; + + /* + * Start the MMC command, or mark `cmd' as failed and return. + */ + error = sdhc_start_command(hp, cmd); + if (error != 0) { + cmd->c_error = error; + SET(cmd->c_flags, SCF_ITSDONE); + hp->data_command = 0; + return; + } + + /* + * Wait until the command phase is done, or until the command + * is marked done for any other reason. + */ + + int status = sdhc_wait_intr(hp, SDHC_COMMAND_COMPLETE, cmd->c_timeout); + if (!ISSET(status, SDHC_COMMAND_COMPLETE)) { + cmd->c_error = ETIMEDOUT; + //dbgprintf("timeout dump: error_intr: 0x%x intr: 0x%x\n", hp->intr_error_status, hp->intr_status); + //sdhc_dump_regs(hp); + SET(cmd->c_flags, SCF_ITSDONE); + hp->data_command = 0; + return; + } + + //dbgprintf("command_complete, continuing...\n"); + + /* + * The host controller removes bits [0:7] from the response + * data (CRC) and we pass the data up unchanged to the bus + * driver (without padding). + */ + if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { + if (ISSET(cmd->c_flags, SCF_RSP_136)) { + u_char *p = (u_char *)cmd->c_resp; + int i; + + for (i = 0; i < 15; i++) + *p++ = HREAD1(hp, SDHC_RESPONSE + i); + } else + cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE); + } + + /* + * If the command has data to transfer in any direction, + * execute the transfer now. + */ + if (cmd->c_error == 0 && cmd->c_datalen > 0) + sdhc_transfer_data(hp, cmd); + + SET(cmd->c_flags, SCF_ITSDONE); + hp->data_command = 0; +} + +int +sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd) +{ + u_int16_t blksize = 0; + u_int16_t blkcount = 0; + u_int16_t mode; + u_int16_t command; + int error; + + + /* + * The maximum block length for commands should be the minimum + * of the host buffer size and the card buffer size. (1.7.2) + */ + + /* Fragment the data into proper blocks. */ + if (cmd->c_datalen > 0) { + blksize = MIN(cmd->c_datalen, cmd->c_blklen); + blkcount = cmd->c_datalen / blksize; + if (cmd->c_datalen % blksize > 0) { + /* XXX: Split this command. (1.7.4) */ + //dbgprintf("sdhc: data not a multiple of %d bytes\n", blksize); + return EINVAL; + } + } + + /* Check limit imposed by 9-bit block count. (1.7.2) */ + if (blkcount > SDHC_BLOCK_COUNT_MAX) { + //dbgprintf("sdhc: too much data\n"); + return EINVAL; + } + + /* Prepare transfer mode register value. (2.2.5) */ + mode = 0; + if (ISSET(cmd->c_flags, SCF_CMD_READ)) + mode |= SDHC_READ_MODE; + if (blkcount > 0) { + mode |= SDHC_BLOCK_COUNT_ENABLE; +// if (blkcount > 1) { + mode |= SDHC_MULTI_BLOCK_MODE; + /* XXX only for memory commands? */ + mode |= SDHC_AUTO_CMD12_ENABLE; +// } + } + if (ISSET(hp->flags, SHF_USE_DMA)) + mode |= SDHC_DMA_ENABLE; + + /* + * Prepare command register value. (2.2.6) + */ + command = (cmd->c_opcode & SDHC_COMMAND_INDEX_MASK) << + SDHC_COMMAND_INDEX_SHIFT; + + if (ISSET(cmd->c_flags, SCF_RSP_CRC)) + command |= SDHC_CRC_CHECK_ENABLE; + if (ISSET(cmd->c_flags, SCF_RSP_IDX)) + command |= SDHC_INDEX_CHECK_ENABLE; + if (cmd->c_data != NULL) + command |= SDHC_DATA_PRESENT_SELECT; + + if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT)) + command |= SDHC_NO_RESPONSE; + else if (ISSET(cmd->c_flags, SCF_RSP_136)) + command |= SDHC_RESP_LEN_136; + else if (ISSET(cmd->c_flags, SCF_RSP_BSY)) + command |= SDHC_RESP_LEN_48_CHK_BUSY; + else + command |= SDHC_RESP_LEN_48; + + /* Wait until command and data inhibit bits are clear. (1.5) */ + if ((error = sdhc_wait_state(hp, SDHC_CMD_INHIBIT_MASK, 0)) != 0) + return error; + + if( ISSET( hp->flags, SHF_USE_DMA) && cmd->c_datalen > 0 ) + { + cmd->c_resid = blkcount; + cmd->c_buf = cmd->c_data; + + if( ISSET(cmd->c_flags, SCF_CMD_READ) ) + { + dc_invalidaterange(cmd->c_data, cmd->c_datalen); + } else { + dc_flushrange(cmd->c_data, cmd->c_datalen); + ahb_flush_to(AHB_SDHC); + } + HWRITE4(hp, SDHC_DMA_ADDR, (u32)cmd->c_data); + } + + + /* + * Start a CPU data transfer. Writing to the high order byte + * of the SDHC_COMMAND register triggers the SD command. (1.5) + */ + HWRITE2(hp, SDHC_BLOCK_SIZE, blksize | 7<<12); + if (blkcount > 0) + HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount); + HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg); + HWRITE4(hp, SDHC_TRANSFER_MODE, ((u32)command<<16)|mode); +// HWRITE2(hp, SDHC_COMMAND, command); +// HWRITE2(hp, SDHC_TRANSFER_MODE, mode); + + return 0; +} + +void +sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd) +{ + int error; + int status; + + error = 0; + + if (ISSET(hp->flags, SHF_USE_DMA)) { + for(;;) { + status = sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE | + SDHC_DMA_INTERRUPT, + SDHC_TRANSFER_TIMEOUT); + if (!status) { + error = ETIMEDOUT; + break; + } + + if (ISSET(status, SDHC_TRANSFER_COMPLETE)) + { + //dbgprintf("got a TRANSFER_COMPLETE: %08x\n", status); + break; + } + if (ISSET(status, SDHC_DMA_INTERRUPT)) { + // this works because our virtual memory + // addresses are equal to the physical memory + // addresses and because we require the target + // buffer to be contiguous + HWRITE4(hp, SDHC_DMA_ADDR, + HREAD4(hp, SDHC_DMA_ADDR)); + continue; + } + } + } + + + +#ifdef SDHC_DEBUG + /* XXX I forgot why I wanted to know when this happens :-( */ + if ((cmd->c_opcode == 52 || cmd->c_opcode == 53) && + ISSET(MMC_R1(cmd->c_resp), 0xcb00)) + dbgprintf("sdhc: CMD52/53 error response flags %#x\n", + MMC_R1(cmd->c_resp) & 0xff00); +#endif + if (ISSET(cmd->c_flags, SCF_CMD_READ)) + ahb_flush_from( AHB_SDHC ); + + if (error != 0) + cmd->c_error = error; + SET(cmd->c_flags, SCF_ITSDONE); + + return; +} + +/* Prepare for another command. */ +int +sdhc_soft_reset(struct sdhc_host *hp, int mask) +{ + int timo; + + + HWRITE1(hp, SDHC_SOFTWARE_RESET, mask); + for (timo = 10; timo > 0; timo--) { + if (!ISSET(HREAD1(hp, SDHC_SOFTWARE_RESET), mask)) + break; + udelay(10000); + HWRITE1(hp, SDHC_SOFTWARE_RESET, 0); + } + if (timo == 0) { + HWRITE1(hp, SDHC_SOFTWARE_RESET, 0); + return (ETIMEDOUT); + } + return (0); +} + +int +sdhc_wait_intr_debug(const char *funcname, int line, struct sdhc_host *hp, int mask, int timo) +{ + int status; + + mask |= SDHC_ERROR_INTERRUPT; + mask |= SDHC_ERROR_TIMEOUT; + + status = hp->intr_status & mask; + + for (; timo > 0; timo--) + { + sdhc_irq(); // seems backwards but ok + + if (hp->intr_status != 0) { + status = hp->intr_status & mask; + break; + } + udelay(1000); + } + + if (timo == 0) { + status |= SDHC_ERROR_TIMEOUT; + } + hp->intr_status &= ~status; + + //DPRINTF(2,("sdhc: funcname=%s, line=%d, timo=%d status=%#x intr status=%#x error %#x\n", + // funcname, line, timo, status, hp->intr_status, hp->intr_error_status)); + + /* Command timeout has higher priority than command complete. */ + if (ISSET(status, SDHC_ERROR_INTERRUPT)) { + //dbgprintf("resetting due to error interrupt\n"); + //sdhc_dump_regs(hp); + + hp->intr_error_status = 0; + (void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD); + status = 0; + } + + /* Command timeout has higher priority than command complete. */ + if (ISSET(status, SDHC_ERROR_TIMEOUT)) { + //dbgprintf("not resetting due to timeout\n"); + //sdhc_dump_regs(hp); + + hp->intr_error_status = 0; +// (void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD); + status = 0; + } + + return status; +} + +/* + * Established by attachment driver at interrupt priority IPL_SDMMC. + */ +int +sdhc_intr(void) +{ + u_int16_t status; + + //DPRINTF(1,("shdc_intr():\n")); + //sdhc_dump_regs(&sc_host); + + /* Find out which interrupts are pending. */ + status = HREAD2(&sc_host, SDHC_NINTR_STATUS); + if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) { + //DPRINTF(1, ("unknown interrupt\n")); + return 0; + } + + /* Acknowledge the interrupts we are about to handle. */ + HWRITE2(&sc_host, SDHC_NINTR_STATUS, status); + //DPRINTF(2,("sdhc: interrupt status=%d\n", status)); + + /* Service error interrupts. */ + if (ISSET(status, SDHC_ERROR_INTERRUPT)) { + u_int16_t error; + u_int16_t signal; + + /* Acknowledge error interrupts. */ + error = HREAD2(&sc_host, SDHC_EINTR_STATUS); + signal = HREAD2(&sc_host, SDHC_EINTR_SIGNAL_EN); + HWRITE2(&sc_host, SDHC_EINTR_SIGNAL_EN, 0); + (void)sdhc_soft_reset(&sc_host, SDHC_RESET_DAT|SDHC_RESET_CMD); + if (sc_host.data_command == 1) { + sc_host.data_command = 0; + + // TODO: add a way to send commands from irq + // context and uncomment this +// sdmmc_abort(); + } + HWRITE2(&sc_host, SDHC_EINTR_STATUS, error); + HWRITE2(&sc_host, SDHC_EINTR_SIGNAL_EN, signal); + + //DPRINTF(2,("sdhc: error interrupt, status=%d\n", error)); + + if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR| + SDHC_DATA_TIMEOUT_ERROR)) { + sc_host.intr_error_status |= error; + sc_host.intr_status |= status; + } + } + + /* + * Wake up the blocking process to service command + * related interrupt(s). + */ + if (ISSET(status, SDHC_BUFFER_READ_READY| + SDHC_BUFFER_WRITE_READY|SDHC_COMMAND_COMPLETE| + SDHC_TRANSFER_COMPLETE|SDHC_DMA_INTERRUPT)) { + sc_host.intr_status |= status; + } + + /* Service SD card interrupts. */ + if (ISSET(status, SDHC_CARD_INTERRUPT)) { + //DPRINTF(0,("sdhc: card interrupt\n")); + HCLR2(&sc_host, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); + } + return 1; +} + +#ifdef SDHC_DEBUG +void +sdhc_dump_regs(struct sdhc_host *hp) +{ + dbgprintf("0x%02x PRESENT_STATE: %x\n", SDHC_PRESENT_STATE, + HREAD4(hp, SDHC_PRESENT_STATE)); + dbgprintf("0x%02x POWER_CTL: %x\n", SDHC_POWER_CTL, + HREAD1(hp, SDHC_POWER_CTL)); + dbgprintf("0x%02x NINTR_STATUS: %x\n", SDHC_NINTR_STATUS, + HREAD2(hp, SDHC_NINTR_STATUS)); + dbgprintf("0x%02x EINTR_STATUS: %x\n", SDHC_EINTR_STATUS, + HREAD2(hp, SDHC_EINTR_STATUS)); + dbgprintf("0x%02x NINTR_STATUS_EN: %x\n", SDHC_NINTR_STATUS_EN, + HREAD2(hp, SDHC_NINTR_STATUS_EN)); + dbgprintf("0x%02x EINTR_STATUS_EN: %x\n", SDHC_EINTR_STATUS_EN, + HREAD2(hp, SDHC_EINTR_STATUS_EN)); + dbgprintf("0x%02x NINTR_SIGNAL_EN: %x\n", SDHC_NINTR_SIGNAL_EN, + HREAD2(hp, SDHC_NINTR_SIGNAL_EN)); + dbgprintf("0x%02x EINTR_SIGNAL_EN: %x\n", SDHC_EINTR_SIGNAL_EN, + HREAD2(hp, SDHC_EINTR_SIGNAL_EN)); + dbgprintf("0x%02x CAPABILITIES: %x\n", SDHC_CAPABILITIES, + HREAD4(hp, SDHC_CAPABILITIES)); + dbgprintf("0x%02x MAX_CAPABILITIES: %x\n", SDHC_MAX_CAPABILITIES, + HREAD4(hp, SDHC_MAX_CAPABILITIES)); +} +#endif + +#include "hollywood.h" + +void sdhc_irq(void) +{ + sdhc_intr(); +} + +void sdhc_init(void) +{ + sdhc_host_found(0, SDHC_REG_BASE, 1); + //sdhc_host_found(0, SDHC_REG_BASE + 0x100, 1); + //sdhc_host_found(0, 0x0d080000, 1); +} + +void sdhc_exit(void) +{ + sdhc_shutdown(); +} \ No newline at end of file diff --git a/sdhc.h b/sdhc.h new file mode 100644 index 0000000..f9fad9d --- /dev/null +++ b/sdhc.h @@ -0,0 +1,210 @@ +/* $OpenBSD: sdhcvar.h,v 1.3 2007/09/06 08:01:01 jsg Exp $ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * Copyright (c) 2009 Sven Peter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDHCVAR_H_ +#define _SDHCVAR_H_ + +#include "bsdtypes.h" +#ifdef CAN_HAZ_IPC +#include "ipc.h" +#endif +#include "sdmmc.h" +struct sdhc_host { + bus_space_tag_t iot; /* host register set tag */ + bus_space_handle_t ioh; /* host register set handle */ + u_int clkbase; /* base clock frequency in KHz */ + int flags; /* flags for this host */ + u_int32_t ocr; /* OCR value from capabilities */ + u_int8_t regs[14]; /* host controller state */ + u_int16_t intr_status; /* soft interrupt status */ + u_int16_t intr_error_status; /* soft error status */ + int data_command; +}; + +extern struct sdhc_host sc_host; + +/* Host controller functions called by the attachment driver. */ +int sdhc_host_found(bus_space_tag_t, bus_space_handle_t, int); +void sdhc_power(int, void *); +void sdhc_shutdown(void); +int sdhc_intr(void); +void sdhc_init(void); +void sdhc_exit(void); +void sdhc_irq(void); +#ifdef CAN_HAZ_IPC +void sdhc_ipc(volatile ipc_request *req); +#endif + +/* Host standard register set */ +#define SDHC_DMA_ADDR 0x00 +#define SDHC_BLOCK_SIZE 0x04 +#define SDHC_BLOCK_COUNT 0x06 +#define SDHC_BLOCK_COUNT_MAX 512 +#define SDHC_ARGUMENT 0x08 +#define SDHC_TRANSFER_MODE 0x0c +#define SDHC_MULTI_BLOCK_MODE (1<<5) +#define SDHC_READ_MODE (1<<4) +#define SDHC_AUTO_CMD12_ENABLE (1<<2) +#define SDHC_BLOCK_COUNT_ENABLE (1<<1) +#define SDHC_DMA_ENABLE (1<<0) +#define SDHC_COMMAND 0x0e +/* 14-15 reserved */ +#define SDHC_COMMAND_INDEX_SHIFT 8 +#define SDHC_COMMAND_INDEX_MASK 0x3f +#define SDHC_COMMAND_TYPE_ABORT (3<<6) +#define SDHC_COMMAND_TYPE_RESUME (2<<6) +#define SDHC_COMMAND_TYPE_SUSPEND (1<<6) +#define SDHC_COMMAND_TYPE_NORMAL (0<<6) +#define SDHC_DATA_PRESENT_SELECT (1<<5) +#define SDHC_INDEX_CHECK_ENABLE (1<<4) +#define SDHC_CRC_CHECK_ENABLE (1<<3) +/* 2 reserved */ +#define SDHC_RESP_LEN_48_CHK_BUSY (3<<0) +#define SDHC_RESP_LEN_48 (2<<0) +#define SDHC_RESP_LEN_136 (1<<0) +#define SDHC_NO_RESPONSE (0<<0) +#define SDHC_RESPONSE 0x10 /* - 0x1f */ +#define SDHC_DATA 0x20 +#define SDHC_PRESENT_STATE 0x24 +/* 25-31 reserved */ +#define SDHC_CMD_LINE_SIGNAL_LEVEL (1<<24) +#define SDHC_DAT3_LINE_LEVEL (1<<23) +#define SDHC_DAT2_LINE_LEVEL (1<<22) +#define SDHC_DAT1_LINE_LEVEL (1<<21) +#define SDHC_DAT0_LINE_LEVEL (1<<20) +#define SDHC_WRITE_PROTECT_SWITCH (1<<19) +#define SDHC_CARD_DETECT_PIN_LEVEL (1<<18) +#define SDHC_CARD_STATE_STABLE (1<<17) +#define SDHC_CARD_INSERTED (1<<16) +/* 12-15 reserved */ +#define SDHC_BUFFER_READ_ENABLE (1<<11) +#define SDHC_BUFFER_WRITE_ENABLE (1<<10) +#define SDHC_READ_TRANSFER_ACTIVE (1<<9) +#define SDHC_WRITE_TRANSFER_ACTIVE (1<<8) +/* 3-7 reserved */ +#define SDHC_DAT_ACTIVE (1<<2) +#define SDHC_CMD_INHIBIT_DAT (1<<1) +#define SDHC_CMD_INHIBIT_CMD (1<<0) +#define SDHC_CMD_INHIBIT_MASK 0x0003 +#define SDHC_HOST_CTL 0x28 +#define SDHC_HIGH_SPEED (1<<2) +#define SDHC_4BIT_MODE (1<<1) +#define SDHC_LED_ON (1<<0) +#define SDHC_POWER_CTL 0x29 +#define SDHC_VOLTAGE_SHIFT 1 +#define SDHC_VOLTAGE_MASK 0x07 +#define SDHC_VOLTAGE_3_3V 0x07 +#define SDHC_VOLTAGE_3_0V 0x06 +#define SDHC_VOLTAGE_1_8V 0x05 +#define SDHC_BUS_POWER (1<<0) +#define SDHC_BLOCK_GAP_CTL 0x2a +#define SDHC_WAKEUP_CTL 0x2b +#define SDHC_CLOCK_CTL 0x2c +#define SDHC_SDCLK_DIV_SHIFT 8 +#define SDHC_SDCLK_DIV_MASK 0xff +#define SDHC_SDCLK_ENABLE (1<<2) +#define SDHC_INTCLK_STABLE (1<<1) +#define SDHC_INTCLK_ENABLE (1<<0) +#define SDHC_TIMEOUT_CTL 0x2e +#define SDHC_TIMEOUT_MAX 0x0e +#define SDHC_SOFTWARE_RESET 0x2f +#define SDHC_RESET_MASK 0x5 +#define SDHC_RESET_DAT (1<<2) +#define SDHC_RESET_CMD (1<<1) +#define SDHC_RESET_ALL (1<<0) +#define SDHC_NINTR_STATUS 0x30 +#define SDHC_ERROR_INTERRUPT (1<<15) +#define SDHC_ERROR_TIMEOUT (1<<14) +#define SDHC_CARD_INTERRUPT (1<<8) +#define SDHC_CARD_REMOVAL (1<<7) +#define SDHC_CARD_INSERTION (1<<6) +#define SDHC_BUFFER_READ_READY (1<<5) +#define SDHC_BUFFER_WRITE_READY (1<<4) +#define SDHC_DMA_INTERRUPT (1<<3) +#define SDHC_BLOCK_GAP_EVENT (1<<2) +#define SDHC_TRANSFER_COMPLETE (1<<1) +#define SDHC_COMMAND_COMPLETE (1<<0) +#define SDHC_NINTR_STATUS_MASK 0x81ff +#define SDHC_EINTR_STATUS 0x32 +#define SDHC_ADMA_ERROR (1<<9) +#define SDHC_AUTO_CMD12_ERROR (1<<8) +#define SDHC_CURRENT_LIMIT_ERROR (1<<7) +#define SDHC_DATA_END_BIT_ERROR (1<<6) +#define SDHC_DATA_CRC_ERROR (1<<5) +#define SDHC_DATA_TIMEOUT_ERROR (1<<4) +#define SDHC_DATA_ERROR 0x70 +#define SDHC_CMD_INDEX_ERROR (1<<3) +#define SDHC_CMD_END_BIT_ERROR (1<<2) +#define SDHC_CMD_CRC_ERROR (1<<1) +#define SDHC_CMD_TIMEOUT_ERROR (1<<0) +#define SDHC_CMD_ERROR 0x0f +#define SDHC_EINTR_STATUS_MASK 0x03ff /* excluding vendor signals */ +#define SDHC_NINTR_STATUS_EN 0x34 +#define SDHC_EINTR_STATUS_EN 0x36 +#define SDHC_NINTR_SIGNAL_EN 0x38 +#define SDHC_NINTR_SIGNAL_MASK 0x01ff +#define SDHC_EINTR_SIGNAL_EN 0x3a +#define SDHC_EINTR_SIGNAL_MASK 0x03ff /* excluding vendor signals */ +#define SDHC_CMD12_ERROR_STATUS 0x3c +#define SDHC_CAPABILITIES 0x40 +#define SDHC_VOLTAGE_SUPP_1_8V (1<<26) +#define SDHC_VOLTAGE_SUPP_3_0V (1<<25) +#define SDHC_VOLTAGE_SUPP_3_3V (1<<24) +#define SDHC_DMA_SUPPORT (1<<22) +#define SDHC_HIGH_SPEED_SUPP (1<<21) +#define SDHC_BASE_FREQ_SHIFT 8 +#define SDHC_BASE_FREQ_MASK 0x3f +#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */ +#define SDHC_TIMEOUT_FREQ_SHIFT 0 +#define SDHC_TIMEOUT_FREQ_MASK 0x1f +#define SDHC_MAX_CAPABILITIES 0x48 +#define SDHC_SLOT_INTR_STATUS 0xfc +#define SDHC_HOST_CTL_VERSION 0xfe +#define SDHC_SPEC_VERS_SHIFT 0 +#define SDHC_SPEC_VERS_MASK 0xff +#define SDHC_VENDOR_VERS_SHIFT 8 +#define SDHC_VENDOR_VERS_MASK 0xff + +/* SDHC_CAPABILITIES decoding */ +#define SDHC_BASE_FREQ_KHZ(cap) \ + ((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK) * 1000) +#define SDHC_TIMEOUT_FREQ(cap) \ + (((cap) >> SDHC_TIMEOUT_FREQ_SHIFT) & SDHC_TIMEOUT_FREQ_MASK) +#define SDHC_TIMEOUT_FREQ_KHZ(cap) \ + (((cap) & SDHC_TIMEOUT_FREQ_UNIT) ? \ + SDHC_TIMEOUT_FREQ(cap) * 1000: \ + SDHC_TIMEOUT_FREQ(cap)) + +/* SDHC_HOST_CTL_VERSION decoding */ +#define SDHC_SPEC_VERSION(hcv) \ + (((hcv) >> SDHC_SPEC_VERS_SHIFT) & SDHC_SPEC_VERS_MASK) +#define SDHC_VENDOR_VERSION(hcv) \ + (((hcv) >> SDHC_VENDOR_VERS_SHIFT) & SDHC_VENDOR_VERS_MASK) + +struct sdmmc_command; + +int sdhc_host_reset(struct sdhc_host *hp); +int sdhc_card_detect(struct sdhc_host *hp); +int sdhc_bus_power(struct sdhc_host *hp, u_int32_t); +int sdhc_bus_clock(struct sdhc_host *hp, int); +void sdhc_card_intr_mask(struct sdhc_host *hp, int); +void sdhc_card_intr_ack(struct sdhc_host *hp); +void sdhc_exec_command(struct sdhc_host *hp, struct sdmmc_command *); + +#endif diff --git a/sdhcreg.h b/sdhcreg.h new file mode 100644 index 0000000..dd89926 --- /dev/null +++ b/sdhcreg.h @@ -0,0 +1,172 @@ +/* $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDHCREG_H_ +#define _SDHCREG_H_ + +/* Host standard register set */ +#define SDHC_DMA_ADDR 0x00 +#define SDHC_BLOCK_SIZE 0x04 +#define SDHC_BLOCK_COUNT 0x06 +#define SDHC_BLOCK_COUNT_MAX 512 +#define SDHC_ARGUMENT 0x08 +#define SDHC_TRANSFER_MODE 0x0c +#define SDHC_MULTI_BLOCK_MODE (1<<5) +#define SDHC_READ_MODE (1<<4) +#define SDHC_AUTO_CMD12_ENABLE (1<<2) +#define SDHC_BLOCK_COUNT_ENABLE (1<<1) +#define SDHC_DMA_ENABLE (1<<0) +#define SDHC_COMMAND 0x0e +/* 14-15 reserved */ +#define SDHC_COMMAND_INDEX_SHIFT 8 +#define SDHC_COMMAND_INDEX_MASK 0x3f +#define SDHC_COMMAND_TYPE_ABORT (3<<6) +#define SDHC_COMMAND_TYPE_RESUME (2<<6) +#define SDHC_COMMAND_TYPE_SUSPEND (1<<6) +#define SDHC_COMMAND_TYPE_NORMAL (0<<6) +#define SDHC_DATA_PRESENT_SELECT (1<<5) +#define SDHC_INDEX_CHECK_ENABLE (1<<4) +#define SDHC_CRC_CHECK_ENABLE (1<<3) +/* 2 reserved */ +#define SDHC_RESP_LEN_48_CHK_BUSY (3<<0) +#define SDHC_RESP_LEN_48 (2<<0) +#define SDHC_RESP_LEN_136 (1<<0) +#define SDHC_NO_RESPONSE (0<<0) +#define SDHC_RESPONSE 0x10 /* - 0x1f */ +#define SDHC_DATA 0x20 +#define SDHC_PRESENT_STATE 0x24 +/* 25-31 reserved */ +#define SDHC_CMD_LINE_SIGNAL_LEVEL (1<<24) +#define SDHC_DAT3_LINE_LEVEL (1<<23) +#define SDHC_DAT2_LINE_LEVEL (1<<22) +#define SDHC_DAT1_LINE_LEVEL (1<<21) +#define SDHC_DAT0_LINE_LEVEL (1<<20) +#define SDHC_WRITE_PROTECT_SWITCH (1<<19) +#define SDHC_CARD_DETECT_PIN_LEVEL (1<<18) +#define SDHC_CARD_STATE_STABLE (1<<17) +#define SDHC_CARD_INSERTED (1<<16) +/* 12-15 reserved */ +#define SDHC_BUFFER_READ_ENABLE (1<<11) +#define SDHC_BUFFER_WRITE_ENABLE (1<<10) +#define SDHC_READ_TRANSFER_ACTIVE (1<<9) +#define SDHC_WRITE_TRANSFER_ACTIVE (1<<8) +/* 3-7 reserved */ +#define SDHC_DAT_ACTIVE (1<<2) +#define SDHC_CMD_INHIBIT_DAT (1<<1) +#define SDHC_CMD_INHIBIT_CMD (1<<0) +#define SDHC_CMD_INHIBIT_MASK 0x0003 +#define SDHC_HOST_CTL 0x28 +#define SDHC_HIGH_SPEED (1<<2) +#define SDHC_4BIT_MODE (1<<1) +#define SDHC_LED_ON (1<<0) +#define SDHC_POWER_CTL 0x29 +#define SDHC_VOLTAGE_SHIFT 1 +#define SDHC_VOLTAGE_MASK 0x07 +#define SDHC_VOLTAGE_3_3V 0x07 +#define SDHC_VOLTAGE_3_0V 0x06 +#define SDHC_VOLTAGE_1_8V 0x05 +#define SDHC_BUS_POWER (1<<0) +#define SDHC_BLOCK_GAP_CTL 0x2a +#define SDHC_WAKEUP_CTL 0x2b +#define SDHC_CLOCK_CTL 0x2c +#define SDHC_SDCLK_DIV_SHIFT 8 +#define SDHC_SDCLK_DIV_MASK 0xff +#define SDHC_SDCLK_ENABLE (1<<2) +#define SDHC_INTCLK_STABLE (1<<1) +#define SDHC_INTCLK_ENABLE (1<<0) +#define SDHC_TIMEOUT_CTL 0x2e +#define SDHC_TIMEOUT_MAX 0x0e +#define SDHC_SOFTWARE_RESET 0x2f +#define SDHC_RESET_MASK 0x5 +#define SDHC_RESET_DAT (1<<2) +#define SDHC_RESET_CMD (1<<1) +#define SDHC_RESET_ALL (1<<0) +#define SDHC_NINTR_STATUS 0x30 +#define SDHC_ERROR_INTERRUPT (1<<15) +#define SDHC_CARD_INTERRUPT (1<<8) +#define SDHC_CARD_REMOVAL (1<<7) +#define SDHC_CARD_INSERTION (1<<6) +#define SDHC_BUFFER_READ_READY (1<<5) +#define SDHC_BUFFER_WRITE_READY (1<<4) +#define SDHC_DMA_INTERRUPT (1<<3) +#define SDHC_BLOCK_GAP_EVENT (1<<2) +#define SDHC_TRANSFER_COMPLETE (1<<1) +#define SDHC_COMMAND_COMPLETE (1<<0) +#define SDHC_NINTR_STATUS_MASK 0x81ff +#define SDHC_EINTR_STATUS 0x32 +#define SDHC_ADMA_ERROR (1<<9) +#define SDHC_AUTO_CMD12_ERROR (1<<8) +#define SDHC_CURRENT_LIMIT_ERROR (1<<7) +#define SDHC_DATA_END_BIT_ERROR (1<<6) +#define SDHC_DATA_CRC_ERROR (1<<5) +#define SDHC_DATA_TIMEOUT_ERROR (1<<4) +#define SDHC_DATA_ERROR 0x70 +#define SDHC_CMD_INDEX_ERROR (1<<3) +#define SDHC_CMD_END_BIT_ERROR (1<<2) +#define SDHC_CMD_CRC_ERROR (1<<1) +#define SDHC_CMD_TIMEOUT_ERROR (1<<0) +#define SDHC_CMD_ERROR 0x0f +#define SDHC_EINTR_STATUS_MASK 0x03ff /* excluding vendor signals */ +#define SDHC_NINTR_STATUS_EN 0x34 +#define SDHC_EINTR_STATUS_EN 0x36 +#define SDHC_NINTR_SIGNAL_EN 0x38 +#define SDHC_NINTR_SIGNAL_MASK 0x01ff +#define SDHC_EINTR_SIGNAL_EN 0x3a +#define SDHC_EINTR_SIGNAL_MASK 0x03ff /* excluding vendor signals */ +#define SDHC_CMD12_ERROR_STATUS 0x3c +#define SDHC_CAPABILITIES 0x40 +#define SDHC_VOLTAGE_SUPP_1_8V (1<<26) +#define SDHC_VOLTAGE_SUPP_3_0V (1<<25) +#define SDHC_VOLTAGE_SUPP_3_3V (1<<24) +#define SDHC_DMA_SUPPORT (1<<22) +#define SDHC_HIGH_SPEED_SUPP (1<<21) +#define SDHC_MAX_BLK_LEN_512 0 +#define SDHC_MAX_BLK_LEN_1024 1 +#define SDHC_MAX_BLK_LEN_2048 2 +#define SDHC_MAX_BLK_LEN_SHIFT 16 +#define SDHC_MAX_BLK_LEN_MASK 0x3 +#define SDHC_BASE_FREQ_SHIFT 8 +#define SDHC_BASE_FREQ_MASK 0x3f +#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */ +#define SDHC_TIMEOUT_FREQ_SHIFT 0 +#define SDHC_TIMEOUT_FREQ_MASK 0x1f +#define SDHC_MAX_CAPABILITIES 0x48 +#define SDHC_SLOT_INTR_STATUS 0xfc +#define SDHC_HOST_CTL_VERSION 0xfe +#define SDHC_SPEC_VERS_SHIFT 0 +#define SDHC_SPEC_VERS_MASK 0xff +#define SDHC_VENDOR_VERS_SHIFT 8 +#define SDHC_VENDOR_VERS_MASK 0xff + +/* SDHC_CAPABILITIES decoding */ +#define SDHC_BASE_FREQ_KHZ(cap) \ + ((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK) * 1000) +#define SDHC_TIMEOUT_FREQ(cap) \ + (((cap) >> SDHC_TIMEOUT_FREQ_SHIFT) & SDHC_TIMEOUT_FREQ_MASK) +#define SDHC_TIMEOUT_FREQ_KHZ(cap) \ + (((cap) & SDHC_TIMEOUT_FREQ_UNIT) ? \ + SDHC_TIMEOUT_FREQ(cap) * 1000: \ + SDHC_TIMEOUT_FREQ(cap)) + +/* SDHC_HOST_CTL_VERSION decoding */ +#define SDHC_SPEC_VERSION(hcv) \ + (((hcv) >> SDHC_SPEC_VERS_SHIFT) & SDHC_SPEC_VERS_MASK) +#define SDHC_VENDOR_VERSION(hcv) \ + (((hcv) >> SDHC_VENDOR_VERS_SHIFT) & SDHC_VENDOR_VERS_MASK) + +#endif diff --git a/sdhcvar.h b/sdhcvar.h new file mode 100644 index 0000000..03d5e55 --- /dev/null +++ b/sdhcvar.h @@ -0,0 +1,62 @@ +/* $OpenBSD: sdhcvar.h,v 1.3 2007/09/06 08:01:01 jsg Exp $ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * Copyright (c) 2009 Sven Peter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDHCVAR_H_ +#define _SDHCVAR_H_ + +#include "bsdtypes.h" + +#define SDHC_MAX_HOSTS 4 + +struct sdhc_host { + struct sdhc_softc *sc; /* host controller device */ + struct device *sdmmc; /* generic SD/MMC device */ + bus_space_tag_t iot; /* host register set tag */ + bus_space_handle_t ioh; /* host register set handle */ + u_int clkbase; /* base clock frequency in KHz */ + int maxblklen; /* maximum block length */ + int flags; /* flags for this host */ + u_int32_t ocr; /* OCR value from capabilities */ + u_int8_t regs[14]; /* host controller state */ + u_int16_t intr_status; /* soft interrupt status */ + u_int16_t intr_error_status; /* soft error status */ + int data_command; +}; + +struct sdhc_softc { + struct device sc_dev; + struct sdhc_host sc_host[SDHC_MAX_HOSTS]; + int sc_nhosts; + u_int sc_flags; +}; + + +/* Host controller functions called by the attachment driver. */ +int sdhc_host_found(struct sdhc_softc *, bus_space_tag_t, + bus_space_handle_t, int); +void sdhc_power(int, void *); +void sdhc_shutdown(void *); +int sdhc_intr(void *); +void SDHCInit(void); +void sdhc_irq(void); + +/* flag values */ +#define SDHC_F_NOPWR0 (1 << 0) + +#endif diff --git a/sdmmc.c b/sdmmc.c new file mode 100644 index 0000000..991d40f --- /dev/null +++ b/sdmmc.c @@ -0,0 +1,373 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + SD/MMC interface + +Copyright (C) 2008, 2009 Sven Peter + +# This code is licensed to you under the terms of the GNU GPL, version 2; +# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +*/ + +#include "bsdtypes.h" +#include "sdhc.h" +#include "string.h" +#include "utils.h" + +//#define SDMMC_DEBUG + +#ifdef SDMMC_DEBUG +static int sdmmcdebug = 0; +#define DPRINTF(n,s) do { if ((n) <= sdmmcdebug) dbgprintf s; } while (0) +#else +#define DPRINTF(n,s) do {} while(0) +#endif + +struct sdmmc_card { + sdmmc_chipset_handle_t handle; + int inserted; + int sdhc_blockmode; + int selected; + int new_card; // set to 1 everytime a new card is inserted + + u32 timeout; + u32 num_sectors; + u32 cid; + u16 rca; +}; + +#ifdef LOADER +static struct sdmmc_card card; +#else +static struct sdmmc_card card; +#endif + +void sdmmc_attach(sdmmc_chipset_handle_t handle) +{ + memset8(&card, 0, sizeof(card)); + + card.handle = handle; + + //DPRINTF(0, ("sdmmc: attached new SD/MMC card\n")); + + sdhc_host_reset(card.handle); + + if (sdhc_card_detect(card.handle)) { + //DPRINTF(1, ("card is inserted. starting init sequence.\n")); + sdmmc_needs_discover(); + } +} + +void sdmmc_abort(void) { + struct sdmmc_command cmd; + //dbgprintf("abortion kthx\n"); + + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_STOP_TRANSMISSION; + cmd.c_arg = 0; + cmd.c_flags = SCF_RSP_R1B; + sdhc_exec_command(card.handle, &cmd); +} + +void sdmmc_needs_discover(void) +{ + struct sdmmc_command cmd; + u32 ocr; + + //DPRINTF(0, ("sdmmc: card needs discovery.\n")); + sdhc_host_reset(card.handle); + card.new_card = 1; + + if (!sdhc_card_detect(card.handle)) { + //DPRINTF(1, ("sdmmc: card (no longer?) inserted.\n")); + card.inserted = 0; + return; + } + + if (sdhc_bus_power(card.handle, 1) != 0) { + //dbgprintf("sdmmc: powerup failed for card\n"); + goto out; + } + + if (sdhc_bus_clock(card.handle, SDMMC_DEFAULT_CLOCK) != 0) { + //dbgprintf("sdmmc: could not enable clock for card\n"); + goto out_power; + } + + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_GO_IDLE_STATE; + cmd.c_flags = SCF_RSP_R0; + sdhc_exec_command(card.handle, &cmd); + + if (cmd.c_error) { + //dbgprintf("sdmmc: GO_IDLE_STATE failed with %d\n", cmd.c_error); + goto out_clock; + } + + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = SD_SEND_IF_COND; + cmd.c_arg = 0x1aa; + cmd.c_flags = SCF_RSP_R7; + cmd.c_timeout = 100; + sdhc_exec_command(card.handle, &cmd); + + ocr = card.handle->ocr; + if (cmd.c_error || (cmd.c_resp[0] & 0xff) != 0xaa) + ocr &= ~SD_OCR_SDHC_CAP; + else + ocr |= SD_OCR_SDHC_CAP; + + int tries; + for (tries = 100; tries > 0; tries--) { + udelay(100000); + + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_APP_CMD; + cmd.c_arg = 0; + cmd.c_flags = SCF_RSP_R1; + sdhc_exec_command(card.handle, &cmd); + + if (cmd.c_error) + continue; + + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = SD_APP_OP_COND; + cmd.c_arg = ocr; + cmd.c_flags = SCF_RSP_R3; + sdhc_exec_command(card.handle, &cmd); + if (cmd.c_error) + continue; + + if (ISSET(MMC_R1(cmd.c_resp), MMC_OCR_MEM_READY)) + break; + } + if (!ISSET(cmd.c_resp[0], MMC_OCR_MEM_READY)) { + //dbgprintf("sdmmc: card failed to powerup.\n"); + goto out_power; + } + + if (ISSET(MMC_R1(cmd.c_resp), SD_OCR_SDHC_CAP)) + card.sdhc_blockmode = 1; + else + card.sdhc_blockmode = 0; + + u8 *resp; + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_ALL_SEND_CID; + cmd.c_arg = 0; + cmd.c_flags = SCF_RSP_R2; + sdhc_exec_command(card.handle, &cmd); + if (cmd.c_error) { + goto out_clock; + } + + card.cid = MMC_R1(cmd.c_resp); + resp = (u8 *)cmd.c_resp; + + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = SD_SEND_RELATIVE_ADDR; + cmd.c_arg = 0; + cmd.c_flags = SCF_RSP_R6; + sdhc_exec_command(card.handle, &cmd); + if (cmd.c_error) { + //dbgprintf("sdmmc: SD_SEND_RCA failed with %d\n", cmd.c_error); + goto out_clock; + } + + card.rca = MMC_R1(cmd.c_resp)>>16; + + card.selected = 0; + card.inserted = 1; + + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_SEND_CSD; + cmd.c_arg = ((u32)card.rca)<<16; + cmd.c_flags = SCF_RSP_R2; + sdhc_exec_command(card.handle, &cmd); + if (cmd.c_error) { + //dbgprintf("sdmmc: MMC_SEND_CSD failed with %d\n", cmd.c_error); + goto out_power; + } + + resp = (u8 *)cmd.c_resp; + + + if (resp[13] == 0xe) { // sdhc + unsigned int c_size = resp[7] << 16 | resp[6] << 8 | resp[5]; + //dbgprintf("sdmmc: sdhc mode, c_size=%u, card size = %uk\n", c_size, (c_size + 1)* 512); + card.timeout = 250 * 1000000; // spec says read timeout is 100ms and write/erase timeout is 250ms + card.num_sectors = (c_size + 1) * 1024; // number of 512-byte sectors + } + else { + unsigned int taac, nsac, read_bl_len, c_size, c_size_mult; + taac = resp[13]; + nsac = resp[12]; + read_bl_len = resp[9] & 0xF; + + c_size = (resp[8] & 3) << 10; + c_size |= (resp[7] << 2); + c_size |= (resp[6] >> 6); + c_size_mult = (resp[5] & 3) << 1; + c_size_mult |= resp[4] >> 7; + //dbgprintf("taac=%u nsac=%u read_bl_len=%u c_size=%u c_size_mult=%u card size=%u bytes\n", + // taac, nsac, read_bl_len, c_size, c_size_mult, (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len)); + static const unsigned int time_unit[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000}; + static const unsigned int time_value[] = {1, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80}; // must div by 10 + card.timeout = time_unit[taac & 7] * time_value[(taac >> 3) & 0xf] / 10; + //dbgprintf("calculated timeout = %uns\n", card.timeout); + card.num_sectors = (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len) / 512; + } + + sdmmc_select(); + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_SET_BLOCKLEN; + cmd.c_arg = SDMMC_DEFAULT_BLOCKLEN; + cmd.c_flags = SCF_RSP_R1; + sdhc_exec_command(card.handle, &cmd); + if (cmd.c_error) { + //dbgprintf("sdmmc: MMC_SET_BLOCKLEN failed with %d\n", cmd.c_error); + card.inserted = card.selected = 0; + goto out_clock; + } + return; + +out_clock: + sdhc_bus_clock(card.handle, SDMMC_SDCLK_OFF); + +out_power: + sdhc_bus_power(card.handle, 0); +out: + return; +} + + +int sdmmc_select(void) +{ + struct sdmmc_command cmd; + + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_SELECT_CARD; + cmd.c_arg = ((u32)card.rca)<<16; + cmd.c_flags = SCF_RSP_R1B; + sdhc_exec_command(card.handle, &cmd); + + + if (cmd.c_error) + { + return -1; + } + + card.selected = 1; + return 0; +} + +int sdmmc_check_card(void) +{ + if (card.inserted == 0) + return SDMMC_NO_CARD; + + if (card.new_card == 1) + return SDMMC_NEW_CARD; + + return SDMMC_INSERTED; +} + +int sdmmc_ack_card(void) +{ + if (card.new_card == 1) { + card.new_card = 0; + return 0; + } + + return -1; +} + +int sdmmc_read(u32 blk_start, u32 blk_count, void *data) +{ + struct sdmmc_command cmd; + + if (card.inserted == 0) + { + return -1; + } + + if (card.selected == 0) { + if (sdmmc_select() < 0) { + return -1; + } + } + + if (card.new_card == 1) { + return -1; + } + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_READ_BLOCK_MULTIPLE; + if (card.sdhc_blockmode) + cmd.c_arg = blk_start; + else + cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN; + cmd.c_data = data; + cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN; + cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN; + cmd.c_flags = SCF_RSP_R1 | SCF_CMD_READ; + sdhc_exec_command(card.handle, &cmd); + + if (cmd.c_error) + { + return -1; + } + + return 0; +} +int sdmmc_write(u32 blk_start, u32 blk_count, void *data) +{ + struct sdmmc_command cmd; + + if (card.inserted == 0) { + return -1; + } + + if (card.selected == 0) { + if (sdmmc_select() < 0) { + return -1; + } + } + + if (card.new_card == 1) { + return -1; + } + + memset8(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_WRITE_BLOCK_MULTIPLE; + if (card.sdhc_blockmode) + cmd.c_arg = blk_start; + else + cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN; + cmd.c_data = data; + cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN; + cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN; + cmd.c_flags = SCF_RSP_R1; + sdhc_exec_command(card.handle, &cmd); + + if (cmd.c_error) + { + return -1; + } + + return 0; +} + +int sdmmc_get_sectors(void) +{ + if (card.inserted == 0) { + return -1; + } + + if (card.new_card == 1) { + return -1; + } + +// sdhc_error(sdhci->reg_base, "num sectors = %u", sdhci->num_sectors); + + return card.num_sectors; +} + diff --git a/sdmmc.h b/sdmmc.h new file mode 100644 index 0000000..cdd8988 --- /dev/null +++ b/sdmmc.h @@ -0,0 +1,370 @@ +#ifndef __SDMMC_H__ +#define __SDMMC_H__ + +#include "bsdtypes.h" + +struct sdmmc_command; + +typedef struct sdhc_host * sdmmc_chipset_handle_t; + +/* clock frequencies for sdmmc_chip_bus_clock() */ +#define SDMMC_SDCLK_OFF 0 +#define SDMMC_SDCLK_400KHZ 400 +#define SDMMC_SDCLK_25MHZ 25000 + + +struct sdmmc_csd { + int csdver; /* CSD structure format */ + int mmcver; /* MMC version (for CID format) */ + int capacity; /* total number of sectors */ + int sector_size; /* sector size in bytes */ + int read_bl_len; /* block length for reads */ + /* ... */ +}; + +struct sdmmc_cid { + int mid; /* manufacturer identification number */ + int oid; /* OEM/product identification number */ + char pnm[8]; /* product name (MMC v1 has the longest) */ + int rev; /* product revision */ + int psn; /* product serial number */ + int mdt; /* manufacturing date */ +}; + +typedef u_int32_t sdmmc_response[4]; + +struct sdmmc_softc; + +struct sdmmc_task { + void (*func)(void *arg); + void *arg; + int onqueue; + struct sdmmc_softc *sc; +}; + +#define sdmmc_init_task(xtask, xfunc, xarg) do { \ + (xtask)->func = (xfunc); \ + (xtask)->arg = (xarg); \ + (xtask)->onqueue = 0; \ + (xtask)->sc = NULL; \ +} while (0) + +#define sdmmc_task_pending(xtask) ((xtask)->onqueue) + +struct sdmmc_command { +// struct sdmmc_task c_task; /* task queue entry */ + u_int16_t c_opcode; /* SD or MMC command index */ + u_int32_t c_arg; /* SD/MMC command argument */ + sdmmc_response c_resp; /* response buffer */ + void *c_data; /* buffer to send or read into */ + int c_datalen; /* length of data buffer */ + int c_blklen; /* block length */ + int c_flags; /* see below */ +#define SCF_ITSDONE 0x0001 /* command is complete */ +#define SCF_CMD(flags) ((flags) & 0x00f0) +#define SCF_CMD_AC 0x0000 +#define SCF_CMD_ADTC 0x0010 +#define SCF_CMD_BC 0x0020 +#define SCF_CMD_BCR 0x0030 +#define SCF_CMD_READ 0x0040 /* read command (data expected) */ +#define SCF_RSP_BSY 0x0100 +#define SCF_RSP_136 0x0200 +#define SCF_RSP_CRC 0x0400 +#define SCF_RSP_IDX 0x0800 +#define SCF_RSP_PRESENT 0x1000 +/* response types */ +#define SCF_RSP_R0 0 /* none */ +#define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) +#define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136) +#define SCF_RSP_R3 (SCF_RSP_PRESENT) +#define SCF_RSP_R4 (SCF_RSP_PRESENT) +#define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) +#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) + int c_error; /* errno value on completion */ + + int c_timeout; + + /* Host controller owned fields for data xfer in progress */ + int c_resid; /* remaining I/O */ + u_char *c_buf; /* remaining data */ +}; + +/* + * Decoded PC Card 16 based Card Information Structure (CIS), + * per card (function 0) and per function (1 and greater). + */ +struct sdmmc_cis { + u_int16_t manufacturer; +#define SDMMC_VENDOR_INVALID 0xffff + u_int16_t product; +#define SDMMC_PRODUCT_INVALID 0xffff + u_int8_t function; +#define SDMMC_FUNCTION_INVALID 0xff + u_char cis1_major; + u_char cis1_minor; + char cis1_info_buf[256]; + char *cis1_info[4]; +}; + +/* + * Structure describing either an SD card I/O function or a SD/MMC + * memory card from a "stack of cards" that responded to CMD2. For a + * combo card with one I/O function and one memory card, there will be + * two of these structures allocated. Each card slot has such a list + * of sdmmc_function structures. + */ +struct sdmmc_function { + /* common members */ + u_int16_t rca; /* relative card address */ + int flags; +#define SFF_ERROR 0x0001 /* function is poo; ignore it */ +#define SFF_SDHC 0x0002 /* SD High Capacity card */ + /* SD card I/O function members */ + int number; /* I/O function number or -1 */ + struct sdmmc_cis cis; /* decoded CIS */ + /* SD/MMC memory card members */ + struct sdmmc_csd csd; /* decoded CSD value */ + struct sdmmc_cid cid; /* decoded CID value */ + sdmmc_response raw_cid; /* temp. storage for decoding */ +}; + +#define SDMMC_LOCK(sc) lockmgr(&(sc)->sc_lock, LK_EXCLUSIVE, NULL) +#define SDMMC_UNLOCK(sc) lockmgr(&(sc)->sc_lock, LK_RELEASE, NULL) +#define SDMMC_ASSERT_LOCKED(sc) \ + KASSERT(lockstatus(&((sc))->sc_lock) == LK_EXCLUSIVE) + +#ifdef CAN_HAZ_IPC +#include "ipc.h" +#endif + +#define SDMMC_DEFAULT_CLOCK 25000 +#define SDMMC_DEFAULT_BLOCKLEN 512 + +#define SDMMC_NO_CARD 1 +#define SDMMC_NEW_CARD 2 +#define SDMMC_INSERTED 3 + +int sdmmc_write(u32 blk_start, u32 blk_count, void *data); +void sdmmc_attach(sdmmc_chipset_handle_t handle); +void sdmmc_needs_discover(void); +int sdmmc_select(void); +int sdmmc_check_card(void); +int sdmmc_ack_card(void); +int sdmmc_read(u32 blk_start, u32 blk_count, void *data); +#ifdef CAN_HAZ_IPC +void sdmmc_ipc(volatile ipc_request *req); +#endif + +/* MMC commands */ /* response type */ +#define MMC_GO_IDLE_STATE 0 /* R0 */ +#define MMC_SEND_OP_COND 1 /* R3 */ +#define MMC_ALL_SEND_CID 2 /* R2 */ +#define MMC_SET_RELATIVE_ADDR 3 /* R1 */ +#define MMC_SELECT_CARD 7 /* R1 */ +#define MMC_SEND_CSD 9 /* R2 */ +#define MMC_STOP_TRANSMISSION 12 /* R1B */ +#define MMC_SEND_STATUS 13 /* R1 */ +#define MMC_SET_BLOCKLEN 16 /* R1 */ +#define MMC_READ_BLOCK_SINGLE 17 /* R1 */ +#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */ +#define MMC_SET_BLOCK_COUNT 23 /* R1 */ +#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */ +#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */ +#define MMC_APP_CMD 55 /* R1 */ + +/* SD commands */ /* response type */ +#define SD_SEND_RELATIVE_ADDR 3 /* R6 */ +#define SD_SEND_IF_COND 8 /* R7 */ + +/* SD application commands */ /* response type */ +#define SD_APP_SET_BUS_WIDTH 6 /* R1 */ +#define SD_APP_OP_COND 41 /* R3 */ + +/* OCR bits */ +#define MMC_OCR_MEM_READY (1<<31) /* memory power-up status bit */ +#define MMC_OCR_3_5V_3_6V (1<<23) +#define MMC_OCR_3_4V_3_5V (1<<22) +#define MMC_OCR_3_3V_3_4V (1<<21) +#define MMC_OCR_3_2V_3_3V (1<<20) +#define MMC_OCR_3_1V_3_2V (1<<19) +#define MMC_OCR_3_0V_3_1V (1<<18) +#define MMC_OCR_2_9V_3_0V (1<<17) +#define MMC_OCR_2_8V_2_9V (1<<16) +#define MMC_OCR_2_7V_2_8V (1<<15) +#define MMC_OCR_2_6V_2_7V (1<<14) +#define MMC_OCR_2_5V_2_6V (1<<13) +#define MMC_OCR_2_4V_2_5V (1<<12) +#define MMC_OCR_2_3V_2_4V (1<<11) +#define MMC_OCR_2_2V_2_3V (1<<10) +#define MMC_OCR_2_1V_2_2V (1<<9) +#define MMC_OCR_2_0V_2_1V (1<<8) +#define MMC_OCR_1_9V_2_0V (1<<7) +#define MMC_OCR_1_8V_1_9V (1<<6) +#define MMC_OCR_1_7V_1_8V (1<<5) +#define MMC_OCR_1_6V_1_7V (1<<4) + +#define SD_OCR_SDHC_CAP (1<<30) +#define SD_OCR_VOL_MASK 0xFF8000 /* bits 23:15 */ + +/* R1 response type bits */ +#define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */ +#define MMC_R1_APP_CMD (1<<5) /* app. commands supported */ + +/* 48-bit response decoding (32 bits w/o CRC) */ +#define MMC_R1(resp) ((resp)[0]) +#define MMC_R3(resp) ((resp)[0]) +#define SD_R6(resp) ((resp)[0]) + +/* RCA argument and response */ +#define MMC_ARG_RCA(rca) ((rca) << 16) +#define SD_R6_RCA(resp) (SD_R6((resp)) >> 16) + +/* bus width argument */ +#define SD_ARG_BUS_WIDTH_1 0 +#define SD_ARG_BUS_WIDTH_4 2 + +/* MMC R2 response (CSD) */ +#define MMC_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2) +#define MMC_CSD_CSDVER_1_0 1 +#define MMC_CSD_CSDVER_2_0 2 +#define MMC_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4) +#define MMC_CSD_MMCVER_1_0 0 /* MMC 1.0 - 1.2 */ +#define MMC_CSD_MMCVER_1_4 1 /* MMC 1.4 */ +#define MMC_CSD_MMCVER_2_0 2 /* MMC 2.0 - 2.2 */ +#define MMC_CSD_MMCVER_3_1 3 /* MMC 3.1 - 3.3 */ +#define MMC_CSD_MMCVER_4_0 4 /* MMC 4 */ +#define MMC_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4) +#define MMC_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12) +#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \ + (MMC_CSD_C_SIZE_MULT((resp))+2)) +#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3) + +/* MMC v1 R2 response (CID) */ +#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24) +#define MMC_CID_PNM_V1_CPY(resp, pnm) \ + do { \ + (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ + (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ + (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ + (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ + (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ + (pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \ + (pnm)[6] = MMC_RSP_BITS((resp), 48, 8); \ + (pnm)[7] = '\0'; \ + } while (0) +#define MMC_CID_REV_V1(resp) MMC_RSP_BITS((resp), 40, 8) +#define MMC_CID_PSN_V1(resp) MMC_RSP_BITS((resp), 16, 24) +#define MMC_CID_MDT_V1(resp) MMC_RSP_BITS((resp), 8, 8) + +/* MMC v2 R2 response (CID) */ +#define MMC_CID_MID_V2(resp) MMC_RSP_BITS((resp), 120, 8) +#define MMC_CID_OID_V2(resp) MMC_RSP_BITS((resp), 104, 16) +#define MMC_CID_PNM_V2_CPY(resp, pnm) \ + do { \ + (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ + (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ + (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ + (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ + (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ + (pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \ + (pnm)[6] = '\0'; \ + } while (0) +#define MMC_CID_PSN_V2(resp) MMC_RSP_BITS((resp), 16, 32) + +/* SD R2 response (CSD) */ +#define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2) +#define SD_CSD_CSDVER_1_0 0 +#define SD_CSD_CSDVER_2_0 1 +#define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8) +#define SD_CSD_TAAC_1_5_MSEC 0x26 +#define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8) +#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8) +#define SD_CSD_SPEED_25_MHZ 0x32 +#define SD_CSD_SPEED_50_MHZ 0x5a +#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12) +#define SD_CSD_CCC_ALL 0x5f5 +#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4) +#define SD_CSD_READ_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 79, 1) +#define SD_CSD_WRITE_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 78, 1) +#define SD_CSD_READ_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 77, 1) +#define SD_CSD_DSR_IMP(resp) MMC_RSP_BITS((resp), 76, 1) +#define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12) +#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \ + (SD_CSD_C_SIZE_MULT((resp))+2)) +#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22) +#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10) +#define SD_CSD_V2_BL_LEN 0x9 /* 512 */ +#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3) +#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3) +#define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3) +#define SD_CSD_VDD_W_CURR_MAX(resp) MMC_RSP_BITS((resp), 50, 3) +#define SD_CSD_VDD_RW_CURR_100mA 0x7 +#define SD_CSD_VDD_RW_CURR_80mA 0x6 +#define SD_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3) +#define SD_CSD_ERASE_BLK_EN(resp) MMC_RSP_BITS((resp), 46, 1) +#define SD_CSD_SECTOR_SIZE(resp) MMC_RSP_BITS((resp), 39, 7) /* +1 */ +#define SD_CSD_WP_GRP_SIZE(resp) MMC_RSP_BITS((resp), 32, 7) /* +1 */ +#define SD_CSD_WP_GRP_ENABLE(resp) MMC_RSP_BITS((resp), 31, 1) +#define SD_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3) +#define SD_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4) +#define SD_CSD_RW_BL_LEN_2G 0xa +#define SD_CSD_RW_BL_LEN_1G 0x9 +#define SD_CSD_WRITE_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 21, 1) +#define SD_CSD_FILE_FORMAT_GRP(resp) MMC_RSP_BITS((resp), 15, 1) +#define SD_CSD_COPY(resp) MMC_RSP_BITS((resp), 14, 1) +#define SD_CSD_PERM_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 13, 1) +#define SD_CSD_TMP_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 12, 1) +#define SD_CSD_FILE_FORMAT(resp) MMC_RSP_BITS((resp), 10, 2) + +/* SD R2 response (CID) */ +#define SD_CID_MID(resp) MMC_RSP_BITS((resp), 120, 8) +#define SD_CID_OID(resp) MMC_RSP_BITS((resp), 104, 16) +#define SD_CID_PNM_CPY(resp, pnm) \ + do { \ + (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ + (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ + (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ + (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ + (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ + (pnm)[5] = '\0'; \ + } while (0) +#define SD_CID_REV(resp) MMC_RSP_BITS((resp), 56, 8) +#define SD_CID_PSN(resp) MMC_RSP_BITS((resp), 24, 32) +#define SD_CID_MDT(resp) MMC_RSP_BITS((resp), 8, 12) + +/* Might be slow, but it should work on big and little endian systems. */ +#define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len)) +static __inline int +__bitfield(u_int32_t *src, int start, int len) +{ + u_int8_t *sp; + u_int32_t dst, mask; + int shift, bs, bc; + + if (start < 0 || len < 0 || len > 32) + return 0; + + dst = 0; + mask = len % 32 ? UINT_MAX >> (32 - (len % 32)) : UINT_MAX; + shift = 0; + + while (len > 0) { + sp = (u_int8_t *)src + start / 8; + bs = start % 8; + bc = 8 - bs; + if (bc > len) + bc = len; + dst |= (*sp++ >> bs) << shift; + shift += bc; + start += bc; + len -= bc; + } + + dst &= mask; + return (int)dst; +} + +#endif diff --git a/sdmmcchip.h b/sdmmcchip.h new file mode 100644 index 0000000..c67b0bf --- /dev/null +++ b/sdmmcchip.h @@ -0,0 +1,83 @@ +/* $OpenBSD: sdmmcchip.h,v 1.4 2009/02/20 19:16:35 miod Exp $ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDMMC_CHIP_H_ +#define _SDMMC_CHIP_H_ + +struct sdmmc_command; + +typedef struct sdmmc_chip_functions *sdmmc_chipset_tag_t; +typedef void *sdmmc_chipset_handle_t; + +struct sdmmc_chip_functions { + /* host controller reset */ + int (*host_reset)(sdmmc_chipset_handle_t); + /* host capabilities */ + u_int32_t (*host_ocr)(sdmmc_chipset_handle_t); + int (*host_maxblklen)(sdmmc_chipset_handle_t); + /* card detection */ + int (*card_detect)(sdmmc_chipset_handle_t); + /* bus power and clock frequency */ + int (*bus_power)(sdmmc_chipset_handle_t, u_int32_t); + int (*bus_clock)(sdmmc_chipset_handle_t, int); + /* command execution */ + void (*exec_command)(sdmmc_chipset_handle_t, + struct sdmmc_command *); + /* bus width */ + void (*set_bus_width)(sdmmc_chipset_handle_t, int); +}; + +/* host controller reset */ +#define sdmmc_chip_host_reset(tag, handle) \ + ((tag)->host_reset((handle))) +/* host capabilities */ +#define sdmmc_chip_host_ocr(tag, handle) \ + ((tag)->host_ocr((handle))) +#define sdmmc_chip_host_maxblklen(tag, handle) \ + ((tag)->host_maxblklen((handle))) +/* card detection */ +#define sdmmc_chip_card_detect(tag, handle) \ + ((tag)->card_detect((handle))) +/* bus power and clock frequency */ +#define sdmmc_chip_bus_power(tag, handle, ocr) \ + ((tag)->bus_power((handle), (ocr))) +#define sdmmc_chip_bus_clock(tag, handle, freq) \ + ((tag)->bus_clock((handle), (freq))) +/* command execution */ +#define sdmmc_chip_exec_command(tag, handle, cmdp) \ + ((tag)->exec_command((handle), (cmdp))) +/* bus widht */ +#define sdmmc_chip_set_bus_width(tag, handle, enable) \ + ((tag)->set_bus_width((handle), (enable))) + +/* clock frequencies for sdmmc_chip_bus_clock() */ +#define SDMMC_SDCLK_OFF 0 +#define SDMMC_SDCLK_400KHZ 400 +#define SDMMC_SDCLK_25MHZ 25000 + +struct sdmmcbus_attach_args { + const char *saa_busname; + sdmmc_chipset_tag_t sct; + sdmmc_chipset_handle_t sch; + int flags; + long max_xfer; +}; + +void sdmmc_delay(u_int); + +#endif diff --git a/sdmmcreg.h b/sdmmcreg.h new file mode 100644 index 0000000..57248d2 --- /dev/null +++ b/sdmmcreg.h @@ -0,0 +1,232 @@ +/* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDMMCREG_H_ +#define _SDMMCREG_H_ + +/* MMC commands */ /* response type */ +#define MMC_GO_IDLE_STATE 0 /* R0 */ +#define MMC_SEND_OP_COND 1 /* R3 */ +#define MMC_ALL_SEND_CID 2 /* R2 */ +#define MMC_SET_RELATIVE_ADDR 3 /* R1 */ +#define MMC_SELECT_CARD 7 /* R1 */ +#define MMC_SEND_CSD 9 /* R2 */ +#define MMC_STOP_TRANSMISSION 12 /* R1B */ +#define MMC_SEND_STATUS 13 /* R1 */ +#define MMC_SET_BLOCKLEN 16 /* R1 */ +#define MMC_READ_BLOCK_SINGLE 17 /* R1 */ +#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */ +#define MMC_SET_BLOCK_COUNT 23 /* R1 */ +#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */ +#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */ +#define MMC_APP_CMD 55 /* R1 */ + +/* SD commands */ /* response type */ +#define SD_SEND_RELATIVE_ADDR 3 /* R6 */ +#define SD_SEND_IF_COND 8 /* R7 */ + +/* SD application commands */ /* response type */ +#define SD_APP_SET_BUS_WIDTH 6 /* R1 */ +#define SD_APP_OP_COND 41 /* R3 */ + +/* OCR bits */ +#define MMC_OCR_MEM_READY (1<<31) /* memory power-up status bit */ +#define MMC_OCR_3_5V_3_6V (1<<23) +#define MMC_OCR_3_4V_3_5V (1<<22) +#define MMC_OCR_3_3V_3_4V (1<<21) +#define MMC_OCR_3_2V_3_3V (1<<20) +#define MMC_OCR_3_1V_3_2V (1<<19) +#define MMC_OCR_3_0V_3_1V (1<<18) +#define MMC_OCR_2_9V_3_0V (1<<17) +#define MMC_OCR_2_8V_2_9V (1<<16) +#define MMC_OCR_2_7V_2_8V (1<<15) +#define MMC_OCR_2_6V_2_7V (1<<14) +#define MMC_OCR_2_5V_2_6V (1<<13) +#define MMC_OCR_2_4V_2_5V (1<<12) +#define MMC_OCR_2_3V_2_4V (1<<11) +#define MMC_OCR_2_2V_2_3V (1<<10) +#define MMC_OCR_2_1V_2_2V (1<<9) +#define MMC_OCR_2_0V_2_1V (1<<8) +#define MMC_OCR_1_9V_2_0V (1<<7) +#define MMC_OCR_1_8V_1_9V (1<<6) +#define MMC_OCR_1_7V_1_8V (1<<5) +#define MMC_OCR_1_6V_1_7V (1<<4) + +#define SD_OCR_SDHC_CAP (1<<30) +#define SD_OCR_VOL_MASK 0xFF8000 /* bits 23:15 */ + +/* R1 response type bits */ +#define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */ +#define MMC_R1_APP_CMD (1<<5) /* app. commands supported */ + +/* 48-bit response decoding (32 bits w/o CRC) */ +#define MMC_R1(resp) ((resp)[0]) +#define MMC_R3(resp) ((resp)[0]) +#define SD_R6(resp) ((resp)[0]) + +/* RCA argument and response */ +#define MMC_ARG_RCA(rca) ((rca) << 16) +#define SD_R6_RCA(resp) (SD_R6((resp)) >> 16) + +/* bus width argument */ +#define SD_ARG_BUS_WIDTH_1 0 +#define SD_ARG_BUS_WIDTH_4 2 + +/* MMC R2 response (CSD) */ +#define MMC_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2) +#define MMC_CSD_CSDVER_1_0 1 +#define MMC_CSD_CSDVER_2_0 2 +#define MMC_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4) +#define MMC_CSD_MMCVER_1_0 0 /* MMC 1.0 - 1.2 */ +#define MMC_CSD_MMCVER_1_4 1 /* MMC 1.4 */ +#define MMC_CSD_MMCVER_2_0 2 /* MMC 2.0 - 2.2 */ +#define MMC_CSD_MMCVER_3_1 3 /* MMC 3.1 - 3.3 */ +#define MMC_CSD_MMCVER_4_0 4 /* MMC 4 */ +#define MMC_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4) +#define MMC_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12) +#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \ + (MMC_CSD_C_SIZE_MULT((resp))+2)) +#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3) + +/* MMC v1 R2 response (CID) */ +#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24) +#define MMC_CID_PNM_V1_CPY(resp, pnm) \ + do { \ + (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ + (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ + (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ + (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ + (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ + (pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \ + (pnm)[6] = MMC_RSP_BITS((resp), 48, 8); \ + (pnm)[7] = '\0'; \ + } while (0) +#define MMC_CID_REV_V1(resp) MMC_RSP_BITS((resp), 40, 8) +#define MMC_CID_PSN_V1(resp) MMC_RSP_BITS((resp), 16, 24) +#define MMC_CID_MDT_V1(resp) MMC_RSP_BITS((resp), 8, 8) + +/* MMC v2 R2 response (CID) */ +#define MMC_CID_MID_V2(resp) MMC_RSP_BITS((resp), 120, 8) +#define MMC_CID_OID_V2(resp) MMC_RSP_BITS((resp), 104, 16) +#define MMC_CID_PNM_V2_CPY(resp, pnm) \ + do { \ + (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ + (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ + (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ + (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ + (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ + (pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \ + (pnm)[6] = '\0'; \ + } while (0) +#define MMC_CID_PSN_V2(resp) MMC_RSP_BITS((resp), 16, 32) + +/* SD R2 response (CSD) */ +#define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2) +#define SD_CSD_CSDVER_1_0 0 +#define SD_CSD_CSDVER_2_0 1 +#define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8) +#define SD_CSD_TAAC_1_5_MSEC 0x26 +#define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8) +#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8) +#define SD_CSD_SPEED_25_MHZ 0x32 +#define SD_CSD_SPEED_50_MHZ 0x5a +#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12) +#define SD_CSD_CCC_ALL 0x5f5 +#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4) +#define SD_CSD_READ_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 79, 1) +#define SD_CSD_WRITE_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 78, 1) +#define SD_CSD_READ_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 77, 1) +#define SD_CSD_DSR_IMP(resp) MMC_RSP_BITS((resp), 76, 1) +#define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12) +#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \ + (SD_CSD_C_SIZE_MULT((resp))+2)) +#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22) +#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10) +#define SD_CSD_V2_BL_LEN 0x9 /* 512 */ +#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3) +#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3) +#define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3) +#define SD_CSD_VDD_W_CURR_MAX(resp) MMC_RSP_BITS((resp), 50, 3) +#define SD_CSD_VDD_RW_CURR_100mA 0x7 +#define SD_CSD_VDD_RW_CURR_80mA 0x6 +#define SD_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3) +#define SD_CSD_ERASE_BLK_EN(resp) MMC_RSP_BITS((resp), 46, 1) +#define SD_CSD_SECTOR_SIZE(resp) MMC_RSP_BITS((resp), 39, 7) /* +1 */ +#define SD_CSD_WP_GRP_SIZE(resp) MMC_RSP_BITS((resp), 32, 7) /* +1 */ +#define SD_CSD_WP_GRP_ENABLE(resp) MMC_RSP_BITS((resp), 31, 1) +#define SD_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3) +#define SD_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4) +#define SD_CSD_RW_BL_LEN_2G 0xa +#define SD_CSD_RW_BL_LEN_1G 0x9 +#define SD_CSD_WRITE_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 21, 1) +#define SD_CSD_FILE_FORMAT_GRP(resp) MMC_RSP_BITS((resp), 15, 1) +#define SD_CSD_COPY(resp) MMC_RSP_BITS((resp), 14, 1) +#define SD_CSD_PERM_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 13, 1) +#define SD_CSD_TMP_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 12, 1) +#define SD_CSD_FILE_FORMAT(resp) MMC_RSP_BITS((resp), 10, 2) + +/* SD R2 response (CID) */ +#define SD_CID_MID(resp) MMC_RSP_BITS((resp), 120, 8) +#define SD_CID_OID(resp) MMC_RSP_BITS((resp), 104, 16) +#define SD_CID_PNM_CPY(resp, pnm) \ + do { \ + (pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \ + (pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \ + (pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \ + (pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \ + (pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \ + (pnm)[5] = '\0'; \ + } while (0) +#define SD_CID_REV(resp) MMC_RSP_BITS((resp), 56, 8) +#define SD_CID_PSN(resp) MMC_RSP_BITS((resp), 24, 32) +#define SD_CID_MDT(resp) MMC_RSP_BITS((resp), 8, 12) + +/* Might be slow, but it should work on big and little endian systems. */ +#define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len)) +static __inline int +__bitfield(u_int32_t *src, int start, int len) +{ + u_int8_t *sp; + u_int32_t dst, mask; + int shift, bs, bc; + + if (start < 0 || len < 0 || len > 32) + return 0; + + dst = 0; + mask = len % 32 ? UINT_MAX >> (32 - (len % 32)) : UINT_MAX; + shift = 0; + + while (len > 0) { + sp = (u_int8_t *)src + start / 8; + bs = start % 8; + bc = 8 - bs; + if (bc > len) + bc = len; + dst |= (*sp++ >> bs) << shift; + shift += bc; + start += bc; + len -= bc; + } + + dst &= mask; + return (int)dst; +} + +#endif + diff --git a/sdmmcvar.h b/sdmmcvar.h new file mode 100644 index 0000000..80823dd --- /dev/null +++ b/sdmmcvar.h @@ -0,0 +1,182 @@ +/* $OpenBSD: sdmmcvar.h,v 1.16 2009/04/07 16:35:52 blambert Exp $ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * Copyright (c) 2009 Sven Peter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDMMCVAR_H_ +#define _SDMMCVAR_H_ + +struct sdmmc_csd { + int csdver; /* CSD structure format */ + int mmcver; /* MMC version (for CID format) */ + int capacity; /* total number of sectors */ + int sector_size; /* sector size in bytes */ + int read_bl_len; /* block length for reads */ + /* ... */ +}; + +struct sdmmc_cid { + int mid; /* manufacturer identification number */ + int oid; /* OEM/product identification number */ + char pnm[8]; /* product name (MMC v1 has the longest) */ + int rev; /* product revision */ + int psn; /* product serial number */ + int mdt; /* manufacturing date */ +}; + +typedef u_int32_t sdmmc_response[4]; + +struct sdmmc_softc; + +struct sdmmc_task { + void (*func)(void *arg); + void *arg; + int onqueue; + struct sdmmc_softc *sc; +}; + +#define sdmmc_init_task(xtask, xfunc, xarg) do { \ + (xtask)->func = (xfunc); \ + (xtask)->arg = (xarg); \ + (xtask)->onqueue = 0; \ + (xtask)->sc = NULL; \ +} while (0) + +#define sdmmc_task_pending(xtask) ((xtask)->onqueue) + +struct sdmmc_command { +// struct sdmmc_task c_task; /* task queue entry */ + u_int16_t c_opcode; /* SD or MMC command index */ + u_int32_t c_arg; /* SD/MMC command argument */ + sdmmc_response c_resp; /* response buffer */ + void *c_data; /* buffer to send or read into */ + int c_datalen; /* length of data buffer */ + int c_blklen; /* block length */ + int c_flags; /* see below */ +#define SCF_ITSDONE 0x0001 /* command is complete */ +#define SCF_CMD(flags) ((flags) & 0x00f0) +#define SCF_CMD_AC 0x0000 +#define SCF_CMD_ADTC 0x0010 +#define SCF_CMD_BC 0x0020 +#define SCF_CMD_BCR 0x0030 +#define SCF_CMD_READ 0x0040 /* read command (data expected) */ +#define SCF_RSP_BSY 0x0100 +#define SCF_RSP_136 0x0200 +#define SCF_RSP_CRC 0x0400 +#define SCF_RSP_IDX 0x0800 +#define SCF_RSP_PRESENT 0x1000 +/* response types */ +#define SCF_RSP_R0 0 /* none */ +#define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) +#define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136) +#define SCF_RSP_R3 (SCF_RSP_PRESENT) +#define SCF_RSP_R4 (SCF_RSP_PRESENT) +#define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) +#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) + int c_error; /* errno value on completion */ + + /* Host controller owned fields for data xfer in progress */ + int c_resid; /* remaining I/O */ + u_char *c_buf; /* remaining data */ +}; + +/* + * Decoded PC Card 16 based Card Information Structure (CIS), + * per card (function 0) and per function (1 and greater). + */ +struct sdmmc_cis { + u_int16_t manufacturer; +#define SDMMC_VENDOR_INVALID 0xffff + u_int16_t product; +#define SDMMC_PRODUCT_INVALID 0xffff + u_int8_t function; +#define SDMMC_FUNCTION_INVALID 0xff + u_char cis1_major; + u_char cis1_minor; + char cis1_info_buf[256]; + char *cis1_info[4]; +}; + +/* + * Structure describing either an SD card I/O function or a SD/MMC + * memory card from a "stack of cards" that responded to CMD2. For a + * combo card with one I/O function and one memory card, there will be + * two of these structures allocated. Each card slot has such a list + * of sdmmc_function structures. + */ +struct sdmmc_function { + /* common members */ + struct sdmmc_softc *sc; /* card slot softc */ + u_int16_t rca; /* relative card address */ + int flags; +#define SFF_ERROR 0x0001 /* function is poo; ignore it */ +#define SFF_SDHC 0x0002 /* SD High Capacity card */ + /* SD card I/O function members */ + int number; /* I/O function number or -1 */ + struct device *child; /* function driver */ + struct sdmmc_cis cis; /* decoded CIS */ + /* SD/MMC memory card members */ + struct sdmmc_csd csd; /* decoded CSD value */ + struct sdmmc_cid cid; /* decoded CID value */ + sdmmc_response raw_cid; /* temp. storage for decoding */ +}; + +/* + * Structure describing a single SD/MMC/SDIO card slot. + */ +struct sdmmc_softc { + struct device sc_dev; /* base device */ +#define SDMMCDEVNAME(sc) ((sc)->sc_dev.dv_xname) + sdmmc_chipset_tag_t sct; /* host controller chipset tag */ + sdmmc_chipset_handle_t sch; /* host controller chipset handle */ + int sc_flags; +#define SMF_SD_MODE 0x0001 /* host in SD mode (MMC otherwise) */ +#define SMF_IO_MODE 0x0002 /* host in I/O mode (SD mode only) */ +#define SMF_MEM_MODE 0x0004 /* host in memory mode (SD or MMC) */ +#define SMF_CARD_PRESENT 0x0010 /* card presence noticed */ +#define SMF_CARD_ATTACHED 0x0020 /* card driver(s) attached */ +#define SMF_STOP_AFTER_MULTIPLE 0x0040 /* send a stop after a multiple cmd */ + int sc_function_count; /* number of I/O functions (SDIO) */ + struct sdmmc_function *sc_card; /* selected card */ + struct sdmmc_function *sc_fn0; /* function 0, the card itself */ + int sc_dying; /* bus driver is shutting down */ + struct proc *sc_task_thread; /* asynchronous tasks */ + struct sdmmc_task sc_discover_task; /* card attach/detach task */ + struct sdmmc_task sc_intr_task; /* card interrupt task */ + void *sc_scsibus; /* SCSI bus emulation softc */ + long sc_max_xfer; /* maximum transfer size */ +}; + +/* + * Attach devices at the sdmmc bus. + */ +struct sdmmc_attach_args { + struct scsi_link *scsi_link; /* XXX */ + struct sdmmc_function *sf; +}; + +#define IPL_SDMMC IPL_BIO + +#define SDMMC_LOCK(sc) lockmgr(&(sc)->sc_lock, LK_EXCLUSIVE, NULL) +#define SDMMC_UNLOCK(sc) lockmgr(&(sc)->sc_lock, LK_RELEASE, NULL) +#define SDMMC_ASSERT_LOCKED(sc) \ + KASSERT(lockstatus(&((sc))->sc_lock) == LK_EXCLUSIVE) + +#endif diff --git a/usb.h b/usb.h deleted file mode 100644 index fdc4aff..0000000 --- a/usb.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef __USB_H__ -#define __USB_H__ - - -#define USB_MAXPATH IPC_MAXPATH_LEN - -#define USB_OK 0 -#define USB_FAILED 1 - -/* Descriptor types */ -#define USB_DT_DEVICE 0x01 -#define USB_DT_CONFIG 0x02 -#define USB_DT_STRING 0x03 -#define USB_DT_INTERFACE 0x04 -#define USB_DT_ENDPOINT 0x05 - -/* Standard requests */ -#define USB_REQ_GETSTATUS 0x00 -#define USB_REQ_CLEARFEATURE 0x01 -#define USB_REQ_SETFEATURE 0x03 -#define USB_REQ_SETADDRESS 0x05 -#define USB_REQ_GETDESCRIPTOR 0x06 -#define USB_REQ_SETDESCRIPTOR 0x07 -#define USB_REQ_GETCONFIG 0x08 -#define USB_REQ_SETCONFIG 0x09 -#define USB_REQ_GETINTERFACE 0x0a -#define USB_REQ_SETINTERFACE 0x0b -#define USB_REQ_SYNCFRAME 0x0c - -/* Descriptor sizes per descriptor type */ -#define USB_DT_DEVICE_SIZE 18 -#define USB_DT_CONFIG_SIZE 9 -#define USB_DT_INTERFACE_SIZE 9 -#define USB_DT_ENDPOINT_SIZE 7 -#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ -#define USB_DT_HUB_NONVAR_SIZE 7 - -/* control message request type bitmask */ -#define USB_CTRLTYPE_DIR_HOST2DEVICE (0<<7) -#define USB_CTRLTYPE_DIR_DEVICE2HOST (1<<7) -#define USB_CTRLTYPE_TYPE_STANDARD (0<<5) -#define USB_CTRLTYPE_TYPE_CLASS (1<<5) -#define USB_CTRLTYPE_TYPE_VENDOR (2<<5) -#define USB_CTRLTYPE_TYPE_RESERVED (3<<5) -#define USB_CTRLTYPE_REC_DEVICE 0 -#define USB_CTRLTYPE_REC_INTERFACE 1 -#define USB_CTRLTYPE_REC_ENDPOINT 2 -#define USB_CTRLTYPE_REC_OTHER 3 - -#define USB_FEATURE_ENDPOINT_HALT 0 - -#define USB_ENDPOINT_IN 0x80 -#define USB_ENDPOINT_OUT 0x00 - - -#ifdef __cplusplus - extern "C" { -#endif /* __cplusplus */ -# define ATTRIBUTE_PACKED __attribute__((packed)) - -typedef struct _usbctrlrequest { - u8 bRequestType; - u8 bRequest; - u16 wValue; - u16 wIndex; - u16 wLength; -} ATTRIBUTE_PACKED usbctrlrequest; - -typedef struct _usbendpointdesc -{ - u8 bLength; - u8 bDescriptorType; - u8 bEndpointAddress; - u8 bmAttributes; - u16 wMaxPacketSize; - u8 bInterval; -} ATTRIBUTE_PACKED usb_endpointdesc; - -typedef struct _usbinterfacedesc -{ - u8 bLength; - u8 bDescriptorType; - u8 bInterfaceNumber; - u8 bAlternateSetting; - u8 bNumEndpoints; - u8 bInterfaceClass; - u8 bInterfaceSubClass; - u8 bInterfaceProtocol; - u8 iInterface; - struct _usbendpointdesc *endpoints; -} ATTRIBUTE_PACKED usb_interfacedesc; - -typedef struct _usbconfdesc -{ - u8 bLength; - u8 bDescriptorType; - u16 wTotalLength; - u8 bNumInterfaces; - u8 bConfigurationValue; - u8 iConfiguration; - u8 bmAttributes; - u8 bMaxPower; - struct _usbinterfacedesc *interfaces; -} ATTRIBUTE_PACKED usb_configurationdesc; - -typedef struct _usbdevdesc -{ - u8 bLength; - u8 bDescriptorType; - u16 bcdUSB; - u8 bDeviceClass; - u8 bDeviceSubClass; - u8 bDeviceProtocol; - u8 bMaxPacketSize0; - u16 idVendor; - u16 idProduct; - u16 bcdDevice; - u8 iManufacturer; - u8 iProduct; - u8 iSerialNumber; - u8 bNumConfigurations; - struct _usbconfdesc *configurations; -} ATTRIBUTE_PACKED usb_devdesc; - -struct ehci_device; - -s32 USB_OpenDevice(const char *device,u16 vid,u16 pid,struct ehci_device **fd); -s32 USB_CloseDevice(struct ehci_device **fd); - -s32 USB_GetDescriptors(struct ehci_device *fd, usb_devdesc *udd); -void USB_FreeDescriptors(usb_devdesc *udd); - -s32 USB_GetDeviceDescription(struct ehci_device *fd,usb_devdesc *devdesc); - -void USB_SuspendDevice(struct ehci_device *fd); -void USB_ResumeDevice(struct ehci_device *fd); - -s32 USB_ReadIntrMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData); - -s32 USB_ReadBlkMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData); - -s32 USB_ReadCtrlMsg(struct ehci_device *fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData); - -s32 USB_WriteIntrMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData); - -s32 USB_WriteBlkMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData); - -s32 USB_WriteCtrlMsg(struct ehci_device *fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData); - -s32 USB_GetConfiguration(struct ehci_device *fd, u8 *configuration); -s32 USB_SetConfiguration(struct ehci_device *fd, u8 configuration); -s32 USB_SetAlternativeInterface(struct ehci_device *fd, u8 interface, u8 alternateSetting); -s32 USB_ClearHalt(struct ehci_device *fd, u8 endpointAddress); -s32 USB_GetDeviceList(const char *devpath,void *descr_buffer,u8 num_descr,u8 b0,u8 *cnt_descr); - -/* alloc memory from the USB subsystem */ -void * USB_Alloc(int size); -void USB_Free(void *ptr); - -#ifdef __cplusplus - } -#endif /* __cplusplus */ - - -#endif diff --git a/usbstorage.h b/usbstorage.h deleted file mode 100644 index 9f5f29f..0000000 --- a/usbstorage.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef __USBSTORAGE_H__ -#define __USBSTORAGE_H__ - - -#ifdef __cplusplus - extern "C" { -#endif /* __cplusplus */ - -#include "ehci.h" - - -#define USBSTORAGE_OK 0 -#define USBSTORAGE_ENOINTERFACE -10000 -#define USBSTORAGE_ESENSE -10001 -#define USBSTORAGE_ESHORTWRITE -10002 -#define USBSTORAGE_ESHORTREAD -10003 -#define USBSTORAGE_ESIGNATURE -10004 -#define USBSTORAGE_ETAG -10005 -#define USBSTORAGE_ESTATUS -10006 -#define USBSTORAGE_EDATARESIDUE -10007 -#define USBSTORAGE_ETIMEDOUT -ETIMEDOUT -#define USBSTORAGE_EINIT -10009 - -typedef struct -{ - u8 configuration; - u32 interface; - u32 altInterface; - - u8 ep_in; - u8 ep_out; - - u8 max_lun; - u32 sector_size[16]; - u32 n_sector[16]; - - struct ehci_device * usb_fd; - - //mutex_t lock; - //cond_t cond; - s32 retval; - - u32 tag; - u8 suspended; - - u8 *buffer; -} usbstorage_handle; - -s32 USBStorage_Initialize(void); - -s32 USBStorage_Open(usbstorage_handle *dev, struct ehci_device *fd); -s32 USBStorage_Close(usbstorage_handle *dev); -s32 USBStorage_Reset(usbstorage_handle *dev); - -s32 USBStorage_GetMaxLUN(usbstorage_handle *dev); -s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun); -s32 USBStorage_Suspend(usbstorage_handle *dev); - -s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors); -s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer); -s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer); -s32 USBStorage_Inquiry(usbstorage_handle *dev, u8 lun); - -#define DEVICE_TYPE_WII_USB (('W'<<24)|('U'<<16)|('S'<<8)|'B') - -s32 USBStorage_Try_Device(struct ehci_device *fd); - -#ifdef __cplusplus - } -#endif /* __cplusplus */ - - -#endif /* __USBSTORAGE_H__ */