1
0
Fork 0
mirror of https://github.com/CTCaer/hekate.git synced 2024-12-27 02:16:02 +00:00

[sdmmc] Fixes Part 1

* MMC/SD: Change many hardcoded values to named ones
* MMC/SD: Fix scr and csd byte/bitfield ordering
* MMC: Add ext csd parsing and using these variables isntead of arrays
* MMC: Fix BKOPS support but disabled
* SD: Add partial sd v1 support
* SD: Fix we support low voltage OCR bit
* SD: Add scr parsing and using these variables instead of hardcoded ones
This commit is contained in:
Kostas Missos 2018-05-14 01:28:27 +03:00 committed by nwert
parent 4d7f016e3a
commit acdc8b580c
5 changed files with 203 additions and 50 deletions

View file

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

View file

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

View file

@ -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;

View file

@ -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);

View file

@ -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;