dml
git-svn-id: svn://localhost/Users/andi/Downloads/code/DML@30 be6c1b03-d731-4111-a574-e37d80d43941
This commit is contained in:
parent
206dff56e5
commit
82602a7ff0
22
Card.c
22
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 ) )
|
||||
@ -90,7 +104,7 @@ 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;
|
||||
|
8
Config.c
8
Config.c
@ -9,13 +9,13 @@ 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 );
|
||||
|
||||
@ -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
|
||||
|
1
Config.h
1
Config.h
@ -3,7 +3,6 @@
|
||||
|
||||
#include "string.h"
|
||||
#include "global.h"
|
||||
#include "ipc.h"
|
||||
#include "alloc.h"
|
||||
#include "vsprintf.h"
|
||||
#include "HW.h"
|
||||
|
18
DVDPatches.c
18
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
|
||||
|
1
HW.h
1
HW.h
@ -4,7 +4,6 @@
|
||||
#include "string.h"
|
||||
#include "global.h"
|
||||
#include "memory.h"
|
||||
#include "ipc.h"
|
||||
|
||||
#include "alloc.h"
|
||||
#include "dip.h"
|
||||
|
@ -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 )
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include "string.h"
|
||||
#include "global.h"
|
||||
#include "ipc.h"
|
||||
#include "alloc.h"
|
||||
#include "ff.h"
|
||||
#include "vsprintf.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;
|
||||
|
6
dip.c
6
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;
|
||||
|
2
global.h
2
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
|
||||
|
67
ipc.h
67
ipc.h
@ -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
|
1
main.c
1
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"
|
||||
|
1
memory.h
1
memory.h
@ -3,7 +3,6 @@
|
||||
|
||||
#include "string.h"
|
||||
#include "global.h"
|
||||
#include "ipc.h"
|
||||
#include "utils.h"
|
||||
#include "hollywood.h"
|
||||
#include "vsprintf.h"
|
||||
|
854
sdhc.c
Normal file
854
sdhc.c
Normal file
@ -0,0 +1,854 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
|
||||
*
|
||||
* 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();
|
||||
}
|
210
sdhc.h
Normal file
210
sdhc.h
Normal file
@ -0,0 +1,210 @@
|
||||
/* $OpenBSD: sdhcvar.h,v 1.3 2007/09/06 08:01:01 jsg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
|
||||
*
|
||||
* 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
|
172
sdhcreg.h
Normal file
172
sdhcreg.h
Normal file
@ -0,0 +1,172 @@
|
||||
/* $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
*
|
||||
* 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
|
62
sdhcvar.h
Normal file
62
sdhcvar.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* $OpenBSD: sdhcvar.h,v 1.3 2007/09/06 08:01:01 jsg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
|
||||
*
|
||||
* 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
|
373
sdmmc.c
Normal file
373
sdmmc.c
Normal file
@ -0,0 +1,373 @@
|
||||
/*
|
||||
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
|
||||
SD/MMC interface
|
||||
|
||||
Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
|
||||
|
||||
# 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;
|
||||
}
|
||||
|
370
sdmmc.h
Normal file
370
sdmmc.h
Normal file
@ -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
|
83
sdmmcchip.h
Normal file
83
sdmmcchip.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* $OpenBSD: sdmmcchip.h,v 1.4 2009/02/20 19:16:35 miod Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
*
|
||||
* 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
|
232
sdmmcreg.h
Normal file
232
sdmmcreg.h
Normal file
@ -0,0 +1,232 @@
|
||||
/* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
*
|
||||
* 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
|
||||
|
182
sdmmcvar.h
Normal file
182
sdmmcvar.h
Normal file
@ -0,0 +1,182 @@
|
||||
/* $OpenBSD: sdmmcvar.h,v 1.16 2009/04/07 16:35:52 blambert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
|
||||
*
|
||||
* 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
|
165
usb.h
165
usb.h
@ -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
|
73
usbstorage.h
73
usbstorage.h
@ -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__ */
|
Loading…
Reference in New Issue
Block a user