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__ */