proper CSD handling, so we can detect SD card capacity

and format the card appropriately for BackupMii
This commit is contained in:
bushing 2009-03-18 04:38:19 -07:00
parent aed064fa37
commit 12ac9bc4eb
3 changed files with 39 additions and 65 deletions

1
ipc.h
View File

@ -43,6 +43,7 @@
#define IPC_SD_GETSTATE 0x0002 #define IPC_SD_GETSTATE 0x0002
#define IPC_SD_READ 0x0003 #define IPC_SD_READ 0x0003
#define IPC_SD_WRITE 0x0004 #define IPC_SD_WRITE 0x0004
#define IPC_SD_GETSIZE 0x0005
#define IPC_KEYS_GETOTP 0x0000 #define IPC_KEYS_GETOTP 0x0000
#define IPC_KEYS_GETEEP 0x0001 #define IPC_KEYS_GETEEP 0x0001

65
sdhc.c
View File

@ -833,42 +833,45 @@ static int __sd_getcid(sdhci_t *sdhci) {
} }
static int __sd_getcsd(sdhci_t *sdhci) { static int __sd_getcsd(sdhci_t *sdhci) {
u32 resp[4]; u8 resp[16];
u32 swapped[4]; sdhc_debug(sdhci->reg_base, "requesting CSD");
sdhc_debug(sdhci->reg_base, "requesting CSD noW!!"); int retval = __sd_cmd(sdhci, SD_CMD_SEND_CSD, SD_R2, sdhci->rca << 16, 0, NULL, (u32 *)resp, 16);
int retval = __sd_cmd(sdhci, SD_CMD_SEND_CSD, SD_R2, sdhci->rca << 16, 0, NULL, resp, 16);
if (retval < 0) { if (retval < 0) {
sdhc_error(sdhci->reg_base, "failed to get CSD register (%d)", retval); sdhc_error(sdhci->reg_base, "failed to get CSD register (%d)", retval);
__sd_reset(sdhci, 1); __sd_reset(sdhci, 1);
return SDHC_EIO; return SDHC_EIO;
} }
swapped[0] = bswap32(resp[3]); sdhc_error(sdhci->reg_base, "CSD = %02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x",
swapped[1] = bswap32(resp[2]); resp[14], resp[13], resp[12], resp[11], resp[10], resp[9], resp[8],
swapped[2] = bswap32(resp[1]); resp[7], resp[6], resp[5], resp[4], resp[3], resp[2], resp[1], resp[0]);
swapped[3] = bswap32(resp[0]);
memcpy(&sdhci->csd, swapped, sizeof swapped); if (resp[13] == 0xe) { // sdhc
sdhc_error(sdhci->reg_base, "CSD = %08x%08x%08x%08x", swapped[0], swapped[1], swapped[2], swapped[3]); unsigned int c_size = resp[7] << 16 | resp[6] << 8 | resp[5];
unsigned int card_size = 0; // in kilobytes, so as to not overflow sdhc_error(sdhci->reg_base, "sdhc mode, c_size=%u, card size = %uk", c_size, (c_size + 1)* 512);
sdhc_error(sdhci->reg_base, "CSD: csd_structure=%x taac=%x nsac=%x tran_speed=%x", sdhci->timeout = 250 * 1000000; // spec says read timeout is 100ms and write/erase timeout is 250ms
sdhci->csd.csd_structure, sdhci->csd.taac, sdhci->csd.nsac, sdhci->csd.tran_speed); sdhci->num_sectors = (c_size + 1) * 1024; // number of 512-byte sectors
sdhc_error(sdhci->reg_base, "CSD: ccc=%x read_bl_len=%x read_bl_partial=%x write_blk_misalign=%x", }
sdhci->csd.ccc, sdhci->csd.read_bl_len, sdhci->csd.read_bl_partial, sdhci->csd.write_blk_misalign); else {
if (sdhci->csd.csd_structure) { // SDHC unsigned int taac, nsac, read_bl_len, c_size, c_size_mult;
sdhc_error(sdhci->reg_base, "CSD: read_blk_misalign=%x dsr_imp=%x c_size_hc=%x", taac = resp[13];
sdhci->csd.read_blk_misalign, sdhci->csd.dsr_imp, sdhci->csd.c_size_hc); nsac = resp[12];
// card_size = (sdhci->csd.c_size_hc + 1) * 512; read_bl_len = resp[9] & 0xF;
card_size = ((swapped[2] >> 16) | ((swapped[1] & 0x3f) << 16)) * 512;
} else { c_size = (resp[8] & 3) << 10;
sdhc_error(sdhci->reg_base, "CSD: read_blk_misalign=%x dsr_imp=%x c_size=%x c_size_mult=%x", c_size |= (resp[7] << 2);
sdhci->csd.read_blk_misalign, sdhci->csd.dsr_imp, sdhci->csd.c_size, sdhci->csd.c_size_mult); c_size |= (resp[6] >> 6);
// card_size = (sdhci->csd.c_size + 1) * (4 << sdhci->csd.c_size_mult) * (1 << sdhci->csd.read_bl_len) / 1024; c_size_mult = (resp[5] & 3) << 1;
unsigned int c_size = (swapped[1] & 3) << 10 | (swapped[2] >> 22); c_size_mult |= resp[4] >> 7;
unsigned int c_size_mult = (swapped[2] >> 15) & 7; sdhc_error(sdhci->reg_base, "taac=%u nsac=%u read_bl_len=%u c_size=%u c_size_mult=%u card size=%u bytes",
sdhc_error(sdhci->reg_base, "calc c_size=%x, c_size_mult=%x", c_size, c_size_mult); taac, nsac, read_bl_len, c_size, c_size_mult, (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len));
card_size = (c_size + 1) * (4 << c_size_mult) * (1 << sdhci->csd.read_bl_len) / 1024; unsigned int time_unit[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
unsigned int time_value[] = {1, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80}; // must div by 10
sdhci->timeout = time_unit[taac & 7] * time_value[(taac >> 3) & 0xf] / 10;
sdhc_error(sdhci->reg_base, "calculated timeout = %uns", sdhci->timeout);
sdhci->num_sectors = (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len) / 512;
} }
sdhc_error(sdhci->reg_base, "card size = %uK (%uM)", card_size, card_size / 1024); sdhc_error(sdhci->reg_base, "num sectors = %u", sdhci->num_sectors);
return 0; return 0;
} }
@ -1176,6 +1179,10 @@ void sd_ipc(volatile ipc_request *req)
ipc_post(req->code, req->tag, 1, retval); ipc_post(req->code, req->tag, 1, retval);
break; break;
case IPC_SD_GETSIZE:
ipc_post(req->code, req->tag, 1, sdhci.num_sectors);
break;
default: default:
gecko_printf("IPC: unknown SLOW SDHC request %04x\n", gecko_printf("IPC: unknown SLOW SDHC request %04x\n",
req->req); req->req);

38
sdhc.h
View File

@ -33,41 +33,6 @@ typedef struct {
unsigned short mdt; unsigned short mdt;
} __attribute__((packed)) cid_str; } __attribute__((packed)) cid_str;
typedef struct {
unsigned char dummy;
unsigned csd_structure : 2;
unsigned reserved0 : 6;
unsigned char taac;
unsigned char nsac;
unsigned char tran_speed;
unsigned ccc : 12;
unsigned read_bl_len : 4;
unsigned read_bl_partial : 1;
unsigned write_blk_misalign : 1;
unsigned read_blk_misalign : 1;
unsigned dsr_imp : 1;
union {
struct {
unsigned reserved : 2;
unsigned c_size : 12;
unsigned vdd_r_curr_min : 3;
unsigned vdd_r_curr_max : 3;
unsigned vdd_w_curr_min : 3;
unsigned vdd_w_curr_max : 3;
unsigned c_size_mult : 3;
};
struct {
unsigned reserved2 : 6;
unsigned c_size_hc : 22;
unsigned reserved3 : 1;
};
};
unsigned erase_blk_en : 1;
unsigned sector_size : 7;
unsigned wp_grp_size : 7;
unsigned int stuff;
} __attribute__((packed)) csd_str;
typedef struct typedef struct
{ {
u32 reg_base; u32 reg_base;
@ -80,7 +45,8 @@ typedef struct
u32 ocr; u32 ocr;
cid_str cid; cid_str cid;
csd_str csd; u32 timeout;
u32 num_sectors;
} sdhci_t; } sdhci_t;
int sd_init(sdhci_t *sdhci, int slot); int sd_init(sdhci_t *sdhci, int slot);