diff --git a/ipl/mmc.h b/ipl/mmc.h index ccf672e..a3beea6 100755 --- a/ipl/mmc.h +++ b/ipl/mmc.h @@ -289,6 +289,7 @@ c : clear by read #define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ #define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */ #define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */ +#define EXT_CSD_DEVICE_VERSION 262 /* RO, 2 bytes */ #define EXT_CSD_PRE_EOL_INFO 267 /* RO */ #define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */ #define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */ diff --git a/ipl/sd.h b/ipl/sd.h index f8c0d4b..2827359 100755 --- a/ipl/sd.h +++ b/ipl/sd.h @@ -35,10 +35,11 @@ #define SD_APP_SEND_SCR 51 /* adtc R1 */ /* OCR bit definitions */ -#define SD_OCR_S18R (1 << 24) /* 1.8V switching request */ -#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */ -#define SD_OCR_XPC (1 << 28) /* SDXC power control */ -#define SD_OCR_CCS (1 << 30) /* Card Capacity Status */ +#define SD_OCR_S18R (1 << 24) /* 1.8V switching request */ +#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */ +#define SD_OCR_XPC (1 << 28) /* SDXC power control */ +#define SD_OCR_CCS (1 << 30) /* Card Capacity Status */ +#define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */ /* * SD_SWITCH argument format: @@ -64,10 +65,11 @@ /* * SCR field definitions */ - #define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ #define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ #define SCR_SPEC_VER_2 2 /* Implements system specification 2.00-3.0X */ +#define SD_SCR_BUS_WIDTH_1 (1<<0) +#define SD_SCR_BUS_WIDTH_4 (1<<2) /* * SD bus widths @@ -75,6 +77,16 @@ #define SD_BUS_WIDTH_1 0 #define SD_BUS_WIDTH_4 2 +/* +* SD bus speeds +*/ +#define UHS_SDR12_BUS_SPEED 0 +#define HIGH_SPEED_BUS_SPEED 1 +#define UHS_SDR25_BUS_SPEED 1 +#define UHS_SDR50_BUS_SPEED 2 +#define UHS_SDR104_BUS_SPEED 3 +#define UHS_DDR50_BUS_SPEED 4 + /* * SD_SWITCH mode */ diff --git a/ipl/sdmmc.c b/ipl/sdmmc.c index 8f0f96d..879f852 100755 --- a/ipl/sdmmc.c +++ b/ipl/sdmmc.c @@ -223,7 +223,7 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power) u32 cond = 0; if (!_mmc_storage_get_op_cond_inner(storage, &cond, power)) break; - if (cond & 0x80000000) + if (cond & MMC_CARD_BUSY) { if (cond & 0x40000000) storage->has_sector_access = 1; @@ -242,6 +242,22 @@ static int _mmc_storage_set_relative_addr(sdmmc_storage_t *storage) return _sdmmc_storage_execute_cmd_type1(storage, MMC_SET_RELATIVE_ADDR, storage->rca << 16, 0, 0x10); } +static int _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf) +{ + storage->ext_csd.rev = buf[EXT_CSD_REV]; + storage->ext_csd.ext_struct = buf[EXT_CSD_STRUCTURE]; + storage->ext_csd.card_type = buf[EXT_CSD_CARD_TYPE]; + storage->ext_csd.dev_version = *(u16 *)&buf[EXT_CSD_DEVICE_VERSION]; + storage->ext_csd.boot_mult = buf[EXT_CSD_BOOT_MULT]; + storage->ext_csd.rpmb_mult = buf[EXT_CSD_RPMB_MULT]; + storage->ext_csd.sectors = *(u32 *)&buf[EXT_CSD_SEC_CNT]; + storage->ext_csd.bkops = buf[EXT_CSD_BKOPS_SUPPORT]; + storage->ext_csd.bkops_en = buf[EXT_CSD_BKOPS_EN]; + storage->ext_csd.bkops_status = buf[EXT_CSD_BKOPS_STATUS]; + + storage->sec_cnt = *(u32 *)&buf[EXT_CSD_SEC_CNT]; +} + static int _mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf) { sdmmc_cmd_t cmdbuf; @@ -260,6 +276,8 @@ static int _mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf) u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); + _mmc_storage_parse_ext_csd(storage, buf); + return _sdmmc_storage_check_result(tmp); } @@ -388,7 +406,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 return 0; DPRINTF("[mmc] got op cond\n"); - if (!_sdmmc_storage_get_cid(storage, storage->cid)) + if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) return 0; DPRINTF("[mmc] got cid\n"); @@ -396,7 +414,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 return 0; DPRINTF("[mmc] set relative addr\n"); - if (!_sdmmc_storage_get_csd(storage, storage->csd)) + if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) return 0; DPRINTF("[mmc] got csd\n"); @@ -412,7 +430,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 return 0; DPRINTF("[mmc] set blocklen to 512\n"); - u32 *csd = (u32 *)storage->csd; + u32 *csd = (u32 *)storage->raw_csd; //Check system specification version, only version 4.0 and later support below features. if (unstuff_bits(csd, 122, 4) < CSD_SPEC_VER_4) { @@ -430,23 +448,27 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 free(ext_csd); return 0; } + free(ext_csd); + DPRINTF("[mmc] got ext_csd\n"); //gfx_hexdump(&gfx_con, 0, ext_csd, 512); - storage->sec_cnt = *(u32 *)&ext_csd[EXT_CSD_SEC_CNT]; - - if (storage->cid[0xE] == 0x11 && ext_csd[EXT_CSD_BKOPS_EN] & EXT_CSD_BKOPS_LEVEL_2) - _mmc_storage_enable_bkops(storage); - - if (!_mmc_storage_enable_highspeed(storage, ext_csd[EXT_CSD_CARD_TYPE], type)) + /* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status. + Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end(). + Additionally this works only when we put the device in idle mode which we don't after enabling it. */ + if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0) { - free(ext_csd); - return 0; + _mmc_storage_enable_bkops(storage); + DPRINTF("[mmc] BKOPS enabled\n"); } - DPRINTF("[mmc] switched to possible highspeed mode\n"); + else + DPRINTF("[mmc] BKOPS disabled\n"); + + if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) + return 0; + DPRINTF("[mmc] switched to highspeed mode\n"); sdmmc_sd_clock_ctrl(storage->sdmmc, 1); - free(ext_csd); return 1; } @@ -484,21 +506,26 @@ static int _sd_storage_send_if_cond(sdmmc_storage_t *storage) sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, SD_SEND_IF_COND, 0x1AA, SDMMC_RSP_TYPE_5, 0); if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) - return 0; - - //TODO: we may have received a timeout error in the above request, which indicates a version 1 card. + return 1; // The SD Card is version 1.X u32 resp = 0; if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5)) - return 0; + return 2; - return (resp & 0xFF) == 0xAA ? 1 : 0; + return (resp & 0xFF) == 0xAA ? 0 : 2; } static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int is_version_1, int supports_low_voltage) { sdmmc_cmd_t cmdbuf; - u32 arg = (((~is_version_1 & 1) << 28) & 0xBFFFFFFF | ((~is_version_1 & 1) << 30)) & 0xFEFFFFFF | ((supports_low_voltage & ~is_version_1 & 1) << 24) | 0x100000; + // Support for Current > 150mA + u32 arg = (~is_version_1 & 1) ? SD_OCR_XPC : 0; + // Support for handling block-addressed SDHC cards + arg |= (~is_version_1 & 1) ? SD_OCR_CCS : 0; + // Support for 1.8V + arg |= (supports_low_voltage & ~is_version_1 & 1) ? SD_OCR_S18R : 0; + // This is needed for most cards. Do not set bit7 even if 1.8V is supported. + arg |= SD_OCR_VDD_32_33; sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0)) return 0; @@ -514,13 +541,12 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i u32 cond = 0; if (!_sd_storage_get_op_cond_once(storage, &cond, is_version_1, supports_low_voltage)) break; - if (cond & 0x80000000) + if (cond & MMC_CARD_BUSY) { - if (cond & 0x40000000) + if (cond & SD_OCR_CCS) storage->has_sector_access = 1; - // TODO: Some SD Card incorrectly report low voltage support - // Disable it for now - if (cond & 0x1000000 && supports_low_voltage) + + if (cond & SD_ROCR_S18A && supports_low_voltage) { //The low voltage regulator configuration is valid for SDMMC1 only. if (storage->sdmmc->id == SDMMC_1 && @@ -574,7 +600,24 @@ static int _sd_storage_get_rca(sdmmc_storage_t *storage) return 0; } -int _sd_storage_get_scr(sdmmc_storage_t *storage, void *buf) +static void _sd_storage_parse_scr(sdmmc_storage_t *storage) +{ + // unstuff_bits can parse only 4 u32 + u32 resp[4]; + + resp[3] = *(u32 *)&storage->raw_scr[4]; + resp[2] = *(u32 *)&storage->raw_scr[0]; + + storage->scr.sda_vsn = unstuff_bits(resp, 56, 4); + storage->scr.bus_widths = unstuff_bits(resp, 48, 4); + if (storage->scr.sda_vsn == SCR_SPEC_VER_2) + /* Check if Physical Layer Spec v3.0 is supported */ + storage->scr.sda_spec3 = unstuff_bits(resp, 47, 1); + if (storage->scr.sda_spec3) + storage->scr.cmds = unstuff_bits(resp, 32, 2); +} + +int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf) { sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, SD_APP_SEND_SCR, 0, SDMMC_RSP_TYPE_1, 0); @@ -592,6 +635,17 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, void *buf) u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); + //Prepare buffer for unstuff_bits + for (int i = 0; i < 8; i+=4) + { + storage->raw_scr[i + 3] = buf[i]; + storage->raw_scr[i + 2] = buf[i + 1]; + storage->raw_scr[i + 1] = buf[i + 2]; + storage->raw_scr[i] = buf[i + 3]; + } + _sd_storage_parse_scr(storage); + //gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8); + return _sdmmc_storage_check_result(tmp); } @@ -673,7 +727,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 if (buf[13] & 8) { type = 11; - hs_type = 3; + hs_type = UHS_SDR104_BUS_SPEED; break; } //Fall through. @@ -681,7 +735,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 if (!(buf[13] & 4)) return 0; type = 10; - hs_type = 2; + hs_type = UHS_SDR50_BUS_SPEED; break; default: return 0; @@ -714,6 +768,8 @@ int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf) int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type) { + int is_version_1 = 0; + memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; @@ -727,16 +783,16 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 return 0; DPRINTF("[sd] went to idle state\n"); - if (!_sd_storage_send_if_cond(storage)) + is_version_1 = _sd_storage_send_if_cond(storage); + if (is_version_1 == 2) return 0; DPRINTF("[sd] after send if cond\n"); - //TODO: use correct version here -----v - if (!_sd_storage_get_op_cond(storage, 0, bus_width == SDMMC_BUS_WIDTH_4 && (type | 1) == 11)) + if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11)) return 0; DPRINTF("[sd] got op cond\n"); - if (!_sdmmc_storage_get_cid(storage, storage->cid)) + if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) return 0; DPRINTF("[sd] got cid\n"); @@ -744,7 +800,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 return 0; DPRINTF("[sd] got rca (= %04X)\n", storage->rca); - if (!_sdmmc_storage_get_csd(storage, storage->csd)) + if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) return 0; DPRINTF("[sd] got csd\n"); @@ -791,11 +847,11 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 u8 *buf = (u8 *)malloc(512); if (!_sd_storage_get_scr(storage, buf)) return 0; - memcpy(storage->scr, buf, 8); + //gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8); DPRINTF("[sd] got scr\n"); - // Check if card supports a wider bus and if it's not SD Version 1.0 - if (bus_width == SDMMC_BUS_WIDTH_4 && storage->scr[1] & 4 && (storage->scr[0] & 0xF)) + // Check if card supports a wider bus and if it's not SD Version 1.X + if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF)) { if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN)) { @@ -817,7 +873,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 } DPRINTF("[sd] enabled highspeed (low voltage)\n"); } - else if (type != 6 && (storage->scr[0] & 0xF) != 0) + else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0) { if (!_sd_storage_enable_highspeed_high_volt(storage, buf)) { @@ -845,7 +901,7 @@ int _gc_storage_custom_cmd(sdmmc_storage_t *storage, void *buf) sdmmc_req_t reqbuf; reqbuf.buf = buf; - reqbuf.blksize = 0x40; + reqbuf.blksize = 64; reqbuf.num_sectors = 1; reqbuf.is_write = 1; reqbuf.is_multi_block = 0; diff --git a/ipl/sdmmc.h b/ipl/sdmmc.h index 89e2877..63d079d 100755 --- a/ipl/sdmmc.h +++ b/ipl/sdmmc.h @@ -20,6 +20,64 @@ #include "types.h" #include "sdmmc_driver.h" +typedef struct _mmc_cid +{ + u32 manfid; + u8 prod_name[8]; + u8 card_bga; + u8 prv; + u32 serial; + u16 oemid; + u16 year; + u8 hwrev; + u8 fwrev; + u8 month; +} mmc_cid_t; + +typedef struct _mmc_csd +{ + u8 structure; + u8 mmca_vsn; + u16 cmdclass; + u32 c_size; + u32 r2w_factor; + u32 max_dtr; + u32 erase_size; /* In sectors */ + u32 read_blkbits; + u32 write_blkbits; + u32 capacity; +} mmc_csd_t; + +typedef struct _mmc_ext_csd +{ + u8 rev; + u32 sectors; + int bkops; /* background support bit */ + int bkops_en; /* manual bkops enable bit */ + u8 ext_struct; /* 194 */ + u8 card_type; /* 196 */ + u8 bkops_status; /* 246 */ + u16 dev_version; + u8 boot_mult; + u8 rpmb_mult; +} mmc_ext_csd_t; + +typedef struct _sd_scr +{ + u8 sda_vsn; + u8 sda_spec3; + u8 bus_widths; + u8 cmds; +} sd_scr_t; + +typedef struct _sd_ssr { + u8 bus_width; + u8 speed_class; + u8 uhs_grade; + u8 video_class; + u8 app_class; +} sd_ssr_t; + /*! SDMMC storage context. */ typedef struct _sdmmc_storage_t { @@ -29,9 +87,15 @@ typedef struct _sdmmc_storage_t u32 sec_cnt; int is_low_voltage; u32 partition; - u8 cid[0x10]; - u8 csd[0x10]; - u8 scr[8]; + u8 raw_cid[0x10]; + u8 raw_csd[0x10]; + u8 raw_scr[8]; + u8 raw_ssr[0x40]; + mmc_cid_t cid; + mmc_csd_t csd; + mmc_ext_csd_t ext_csd; + sd_scr_t scr; + sd_ssr_t ssr; } sdmmc_storage_t; int sdmmc_storage_end(sdmmc_storage_t *storage); diff --git a/ipl/sdmmc_driver.c b/ipl/sdmmc_driver.c index 0443455..5f291e5 100755 --- a/ipl/sdmmc_driver.c +++ b/ipl/sdmmc_driver.c @@ -304,10 +304,30 @@ static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) case SDMMC_RSP_TYPE_2: if (size < 0x10) return 0; - rsp[0] = sdmmc->regs->rspreg0; - rsp[1] = sdmmc->regs->rspreg1; - rsp[2] = sdmmc->regs->rspreg2; - rsp[3] = sdmmc->regs->rspreg3; + // CRC is stripped, so shifting is needed. + u32 tempreg; + for (int i = 0; i < 4; i++) + { + switch(i) + { + case 0: + tempreg = sdmmc->regs->rspreg3; + break; + case 1: + tempreg = sdmmc->regs->rspreg2; + break; + case 2: + tempreg = sdmmc->regs->rspreg1; + break; + case 3: + tempreg = sdmmc->regs->rspreg0; + break; + } + rsp[i] = tempreg << 8; + + if (i != 0) + rsp[i - 1] |= (tempreg >> 24) & 0xFF; + } break; default: return 0;