mirror of
https://github.com/CTCaer/hekate.git
synced 2024-11-22 18:06:40 +00:00
sdmmc: add support for sandisk emmc device report
This commit is contained in:
parent
e94bd23d6f
commit
dcdf687a07
3 changed files with 190 additions and 51 deletions
|
@ -2,6 +2,7 @@
|
||||||
* Header for MultiMediaCard (MMC)
|
* Header for MultiMediaCard (MMC)
|
||||||
*
|
*
|
||||||
* Copyright 2002 Hewlett-Packard Company
|
* Copyright 2002 Hewlett-Packard Company
|
||||||
|
* Copyright 2018-2021 CTCaer
|
||||||
*
|
*
|
||||||
* Use consistent with the GNU GPL is permitted,
|
* Use consistent with the GNU GPL is permitted,
|
||||||
* provided that this copyright notice is
|
* provided that this copyright notice is
|
||||||
|
@ -21,8 +22,8 @@
|
||||||
* 15 May 2002
|
* 15 May 2002
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LINUX_MMC_MMC_H
|
#ifndef MMC_H
|
||||||
#define LINUX_MMC_MMC_H
|
#define MMC_H
|
||||||
|
|
||||||
/* Standard MMC commands (4.1) type argument response */
|
/* Standard MMC commands (4.1) type argument response */
|
||||||
/* class 1 */
|
/* class 1 */
|
||||||
|
@ -97,29 +98,29 @@
|
||||||
#define MMC_CMDQ_TASK_MGMT 48 /* ac [20:16] task id R1b */
|
#define MMC_CMDQ_TASK_MGMT 48 /* ac [20:16] task id R1b */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MMC_SWITCH argument format:
|
* MMC_SWITCH argument format:
|
||||||
*
|
*
|
||||||
* [31:26] Always 0
|
* [31:26] Always 0
|
||||||
* [25:24] Access Mode
|
* [25:24] Access Mode
|
||||||
* [23:16] Location of target Byte in EXT_CSD
|
* [23:16] Location of target Byte in EXT_CSD
|
||||||
* [15:08] Value Byte
|
* [15:08] Value Byte
|
||||||
* [07:03] Always 0
|
* [07:03] Always 0
|
||||||
* [02:00] Command Set
|
* [02:00] Command Set
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MMC status in R1, for native mode (SPI bits are different)
|
* MMC status in R1, for native mode (SPI bits are different)
|
||||||
Type
|
* Type
|
||||||
e : error bit
|
* e : error bit
|
||||||
s : status bit
|
* s : status bit
|
||||||
r : detected and set for the actual command response
|
* r : detected and set for the actual command response
|
||||||
x : detected and set during command execution. the host must poll
|
* x : detected and set during command execution. the host must poll
|
||||||
the card by sending status command in order to read these bits.
|
* the card by sending status command in order to read these bits.
|
||||||
Clear condition
|
* Clear condition
|
||||||
a : according to the card state
|
* a : according to the card state
|
||||||
b : always related to the previous command. Reception of
|
* b : always related to the previous command. Reception of a valid
|
||||||
a valid command will clear it (with a delay of one command)
|
* command will clear it (with a delay of one command)
|
||||||
c : clear by read
|
* c : clear by read
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
|
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
|
||||||
|
@ -151,6 +152,7 @@ c : clear by read
|
||||||
#define R1_AKE_SEQ_ERROR (1 << 3)
|
#define R1_AKE_SEQ_ERROR (1 << 3)
|
||||||
|
|
||||||
/* R1_CURRENT_STATE 12:9 */
|
/* R1_CURRENT_STATE 12:9 */
|
||||||
|
#define R1_STATE(x) ((x) << 9)
|
||||||
#define R1_STATE_IDLE 0
|
#define R1_STATE_IDLE 0
|
||||||
#define R1_STATE_READY 1
|
#define R1_STATE_READY 1
|
||||||
#define R1_STATE_IDENT 2
|
#define R1_STATE_IDENT 2
|
||||||
|
@ -162,9 +164,9 @@ c : clear by read
|
||||||
#define R1_STATE_DIS 8
|
#define R1_STATE_DIS 8
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS
|
* MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS
|
||||||
* R1 is the low order byte; R2 is the next highest byte, when present.
|
* R1 is the low order byte; R2 is the next highest byte, when present.
|
||||||
*/
|
*/
|
||||||
#define R1_SPI_IDLE (1 << 0)
|
#define R1_SPI_IDLE (1 << 0)
|
||||||
#define R1_SPI_ERASE_RESET (1 << 1)
|
#define R1_SPI_ERASE_RESET (1 << 1)
|
||||||
#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
|
#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
|
||||||
|
@ -185,16 +187,16 @@ c : clear by read
|
||||||
#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
|
#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OCR bits are mostly in host.h
|
* OCR bits are mostly in host.h
|
||||||
*/
|
*/
|
||||||
#define MMC_CARD_VDD_18 (1 << 7) /* Card VDD voltage 1.8 */
|
#define MMC_CARD_VDD_18 (1 << 7) /* Card VDD voltage 1.8 */
|
||||||
#define MMC_CARD_VDD_27_34 (0x7F << 15) /* Card VDD voltage 2.7 ~ 3.4 */
|
#define MMC_CARD_VDD_27_34 (0x7F << 15) /* Card VDD voltage 2.7 ~ 3.4 */
|
||||||
#define MMC_CARD_CCS (1 << 30) /* Card Capacity status bit */
|
#define MMC_CARD_CCS (1 << 30) /* Card Capacity status bit */
|
||||||
#define MMC_CARD_BUSY (1 << 31) /* Card Power up status bit */
|
#define MMC_CARD_BUSY (1 << 31) /* Card Power up status bit */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Card Command Classes (CCC)
|
* Card Command Classes (CCC)
|
||||||
*/
|
*/
|
||||||
#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */
|
#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */
|
||||||
/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
|
/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
|
||||||
/* (and for SPI, CMD58,59) */
|
/* (and for SPI, CMD58,59) */
|
||||||
|
@ -222,8 +224,8 @@ c : clear by read
|
||||||
/* (CMD?) */
|
/* (CMD?) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CSD field definitions
|
* CSD field definitions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
|
#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
|
||||||
#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
|
#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
|
||||||
|
@ -237,8 +239,8 @@ c : clear by read
|
||||||
#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */
|
#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EXT_CSD fields
|
* EXT_CSD fields
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */
|
#define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */
|
||||||
#define EXT_CSD_FLUSH_CACHE 32 /* W */
|
#define EXT_CSD_FLUSH_CACHE 32 /* W */
|
||||||
|
@ -316,8 +318,8 @@ c : clear by read
|
||||||
#define EXT_CSD_HPI_FEATURES 503 /* RO */
|
#define EXT_CSD_HPI_FEATURES 503 /* RO */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EXT_CSD field definitions
|
* EXT_CSD field definitions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define EXT_CSD_WR_REL_PARAM_EN (1<<2)
|
#define EXT_CSD_WR_REL_PARAM_EN (1<<2)
|
||||||
|
|
||||||
|
@ -393,8 +395,8 @@ c : clear by read
|
||||||
#define EXT_CSD_PACKED_EVENT_EN (1<<3)
|
#define EXT_CSD_PACKED_EVENT_EN (1<<3)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EXCEPTION_EVENT_STATUS field
|
* EXCEPTION_EVENT_STATUS field
|
||||||
*/
|
*/
|
||||||
#define EXT_CSD_URGENT_BKOPS (1<<0)
|
#define EXT_CSD_URGENT_BKOPS (1<<0)
|
||||||
#define EXT_CSD_DYNCAP_NEEDED (1<<1)
|
#define EXT_CSD_DYNCAP_NEEDED (1<<1)
|
||||||
#define EXT_CSD_SYSPOOL_EXHAUSTED (1<<2)
|
#define EXT_CSD_SYSPOOL_EXHAUSTED (1<<2)
|
||||||
|
@ -404,34 +406,34 @@ c : clear by read
|
||||||
#define EXT_CSD_PACKED_INDEXED_ERROR (1<<1)
|
#define EXT_CSD_PACKED_INDEXED_ERROR (1<<1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BKOPS status level
|
* BKOPS status level
|
||||||
*/
|
*/
|
||||||
#define EXT_CSD_BKOPS_LEVEL_2 0x2
|
#define EXT_CSD_BKOPS_LEVEL_2 0x2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BKOPS modes
|
* BKOPS modes
|
||||||
*/
|
*/
|
||||||
#define EXT_CSD_MANUAL_BKOPS_MASK 0x01
|
#define EXT_CSD_MANUAL_BKOPS_MASK 0x01
|
||||||
#define EXT_CSD_AUTO_BKOPS_MASK 0x02
|
#define EXT_CSD_AUTO_BKOPS_MASK 0x02
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Command Queue
|
* Command Queue
|
||||||
*/
|
*/
|
||||||
#define EXT_CSD_CMDQ_MODE_ENABLED (1<<0)
|
#define EXT_CSD_CMDQ_MODE_ENABLED (1<<0)
|
||||||
#define EXT_CSD_CMDQ_DEPTH_MASK 0x1F
|
#define EXT_CSD_CMDQ_DEPTH_MASK 0x1F
|
||||||
#define EXT_CSD_CMDQ_SUPPORTED (1<<0)
|
#define EXT_CSD_CMDQ_SUPPORTED (1<<0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MMC_SWITCH access modes
|
* MMC_SWITCH access modes
|
||||||
*/
|
*/
|
||||||
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
|
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
|
||||||
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
|
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
|
||||||
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
|
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
|
||||||
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
|
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Erase/trim/discard
|
* Erase/trim/discard
|
||||||
*/
|
*/
|
||||||
#define MMC_ERASE_ARG 0x00000000
|
#define MMC_ERASE_ARG 0x00000000
|
||||||
#define MMC_SECURE_ERASE_ARG 0x80000000
|
#define MMC_SECURE_ERASE_ARG 0x80000000
|
||||||
#define MMC_TRIM_ARG 0x00000001
|
#define MMC_TRIM_ARG 0x00000001
|
||||||
|
@ -441,4 +443,9 @@ c : clear by read
|
||||||
#define MMC_SECURE_ARGS 0x80000000
|
#define MMC_SECURE_ARGS 0x80000000
|
||||||
#define MMC_TRIM_ARGS 0x00008001
|
#define MMC_TRIM_ARGS 0x00008001
|
||||||
|
|
||||||
#endif /* LINUX_MMC_MMC_H */
|
/*
|
||||||
|
* Vendor definitions and structs
|
||||||
|
*/
|
||||||
|
#define MMC_SANDISK_HEALTH_REPORT 0x96C9D71C
|
||||||
|
|
||||||
|
#endif /* MMC_H */
|
||||||
|
|
|
@ -139,6 +139,60 @@ static int _sdmmc_storage_check_status(sdmmc_storage_t *storage)
|
||||||
return _sdmmc_storage_get_status(storage, &tmp, 0);
|
return _sdmmc_storage_get_status(storage, &tmp, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sdmmc_storage_execute_vendor_cmd(sdmmc_storage_t *storage, u32 arg)
|
||||||
|
{
|
||||||
|
sdmmc_cmd_t cmdbuf;
|
||||||
|
sdmmc_init_cmd(&cmdbuf, MMC_VENDOR_62_CMD, arg, SDMMC_RSP_TYPE_1, 1);
|
||||||
|
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 resp;
|
||||||
|
sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_1);
|
||||||
|
|
||||||
|
resp = -1;
|
||||||
|
u32 timeout = get_tmr_ms() + 1500;
|
||||||
|
while (resp != (R1_READY_FOR_DATA | R1_STATE(R1_STATE_TRAN)))
|
||||||
|
{
|
||||||
|
_sdmmc_storage_get_status(storage, &resp, 0);
|
||||||
|
|
||||||
|
if (get_tmr_ms() > timeout)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _sdmmc_storage_check_card_status(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sdmmc_storage_vendor_sandisk_report(sdmmc_storage_t *storage, void *buf)
|
||||||
|
{
|
||||||
|
// Request health report.
|
||||||
|
if (!sdmmc_storage_execute_vendor_cmd(storage, MMC_SANDISK_HEALTH_REPORT))
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
u32 tmp = 0;
|
||||||
|
sdmmc_cmd_t cmdbuf;
|
||||||
|
sdmmc_req_t reqbuf;
|
||||||
|
|
||||||
|
sdmmc_init_cmd(&cmdbuf, MMC_VENDOR_63_CMD, 0, SDMMC_RSP_TYPE_1, 0); // similar to CMD17 with arg 0x0.
|
||||||
|
|
||||||
|
reqbuf.buf = buf;
|
||||||
|
reqbuf.num_sectors = 1;
|
||||||
|
reqbuf.blksize = 512;
|
||||||
|
reqbuf.is_write = 0;
|
||||||
|
reqbuf.is_multi_block = 0;
|
||||||
|
reqbuf.is_auto_stop_trn = 0;
|
||||||
|
|
||||||
|
u32 blkcnt_out;
|
||||||
|
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, &blkcnt_out))
|
||||||
|
{
|
||||||
|
sdmmc_stop_transmission(storage->sdmmc, &tmp);
|
||||||
|
_sdmmc_storage_get_status(storage, &tmp, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write)
|
static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write)
|
||||||
{
|
{
|
||||||
u32 tmp = 0;
|
u32 tmp = 0;
|
||||||
|
@ -1360,8 +1414,6 @@ DPRINTF("[SD] SD does not support wide bus width\n");
|
||||||
if (!_sd_storage_enable_uhs_low_volt(storage, type, buf))
|
if (!_sd_storage_enable_uhs_low_volt(storage, type, buf))
|
||||||
return 0;
|
return 0;
|
||||||
DPRINTF("[SD] enabled UHS\n");
|
DPRINTF("[SD] enabled UHS\n");
|
||||||
|
|
||||||
sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE);
|
|
||||||
}
|
}
|
||||||
else if (type != SDHCI_TIMING_SD_DS12 && storage->scr.sda_vsn) // Not default speed and not SD Version 1.0.
|
else if (type != SDHCI_TIMING_SD_DS12 && storage->scr.sda_vsn) // Not default speed and not SD Version 1.0.
|
||||||
{
|
{
|
||||||
|
@ -1387,6 +1439,8 @@ DPRINTF("[SD] enabled HS\n");
|
||||||
DPRINTF("[SD] got sd status\n");
|
DPRINTF("[SD] got sd status\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE);
|
||||||
|
|
||||||
storage->initialized = 1;
|
storage->initialized = 1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -34,6 +34,81 @@ typedef enum _sdmmc_type
|
||||||
EMMC_RPMB = 3
|
EMMC_RPMB = 3
|
||||||
} sdmmc_type;
|
} sdmmc_type;
|
||||||
|
|
||||||
|
typedef struct _mmc_sandisk_advanced_report_t
|
||||||
|
{
|
||||||
|
u32 power_inits;
|
||||||
|
|
||||||
|
u32 max_erase_cycles_sys;
|
||||||
|
u32 max_erase_cycles_slc;
|
||||||
|
u32 max_erase_cycles_mlc;
|
||||||
|
|
||||||
|
u32 min_erase_cycles_sys;
|
||||||
|
u32 min_erase_cycles_slc;
|
||||||
|
u32 min_erase_cycles_mlc;
|
||||||
|
|
||||||
|
u32 max_erase_cycles_euda;
|
||||||
|
u32 min_erase_cycles_euda;
|
||||||
|
u32 avg_erase_cycles_euda;
|
||||||
|
u32 read_reclaim_cnt_euda;
|
||||||
|
u32 bad_blocks_euda;
|
||||||
|
|
||||||
|
u32 pre_eol_euda;
|
||||||
|
u32 pre_eol_sys;
|
||||||
|
u32 pre_eol_mlc;
|
||||||
|
|
||||||
|
u32 uncorrectable_ecc;
|
||||||
|
|
||||||
|
u32 temperature_now;
|
||||||
|
u32 temperature_min;
|
||||||
|
u32 temperature_max;
|
||||||
|
|
||||||
|
u32 health_pct_euda;
|
||||||
|
u32 health_pct_sys;
|
||||||
|
u32 health_pct_mlc;
|
||||||
|
|
||||||
|
u32 unk0;
|
||||||
|
u32 unk1;
|
||||||
|
u32 unk2;
|
||||||
|
|
||||||
|
u32 reserved[78];
|
||||||
|
} mmc_sandisk_advanced_report_t;
|
||||||
|
|
||||||
|
typedef struct _mmc_sandisk_report_t
|
||||||
|
{
|
||||||
|
u32 avg_erase_cycles_sys;
|
||||||
|
u32 avg_erase_cycles_slc;
|
||||||
|
u32 avg_erase_cycles_mlc;
|
||||||
|
|
||||||
|
u32 read_reclaim_cnt_sys;
|
||||||
|
u32 read_reclaim_cnt_slc;
|
||||||
|
u32 read_reclaim_cnt_mlc;
|
||||||
|
|
||||||
|
u32 bad_blocks_factory;
|
||||||
|
u32 bad_blocks_sys;
|
||||||
|
u32 bad_blocks_slc;
|
||||||
|
u32 bad_blocks_mlc;
|
||||||
|
|
||||||
|
u32 fw_updates_cnt;
|
||||||
|
|
||||||
|
u8 fw_update_date[12];
|
||||||
|
u8 fw_update_time[8];
|
||||||
|
|
||||||
|
u32 total_writes_100mb;
|
||||||
|
u32 vdrops;
|
||||||
|
u32 vdroops;
|
||||||
|
|
||||||
|
u32 vdrops_failed_data_rec;
|
||||||
|
u32 vdrops_data_rec_ops;
|
||||||
|
|
||||||
|
u32 total_writes_slc_100mb;
|
||||||
|
u32 total_writes_mlc_100mb;
|
||||||
|
|
||||||
|
u32 mlc_bigfile_mode_limit_exceeded;
|
||||||
|
u32 avg_erase_cycles_hybrid;
|
||||||
|
|
||||||
|
mmc_sandisk_advanced_report_t advanced;
|
||||||
|
} mmc_sandisk_report_t;
|
||||||
|
|
||||||
typedef struct _mmc_cid
|
typedef struct _mmc_cid
|
||||||
{
|
{
|
||||||
u32 manfid;
|
u32 manfid;
|
||||||
|
@ -131,6 +206,9 @@ void sdmmc_storage_init_wait_sd();
|
||||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);
|
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);
|
||||||
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||||
|
|
||||||
|
int sdmmc_storage_execute_vendor_cmd(sdmmc_storage_t *storage, u32 arg);
|
||||||
|
int sdmmc_storage_vendor_sandisk_report(sdmmc_storage_t *storage, void *buf);
|
||||||
|
|
||||||
int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf);
|
int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf);
|
||||||
u32 sd_storage_get_ssr_au(sdmmc_storage_t *storage);
|
u32 sd_storage_get_ssr_au(sdmmc_storage_t *storage);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue