sdmmc: add support for sandisk emmc device report

This commit is contained in:
CTCaer 2021-07-06 10:15:59 +03:00
parent e94bd23d6f
commit dcdf687a07
3 changed files with 190 additions and 51 deletions

View file

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

View file

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

View file

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