@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved.
|
||||
* Copyright (c) 2018-2023 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,11 +17,16 @@
|
||||
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
|
||||
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
|
||||
#define SD_SWITCH_VOLTAGE 11 /* ac R1 */
|
||||
/* Class 2 */
|
||||
#define SD_ADDR_EXT 22 /* ac [5:0] R1 */
|
||||
/* class 10 */
|
||||
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
|
||||
/* class 5 */
|
||||
#define SD_ERASE_WR_BLK_START 32 /* ac [31:0] data addr R1 */
|
||||
#define SD_ERASE_WR_BLK_END 33 /* ac [31:0] data addr R1 */
|
||||
/* class 11 */
|
||||
#define SD_READ_EXTR_SINGLE 48 /* adtc [31:0] R1 */
|
||||
#define SD_WRITE_EXTR_SINGLE 49 /* adtc [31:0] R1 */
|
||||
|
||||
/* Application commands */
|
||||
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2023 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <mem/heap.h>
|
||||
#include <mem/mc.h>
|
||||
#include <soc/timer.h>
|
||||
#include <storage/emmc.h>
|
||||
#include <storage/sdmmc.h>
|
||||
@@ -28,14 +29,26 @@
|
||||
#include <memory_map.h>
|
||||
#include <gfx_utils.h>
|
||||
|
||||
//#define SDMMC_DEBUG_PRINT_SD_REGS
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
//#define SDMMC_DEBUG_PRINT_SD_REGS
|
||||
#ifdef SDMMC_DEBUG_PRINT_SD_REGS
|
||||
#define DREGPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#else
|
||||
#define DREGPRINTF(...)
|
||||
#endif
|
||||
|
||||
#ifdef BDK_SDMMC_EXTRA_PRINT
|
||||
#define ERROR_EXTRA_PRINTING
|
||||
#endif
|
||||
|
||||
u32 sd_power_cycle_time_start;
|
||||
|
||||
static inline u32 unstuff_bits(const u32 *resp, u32 start, u32 size)
|
||||
{
|
||||
start %= 128;
|
||||
|
||||
const u32 mask = (size < 32 ? 1 << size : 0) - 1;
|
||||
const u32 off = 3 - ((start) / 32);
|
||||
const u32 shft = (start) & 31;
|
||||
@@ -53,7 +66,7 @@ static inline u32 unstuff_bits(const u32 *resp, u32 start, u32 size)
|
||||
static int _sdmmc_storage_check_card_status(u32 res)
|
||||
{
|
||||
//Error mask:
|
||||
//TODO: R1_SWITCH_ERROR can be skipped for certain card types.
|
||||
//!WARN: R1_SWITCH_ERROR is reserved on SD. The card isn't supposed to use it.
|
||||
if (res &
|
||||
(R1_OUT_OF_RANGE | R1_ADDRESS_ERROR | R1_BLOCK_LEN_ERROR |
|
||||
R1_ERASE_SEQ_ERROR | R1_ERASE_PARAM | R1_WP_VIOLATION |
|
||||
@@ -74,7 +87,7 @@ static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *re
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_rsp(storage->sdmmc, resp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, resp, SDMMC_RSP_TYPE_1);
|
||||
if (mask)
|
||||
*resp &= ~mask;
|
||||
|
||||
@@ -106,7 +119,7 @@ static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage)
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_rsp(storage->sdmmc, (u32 *)storage->raw_cid, 16, SDMMC_RSP_TYPE_2);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, (u32 *)storage->raw_cid, SDMMC_RSP_TYPE_2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -123,7 +136,7 @@ static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage)
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_rsp(storage->sdmmc, (u32 *)storage->raw_csd, 16, SDMMC_RSP_TYPE_2);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, (u32 *)storage->raw_csd, SDMMC_RSP_TYPE_2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -152,7 +165,7 @@ int sdmmc_storage_execute_vendor_cmd(sdmmc_storage_t *storage, u32 arg)
|
||||
return 0;
|
||||
|
||||
u32 resp;
|
||||
sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_1);
|
||||
|
||||
resp = -1;
|
||||
u32 timeout = get_tmr_ms() + 1500;
|
||||
@@ -229,6 +242,10 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
|
||||
return 0;
|
||||
}
|
||||
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
if (!_sdmmc_storage_check_card_status(tmp))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -246,6 +263,43 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _sdmmc_storage_handle_io_error(sdmmc_storage_t *storage, bool first_reinit)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (storage->sdmmc->id == SDMMC_1 || storage->sdmmc->id == SDMMC_4)
|
||||
{
|
||||
if (storage->sdmmc->id == SDMMC_1)
|
||||
{
|
||||
sd_error_count_increment(SD_ERROR_RW_FAIL);
|
||||
|
||||
if (first_reinit)
|
||||
res = sd_initialize(true);
|
||||
else
|
||||
{
|
||||
res = sd_init_retry(true);
|
||||
if (!res)
|
||||
sd_error_count_increment(SD_ERROR_INIT_FAIL);
|
||||
}
|
||||
}
|
||||
else if (storage->sdmmc->id == SDMMC_4)
|
||||
{
|
||||
emmc_error_count_increment(EMMC_ERROR_RW_FAIL);
|
||||
|
||||
if (first_reinit)
|
||||
res = emmc_initialize(true);
|
||||
else
|
||||
{
|
||||
res = emmc_init_retry(true);
|
||||
if (!res)
|
||||
emmc_error_count_increment(EMMC_ERROR_INIT_FAIL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write)
|
||||
{
|
||||
u8 *bbuf = (u8 *)buf;
|
||||
@@ -257,6 +311,15 @@ static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 nu
|
||||
if (!storage->initialized)
|
||||
return 0;
|
||||
|
||||
// Check if out of bounds.
|
||||
if (((u64)sector + num_sectors) > storage->sec_cnt)
|
||||
{
|
||||
#ifdef ERROR_EXTRA_PRINTING
|
||||
EPRINTFARGS("SDMMC%d: Out of bounds!", storage->sdmmc->id + 1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (sct_total)
|
||||
{
|
||||
u32 blkcnt = 0;
|
||||
@@ -276,51 +339,18 @@ reinit_try:
|
||||
} while (retries);
|
||||
|
||||
// Disk IO failure! Reinit SD/EMMC to a lower speed.
|
||||
if (storage->sdmmc->id == SDMMC_1 || storage->sdmmc->id == SDMMC_4)
|
||||
if (_sdmmc_storage_handle_io_error(storage, first_reinit))
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (storage->sdmmc->id == SDMMC_1)
|
||||
{
|
||||
sd_error_count_increment(SD_ERROR_RW_FAIL);
|
||||
|
||||
if (first_reinit)
|
||||
res = sd_initialize(true);
|
||||
else
|
||||
{
|
||||
res = sd_init_retry(true);
|
||||
if (!res)
|
||||
sd_error_count_increment(SD_ERROR_INIT_FAIL);
|
||||
}
|
||||
}
|
||||
else if (storage->sdmmc->id == SDMMC_4)
|
||||
{
|
||||
emmc_error_count_increment(EMMC_ERROR_RW_FAIL);
|
||||
|
||||
if (first_reinit)
|
||||
res = emmc_initialize(true);
|
||||
else
|
||||
{
|
||||
res = emmc_init_retry(true);
|
||||
if (!res)
|
||||
emmc_error_count_increment(EMMC_ERROR_INIT_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset values for a retry.
|
||||
blkcnt = 0;
|
||||
retries = 3;
|
||||
first_reinit = false;
|
||||
|
||||
// If successful reinit, restart xfer.
|
||||
if (res)
|
||||
{
|
||||
bbuf = (u8 *)buf;
|
||||
sct_off = sector;
|
||||
sct_total = num_sectors;
|
||||
bbuf = (u8 *)buf;
|
||||
sct_off = sector;
|
||||
sct_total = num_sectors;
|
||||
|
||||
goto reinit_try;
|
||||
}
|
||||
goto reinit_try;
|
||||
}
|
||||
|
||||
// Failed.
|
||||
@@ -394,7 +424,7 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))
|
||||
return 0;
|
||||
|
||||
return sdmmc_get_rsp(storage->sdmmc, pout, 4, SDMMC_RSP_TYPE_3);
|
||||
return sdmmc_get_cached_rsp(storage->sdmmc, pout, SDMMC_RSP_TYPE_3);
|
||||
}
|
||||
|
||||
static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power)
|
||||
@@ -478,12 +508,12 @@ static void _mmc_storage_parse_csd(sdmmc_storage_t *storage)
|
||||
{
|
||||
u32 *raw_csd = (u32 *)storage->raw_csd;
|
||||
|
||||
storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4);
|
||||
storage->csd.structure = unstuff_bits(raw_csd, 126, 2);
|
||||
storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12);
|
||||
storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4);
|
||||
storage->csd.structure = unstuff_bits(raw_csd, 126, 2);
|
||||
storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12);
|
||||
storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4);
|
||||
storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2);
|
||||
storage->sec_cnt = storage->csd.capacity;
|
||||
storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2);
|
||||
storage->sec_cnt = storage->csd.capacity;
|
||||
}
|
||||
|
||||
static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf)
|
||||
@@ -532,12 +562,40 @@ int mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf)
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
_mmc_storage_parse_ext_csd(storage, buf);
|
||||
|
||||
return _sdmmc_storage_check_card_status(tmp);
|
||||
}
|
||||
|
||||
int sd_storage_get_ext_reg(sdmmc_storage_t *storage, u8 fno, u8 page, u16 address, u32 len, void *buf)
|
||||
{
|
||||
if (!(storage->scr.cmds & BIT(2)))
|
||||
return 0;
|
||||
|
||||
sdmmc_cmd_t cmdbuf;
|
||||
|
||||
u32 arg = fno << 27 | page << 18 | address << 9 | (len - 1);
|
||||
|
||||
sdmmc_init_cmd(&cmdbuf, SD_READ_EXTR_SINGLE, arg, SDMMC_RSP_TYPE_1, 0);
|
||||
|
||||
sdmmc_req_t reqbuf;
|
||||
reqbuf.buf = buf;
|
||||
reqbuf.blksize = SDMMC_DAT_BLOCKSIZE;
|
||||
reqbuf.num_sectors = 1;
|
||||
reqbuf.is_write = 0;
|
||||
reqbuf.is_multi_block = 0;
|
||||
reqbuf.is_auto_stop_trn = 0;
|
||||
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL))
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
|
||||
return _sdmmc_storage_check_card_status(tmp);
|
||||
}
|
||||
|
||||
static int _mmc_storage_switch(sdmmc_storage_t *storage, u32 arg)
|
||||
{
|
||||
return _sdmmc_storage_execute_cmd_type1(storage, MMC_SWITCH, arg, 1, R1_SKIP_STATE_CHECK);
|
||||
@@ -814,7 +872,7 @@ void _sd_storage_debug_print_csd(const u32 *raw_csd)
|
||||
gfx_printf("WRITE_BLK_MISALIGN: %X\n", unstuff_bits(raw_csd, 78, 1));
|
||||
gfx_printf("READ_BLK_MISALIGN: %X\n", unstuff_bits(raw_csd, 77, 1));
|
||||
gfx_printf("DSR_IMP: %X\n", unstuff_bits(raw_csd, 76, 1));
|
||||
gfx_printf("C_SIZE: %06X\n", unstuff_bits(raw_csd, 48, 22));
|
||||
gfx_printf("C_SIZE: %06X\n", unstuff_bits(raw_csd, 48, 28)); // CSD 3 (SDUC).
|
||||
|
||||
gfx_printf("ERASE_BLK_LEN: %X\n", unstuff_bits(raw_csd, 46, 1));
|
||||
gfx_printf("SECTOR_SIZE: %02X\n", unstuff_bits(raw_csd, 39, 6));
|
||||
@@ -831,8 +889,8 @@ void _sd_storage_debug_print_csd(const u32 *raw_csd)
|
||||
gfx_printf("TMP_WRITE_PROTECT: %X\n", unstuff_bits(raw_csd, 12, 1));
|
||||
gfx_printf("FILE_FORMAT: %X\n", unstuff_bits(raw_csd, 10, 2));
|
||||
|
||||
gfx_printf("--RSVD-- %02X %02X %X %X %02X %X\n",
|
||||
unstuff_bits(raw_csd, 120, 6), unstuff_bits(raw_csd, 70, 6),
|
||||
gfx_printf("--RSVD-- %02X %X %X %02X %X\n",
|
||||
unstuff_bits(raw_csd, 120, 6),
|
||||
unstuff_bits(raw_csd, 47, 1), unstuff_bits(raw_csd, 29, 2),
|
||||
unstuff_bits(raw_csd, 16, 5), unstuff_bits(raw_csd, 8, 2));
|
||||
}
|
||||
@@ -871,39 +929,39 @@ void _sd_storage_debug_print_ssr(const u8 *raw_ssr)
|
||||
|
||||
gfx_printf("\nSD Status:\n");
|
||||
|
||||
gfx_printf("DAT_BUS_WIDTH: %X\n", unstuff_bits(raw_ssr0, 510 - 384, 2));
|
||||
gfx_printf("SECURED_MODE: %X\n", unstuff_bits(raw_ssr0, 509 - 384, 1));
|
||||
gfx_printf("SECURITY_FUNCTIONS: %02X\n", unstuff_bits(raw_ssr0, 502 - 384, 6));
|
||||
gfx_printf("SD_CARD_TYPE: %04X\n", unstuff_bits(raw_ssr0, 480 - 384, 16));
|
||||
gfx_printf("SZ_OF_PROTECTED_AREA: %08X\n", unstuff_bits(raw_ssr0, 448 - 384, 32));
|
||||
gfx_printf("SPEED_CLASS: %02X\n", unstuff_bits(raw_ssr0, 440 - 384, 8));
|
||||
gfx_printf("PERFORMANCE_MOVE: %02X\n", unstuff_bits(raw_ssr0, 432 - 384, 8));
|
||||
gfx_printf("AU_SIZE: %X\n", unstuff_bits(raw_ssr0, 428 - 384, 4));
|
||||
gfx_printf("ERAZE_SIZE: %04X\n", unstuff_bits(raw_ssr0, 408 - 384, 16));
|
||||
gfx_printf("ERASE_TIMEOUT: %02X\n", unstuff_bits(raw_ssr0, 402 - 384, 6));
|
||||
gfx_printf("ERASE_OFFSET: %X\n", unstuff_bits(raw_ssr0, 400 - 384, 2));
|
||||
gfx_printf("UHS_SPEED_GRADE: %X\n", unstuff_bits(raw_ssr0, 396 - 384, 4));
|
||||
gfx_printf("UHS_AU_SIZE: %X\n", unstuff_bits(raw_ssr0, 392 - 384, 4));
|
||||
gfx_printf("VIDEO_SPEED_CLASS: %02X\n", unstuff_bits(raw_ssr0, 384 - 384, 8));
|
||||
gfx_printf("DAT_BUS_WIDTH: %X\n", unstuff_bits(raw_ssr0, 510, 2));
|
||||
gfx_printf("SECURED_MODE: %X\n", unstuff_bits(raw_ssr0, 509, 1));
|
||||
gfx_printf("SECURITY_FUNCTIONS: %02X\n", unstuff_bits(raw_ssr0, 502, 6));
|
||||
gfx_printf("SD_CARD_TYPE: %04X\n", unstuff_bits(raw_ssr0, 480, 16));
|
||||
gfx_printf("SZ_OF_PROTECTED_AREA: %08X\n", unstuff_bits(raw_ssr0, 448, 32));
|
||||
gfx_printf("SPEED_CLASS: %02X\n", unstuff_bits(raw_ssr0, 440, 8));
|
||||
gfx_printf("PERFORMANCE_MOVE: %02X\n", unstuff_bits(raw_ssr0, 432, 8));
|
||||
gfx_printf("AU_SIZE: %X\n", unstuff_bits(raw_ssr0, 428, 4));
|
||||
gfx_printf("ERAZE_SIZE: %04X\n", unstuff_bits(raw_ssr0, 408, 16));
|
||||
gfx_printf("ERASE_TIMEOUT: %02X\n", unstuff_bits(raw_ssr0, 402, 6));
|
||||
gfx_printf("ERASE_OFFSET: %X\n", unstuff_bits(raw_ssr0, 400, 2));
|
||||
gfx_printf("UHS_SPEED_GRADE: %X\n", unstuff_bits(raw_ssr0, 396, 4));
|
||||
gfx_printf("UHS_AU_SIZE: %X\n", unstuff_bits(raw_ssr0, 392, 4));
|
||||
gfx_printf("VIDEO_SPEED_CLASS: %02X\n", unstuff_bits(raw_ssr0, 384, 8));
|
||||
|
||||
gfx_printf("VSC_AU_SIZE: %03X\n", unstuff_bits(raw_ssr1, 368 - 256, 10));
|
||||
gfx_printf("SUS_ADDR: %06X\n", unstuff_bits(raw_ssr1, 346 - 256, 22));
|
||||
gfx_printf("APP_PERF_CLASS: %X\n", unstuff_bits(raw_ssr1, 336 - 256, 4));
|
||||
gfx_printf("PERFORMANCE_ENHANCE: %02X\n", unstuff_bits(raw_ssr1, 328 - 256, 8));
|
||||
gfx_printf("DISCARD_SUPPORT: %X\n", unstuff_bits(raw_ssr1, 313 - 256, 1));
|
||||
gfx_printf("FULE_SUPPORT: %X\n", unstuff_bits(raw_ssr1, 312 - 256, 1));
|
||||
gfx_printf("VSC_AU_SIZE: %03X\n", unstuff_bits(raw_ssr1, 368, 10));
|
||||
gfx_printf("SUS_ADDR: %06X\n", unstuff_bits(raw_ssr1, 346, 22));
|
||||
gfx_printf("APP_PERF_CLASS: %X\n", unstuff_bits(raw_ssr1, 336, 4));
|
||||
gfx_printf("PERFORMANCE_ENHANCE: %02X\n", unstuff_bits(raw_ssr1, 328, 8));
|
||||
gfx_printf("DISCARD_SUPPORT: %X\n", unstuff_bits(raw_ssr1, 313, 1));
|
||||
gfx_printf("FULE_SUPPORT: %X\n", unstuff_bits(raw_ssr1, 312, 1));
|
||||
|
||||
gfx_printf("--RSVD-- %02X %X %02X %02X %04X\n",
|
||||
unstuff_bits(raw_ssr0, 496 - 384, 6), unstuff_bits(raw_ssr0, 424 - 384, 4),
|
||||
unstuff_bits(raw_ssr1, 378 - 256, 6), unstuff_bits(raw_ssr1, 340 - 256, 6),
|
||||
unstuff_bits(raw_ssr1, 314 - 256, 14));
|
||||
unstuff_bits(raw_ssr0, 496, 6), unstuff_bits(raw_ssr0, 424, 4),
|
||||
unstuff_bits(raw_ssr1, 378, 6), unstuff_bits(raw_ssr1, 340, 6),
|
||||
unstuff_bits(raw_ssr1, 314, 14));
|
||||
|
||||
gfx_printf("VENDOR_1: %06X %08X\n",
|
||||
unstuff_bits(raw_ssr1, 288 - 256, 24), unstuff_bits(raw_ssr1, 256 - 256, 32));
|
||||
unstuff_bits(raw_ssr1, 288, 24), unstuff_bits(raw_ssr1, 256, 32));
|
||||
|
||||
gfx_printf("VENDOR_2: %08X %08X %08X %08X\n",
|
||||
unstuff_bits(raw_ssr2, 224 - 128, 32), unstuff_bits(raw_ssr2, 192 - 128, 32),
|
||||
unstuff_bits(raw_ssr2, 160 - 128, 32), unstuff_bits(raw_ssr2, 128 - 128, 32));
|
||||
unstuff_bits(raw_ssr2, 224, 32), unstuff_bits(raw_ssr2, 192, 32),
|
||||
unstuff_bits(raw_ssr2, 160, 32), unstuff_bits(raw_ssr2, 128, 32));
|
||||
gfx_printf("VENDOR_3: %08X %08X %08X %08X\n",
|
||||
unstuff_bits(raw_ssr3, 96 - 0, 32), unstuff_bits(raw_ssr3, 64, 32),
|
||||
unstuff_bits(raw_ssr3, 32 - 0, 32), unstuff_bits(raw_ssr3, 0, 32));
|
||||
@@ -917,13 +975,19 @@ static int _sd_storage_send_if_cond(sdmmc_storage_t *storage, bool *is_sdsc)
|
||||
sdmmc_init_cmd(&cmdbuf, SD_SEND_IF_COND, vhd_pattern, SDMMC_RSP_TYPE_5, 0);
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))
|
||||
{
|
||||
*is_sdsc = 1; // The SD Card is version 1.X
|
||||
return 1;
|
||||
// The SD Card is version 1.X (SDSC) if there is no response.
|
||||
if (storage->sdmmc->error_sts == SDHCI_ERR_INT_CMD_TIMEOUT)
|
||||
{
|
||||
*is_sdsc = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// For Card version >= 2.0, parse results.
|
||||
u32 resp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_5);
|
||||
|
||||
// Check if VHD was accepted and pattern was properly returned.
|
||||
if ((resp & 0xFFF) == vhd_pattern)
|
||||
@@ -949,7 +1013,7 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, boo
|
||||
if (!_sd_storage_execute_app_cmd(storage, R1_SKIP_STATE_CHECK, is_sdsc ? R1_ILLEGAL_COMMAND : 0, &cmdbuf, NULL, NULL))
|
||||
return 0;
|
||||
|
||||
return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3);
|
||||
return sdmmc_get_cached_rsp(storage->sdmmc, cond, SDMMC_RSP_TYPE_3);
|
||||
}
|
||||
|
||||
static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, bool is_sdsc, int bus_uhs_support)
|
||||
@@ -972,7 +1036,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, bool is_sdsc, int b
|
||||
storage->has_sector_access = 1;
|
||||
|
||||
// Check if card supports 1.8V signaling.
|
||||
if (cond & SD_ROCR_S18A && bus_uhs_support)
|
||||
if (cond & SD_ROCR_S18A && bus_uhs_support && !storage->is_low_voltage)
|
||||
{
|
||||
// Switch to 1.8V signaling.
|
||||
if (_sdmmc_storage_execute_cmd_type1(storage, SD_SWITCH_VOLTAGE, 0, 0, R1_STATE_READY))
|
||||
@@ -1016,7 +1080,7 @@ static int _sd_storage_get_rca(sdmmc_storage_t *storage)
|
||||
break;
|
||||
|
||||
u32 resp = 0;
|
||||
if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_4))
|
||||
if (!sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_4))
|
||||
break;
|
||||
|
||||
if (resp >> 16)
|
||||
@@ -1047,11 +1111,17 @@ static void _sd_storage_parse_scr(sdmmc_storage_t *storage)
|
||||
storage->scr.sda_vsn = unstuff_bits(resp, 56, 4);
|
||||
storage->scr.bus_widths = unstuff_bits(resp, 48, 4);
|
||||
|
||||
/* If v2.0 is supported, check if Physical Layer Spec v3.0 is supported */
|
||||
// If v2.0 is supported, check if Physical Layer Spec v3.0 is supported.
|
||||
if (storage->scr.sda_vsn == SCR_SPEC_VER_2)
|
||||
storage->scr.sda_spec3 = unstuff_bits(resp, 47, 1);
|
||||
if (storage->scr.sda_spec3)
|
||||
storage->scr.cmds = unstuff_bits(resp, 32, 2);
|
||||
{
|
||||
u8 sda_spec4 = unstuff_bits(resp, 42, 1);
|
||||
if (sda_spec4)
|
||||
storage->scr.cmds = unstuff_bits(resp, 32, 4);
|
||||
else
|
||||
storage->scr.cmds = unstuff_bits(resp, 32, 2);
|
||||
}
|
||||
}
|
||||
|
||||
int sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
|
||||
@@ -1071,9 +1141,9 @@ int sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
//Prepare buffer for unstuff_bits
|
||||
for (int i = 0; i < 8; i+=4)
|
||||
for (u32 i = 0; i < 8; i+=4)
|
||||
{
|
||||
storage->raw_scr[i + 3] = buf[i];
|
||||
storage->raw_scr[i + 2] = buf[i + 1];
|
||||
@@ -1102,7 +1172,7 @@ static int _sd_storage_switch_get(sdmmc_storage_t *storage, void *buf)
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
return _sdmmc_storage_check_card_status(tmp);
|
||||
}
|
||||
|
||||
@@ -1126,7 +1196,7 @@ static int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
return _sdmmc_storage_check_card_status(tmp);
|
||||
}
|
||||
|
||||
@@ -1242,7 +1312,7 @@ static int _sd_storage_enable_DDR200(sdmmc_storage_t *storage, u8 *buf)
|
||||
|
||||
u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1];
|
||||
DPRINTF("[SD] max power: %d mW\n", total_pwr_consumption * 3600 / 1000);
|
||||
storage->card_power_limit = total_pwr_consumption;
|
||||
storage->max_power = total_pwr_consumption;
|
||||
|
||||
if (total_pwr_consumption <= 800)
|
||||
{
|
||||
@@ -1281,7 +1351,7 @@ static int _sd_storage_set_card_bus_speed(sdmmc_storage_t *storage, u32 hs_type,
|
||||
|
||||
u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1];
|
||||
DPRINTF("[SD] max power: %d mW\n", total_pwr_consumption * 3600 / 1000);
|
||||
storage->card_power_limit = total_pwr_consumption;
|
||||
storage->max_power = total_pwr_consumption;
|
||||
|
||||
if (total_pwr_consumption <= 800)
|
||||
{
|
||||
@@ -1493,10 +1563,10 @@ static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
|
||||
_sd_storage_debug_print_ssr(storage->raw_ssr);
|
||||
#endif
|
||||
|
||||
storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510 - 384, 2) & SD_BUS_WIDTH_4) ? 4 : 1;
|
||||
storage->ssr.protected_size = unstuff_bits(raw_ssr1, 448 - 384, 32);
|
||||
storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510, 2) & SD_BUS_WIDTH_4) ? 4 : 1;
|
||||
storage->ssr.protected_size = unstuff_bits(raw_ssr1, 448, 32);
|
||||
|
||||
u32 speed_class = unstuff_bits(raw_ssr1, 440 - 384, 8);
|
||||
u32 speed_class = unstuff_bits(raw_ssr1, 440, 8);
|
||||
switch(speed_class)
|
||||
{
|
||||
case 0:
|
||||
@@ -1514,12 +1584,94 @@ static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
|
||||
storage->ssr.speed_class = speed_class;
|
||||
break;
|
||||
}
|
||||
storage->ssr.uhs_grade = unstuff_bits(raw_ssr1, 396 - 384, 4);
|
||||
storage->ssr.video_class = unstuff_bits(raw_ssr1, 384 - 384, 8);
|
||||
storage->ssr.app_class = unstuff_bits(raw_ssr2, 336 - 256, 4);
|
||||
storage->ssr.uhs_grade = unstuff_bits(raw_ssr1, 396, 4);
|
||||
storage->ssr.video_class = unstuff_bits(raw_ssr1, 384, 8);
|
||||
storage->ssr.app_class = unstuff_bits(raw_ssr2, 336, 4);
|
||||
|
||||
storage->ssr.au_size = unstuff_bits(raw_ssr1, 428 - 384, 4);
|
||||
storage->ssr.uhs_au_size = unstuff_bits(raw_ssr1, 392 - 384, 4);
|
||||
storage->ssr.au_size = unstuff_bits(raw_ssr1, 428, 4);
|
||||
storage->ssr.uhs_au_size = unstuff_bits(raw_ssr1, 392, 4);
|
||||
|
||||
storage->ssr.perf_enhance = unstuff_bits(raw_ssr2, 328, 8);
|
||||
}
|
||||
|
||||
int sd_storage_parse_perf_enhance(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u8 *buf)
|
||||
{
|
||||
// Check status reg for support.
|
||||
storage->ser.cache = (storage->ssr.perf_enhance >> 2) & BIT(0);
|
||||
storage->ser.cmdq = (storage->ssr.perf_enhance >> 3) & 0x1F;
|
||||
|
||||
if (!sd_storage_get_ext_reg(storage, fno, page, offset, 512, buf))
|
||||
{
|
||||
storage->ser.cache_ext = 0;
|
||||
storage->ser.cmdq_ext = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
storage->ser.cache_ext = buf[4] & BIT(0);
|
||||
storage->ser.cmdq_ext = buf[6] & 0x1F;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _sd_storage_parse_ext_reg(sdmmc_storage_t *storage, u8 *buf, u16 *addr_next)
|
||||
{
|
||||
u16 addr = *addr_next;
|
||||
|
||||
// Address to the next extension.
|
||||
*addr_next = (buf[addr + 41] << 8) | buf[addr + 40];
|
||||
|
||||
u16 sfc = (buf[addr + 1] << 8) | buf[addr];
|
||||
|
||||
u32 reg_sets = buf[addr + 42];
|
||||
|
||||
#ifdef SDMMC_DEBUG_PRINT_SD_REGS
|
||||
for (u32 i = 0; i < reg_sets; i++)
|
||||
{
|
||||
u32 reg_set_addr;
|
||||
memcpy(®_set_addr, &buf[addr + 44 + 4 * i], 4);
|
||||
u16 off = reg_set_addr & 0x1FF;
|
||||
u8 page = reg_set_addr >> 9 & 0xFF;
|
||||
u8 fno = reg_set_addr >> 18 & 0xFF;
|
||||
gfx_printf("Addr: %04X sfc:%02X - fno:%02X, page:%02X, off:%04X\n", addr, sfc, fno, page, off);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Parse Performance Enhance.
|
||||
if (sfc == 2 && reg_sets == 1)
|
||||
{
|
||||
u32 reg_set0_addr;
|
||||
memcpy(®_set0_addr, &buf[addr + 44], 4);
|
||||
u16 off = reg_set0_addr & 0x1FF;
|
||||
u8 page = reg_set0_addr >> 9 & 0xFF;
|
||||
u8 fno = reg_set0_addr >> 18 & 0xFF;
|
||||
|
||||
if (sd_storage_parse_perf_enhance(storage, fno, page, off, buf))
|
||||
storage->ser.valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void sd_storage_get_ext_regs(sdmmc_storage_t *storage, u8 *buf)
|
||||
{
|
||||
DREGPRINTF("SD Extension Registers:\n\n");
|
||||
|
||||
if (!(storage->scr.cmds & BIT(2)))
|
||||
{
|
||||
DREGPRINTF("Not Supported!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sd_storage_get_ext_reg(storage, 0, 0, 0, 512, buf))
|
||||
{
|
||||
DREGPRINTF("Failed to get general info!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
u16 size = (buf[3] << 8) | buf[2];
|
||||
u16 addr_next = 16;
|
||||
u32 num_ext = buf[4];
|
||||
for (u32 i = 0; i < num_ext && addr_next < size; i++)
|
||||
_sd_storage_parse_ext_reg(storage, buf, &addr_next);
|
||||
}
|
||||
|
||||
int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
|
||||
@@ -1545,10 +1697,10 @@ int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
|
||||
// Convert buffer to LE.
|
||||
for (int i = 0; i < SDMMC_CMD_BLOCKSIZE; i += 4)
|
||||
for (u32 i = 0; i < SDMMC_CMD_BLOCKSIZE; i += 4)
|
||||
{
|
||||
storage->raw_ssr[i + 3] = buf[i];
|
||||
storage->raw_ssr[i + 2] = buf[i + 1];
|
||||
@@ -1645,7 +1797,7 @@ void sdmmc_storage_init_wait_sd()
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
|
||||
{
|
||||
u32 tmp = 0;
|
||||
int is_sdsc = 0;
|
||||
bool is_sdsc = 0;
|
||||
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
|
||||
bool bus_uhs_support = _sdmmc_storage_get_bus_uhs_support(bus_width, type);
|
||||
|
||||
@@ -1790,7 +1942,7 @@ int _gc_storage_custom_cmd(sdmmc_storage_t *storage, void *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_1))
|
||||
if (!sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_1))
|
||||
return 0;
|
||||
if (!_sdmmc_storage_check_card_status(resp))
|
||||
return 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2022 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -174,20 +174,30 @@ typedef struct _sd_ssr
|
||||
u8 app_class;
|
||||
u8 au_size;
|
||||
u8 uhs_au_size;
|
||||
u8 perf_enhance;
|
||||
u32 protected_size;
|
||||
} sd_ssr_t;
|
||||
|
||||
typedef struct _sd_ext_reg_t
|
||||
{
|
||||
u8 cmdq;
|
||||
u8 cmdq_ext;
|
||||
u8 cache;
|
||||
u8 cache_ext;
|
||||
int valid;
|
||||
} sd_ext_reg_t;
|
||||
|
||||
/*! SDMMC storage context. */
|
||||
typedef struct _sdmmc_storage_t
|
||||
{
|
||||
sdmmc_t *sdmmc;
|
||||
u32 rca;
|
||||
int has_sector_access;
|
||||
u32 sec_cnt;
|
||||
int is_low_voltage;
|
||||
u32 partition;
|
||||
int initialized;
|
||||
u32 card_power_limit;
|
||||
int is_low_voltage;
|
||||
int has_sector_access;
|
||||
u32 rca;
|
||||
u32 sec_cnt;
|
||||
u32 partition;
|
||||
u32 max_power;
|
||||
u8 raw_cid[0x10];
|
||||
u8 raw_csd[0x10];
|
||||
u8 raw_scr[8];
|
||||
@@ -197,6 +207,7 @@ typedef struct _sdmmc_storage_t
|
||||
mmc_ext_csd_t ext_csd;
|
||||
sd_scr_t scr;
|
||||
sd_ssr_t ssr;
|
||||
sd_ext_reg_t ser;
|
||||
} sdmmc_storage_t;
|
||||
|
||||
typedef struct _sd_func_modes_t
|
||||
@@ -221,9 +232,13 @@ int sdmmc_storage_vendor_sandisk_report(sdmmc_storage_t *storage, void *buf);
|
||||
|
||||
int mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf);
|
||||
|
||||
int sd_storage_get_ext_reg(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u32 len, void *buf);
|
||||
int sd_storage_get_fmodes(sdmmc_storage_t *storage, u8 *buf, sd_func_modes_t *functions);
|
||||
int sd_storage_get_scr(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);
|
||||
|
||||
void sd_storage_get_ext_regs(sdmmc_storage_t *storage, u8 *buf);
|
||||
int sd_storage_parse_perf_enhance(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u8 *buf);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -212,7 +212,7 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
||||
// Use 0x1F mask for all.
|
||||
u8 autocal_pu_status = sdmmc->regs->autocalsts & 0x1F;
|
||||
if (!autocal_pu_status)
|
||||
EPRINTFARGS("SDMMC%d: Comp Pad open!", sdmmc->id + 1);
|
||||
EPRINTFARGS("SDMMC%d: Comp Pad open!", sdmmc->id + 1); // Or resistance is extreme.
|
||||
else if (autocal_pu_status == 0x1F)
|
||||
EPRINTFARGS("SDMMC%d: Comp Pad short to gnd!", sdmmc->id + 1);
|
||||
#endif
|
||||
@@ -394,8 +394,8 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
|
||||
static void _sdmmc_card_clock_enable(sdmmc_t *sdmmc)
|
||||
{
|
||||
// Recalibrate conditionally.
|
||||
if (sdmmc->manual_cal && !sdmmc->powersave_enabled)
|
||||
// Recalibrate periodically if needed.
|
||||
if (sdmmc->periodic_calibration && !sdmmc->powersave_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
if (!sdmmc->powersave_enabled)
|
||||
@@ -414,8 +414,8 @@ static void _sdmmc_card_clock_disable(sdmmc_t *sdmmc)
|
||||
|
||||
void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable)
|
||||
{
|
||||
// Recalibrate periodically for SDMMC1.
|
||||
if (sdmmc->manual_cal && !powersave_enable && sdmmc->card_clock_enabled)
|
||||
// Recalibrate periodically if needed.
|
||||
if (sdmmc->periodic_calibration && !powersave_enable && sdmmc->card_clock_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
sdmmc->powersave_enabled = powersave_enable;
|
||||
@@ -431,7 +431,7 @@ void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable)
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
@@ -439,33 +439,14 @@ static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
case SDMMC_RSP_TYPE_3:
|
||||
case SDMMC_RSP_TYPE_4:
|
||||
case SDMMC_RSP_TYPE_5:
|
||||
if (size < 4)
|
||||
return 0;
|
||||
rsp[0] = sdmmc->regs->rspreg0;
|
||||
rsp[0] = sdmmc->regs->rspreg[0];
|
||||
break;
|
||||
|
||||
case SDMMC_RSP_TYPE_2:
|
||||
if (size < 0x10)
|
||||
return 0;
|
||||
// CRC is stripped, so shifting is needed.
|
||||
u32 tempreg;
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (u32 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;
|
||||
}
|
||||
u32 tempreg = sdmmc->regs->rspreg[3 - i];
|
||||
rsp[i] = tempreg << 8;
|
||||
|
||||
if (i != 0)
|
||||
@@ -480,7 +461,7 @@ static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
int sdmmc_get_cached_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 type)
|
||||
{
|
||||
if (!rsp || sdmmc->expected_rsp_type != type)
|
||||
return 0;
|
||||
@@ -491,18 +472,12 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
case SDMMC_RSP_TYPE_3:
|
||||
case SDMMC_RSP_TYPE_4:
|
||||
case SDMMC_RSP_TYPE_5:
|
||||
if (size < 4)
|
||||
return 0;
|
||||
rsp[0] = sdmmc->rsp[0];
|
||||
break;
|
||||
|
||||
case SDMMC_RSP_TYPE_2:
|
||||
if (size < 16)
|
||||
return 0;
|
||||
rsp[0] = sdmmc->rsp[0];
|
||||
rsp[1] = sdmmc->rsp[1];
|
||||
rsp[2] = sdmmc->rsp[2];
|
||||
rsp[3] = sdmmc->rsp[3];
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
rsp[i] = sdmmc->rsp[i];
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -915,6 +890,7 @@ static void _sdmmc_enable_interrupts(sdmmc_t *sdmmc)
|
||||
sdmmc->regs->errintstsen |= SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR;
|
||||
sdmmc->regs->norintsts = sdmmc->regs->norintsts;
|
||||
sdmmc->regs->errintsts = sdmmc->regs->errintsts;
|
||||
sdmmc->error_sts = 0;
|
||||
}
|
||||
|
||||
static void _sdmmc_mask_interrupts(sdmmc_t *sdmmc)
|
||||
@@ -937,8 +913,9 @@ static u32 _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
|
||||
if (norintsts & SDHCI_INT_ERROR)
|
||||
{
|
||||
#ifdef ERROR_EXTRA_PRINTING
|
||||
EPRINTFARGS("SDMMC%d: norintsts %08X, errintsts %08X", sdmmc->id + 1, norintsts, errintsts);
|
||||
EPRINTFARGS("SDMMC%d: intsts %08X, errintsts %08X", sdmmc->id + 1, norintsts, errintsts);
|
||||
#endif
|
||||
sdmmc->error_sts = errintsts;
|
||||
sdmmc->regs->errintsts = errintsts;
|
||||
return SDMMC_MASKINT_ERROR;
|
||||
}
|
||||
@@ -993,7 +970,7 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp)
|
||||
if (!result)
|
||||
return 0;
|
||||
|
||||
_sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1);
|
||||
_sdmmc_cache_rsp(sdmmc, rsp, SDMMC_RSP_TYPE_1);
|
||||
|
||||
return _sdmmc_wait_card_busy(sdmmc);
|
||||
}
|
||||
@@ -1003,8 +980,8 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
|
||||
if (!sdmmc->card_clock_enabled)
|
||||
return 0;
|
||||
|
||||
// Recalibrate periodically for SDMMC1.
|
||||
if (sdmmc->manual_cal && sdmmc->powersave_enabled)
|
||||
// Recalibrate periodically if needed.
|
||||
if (sdmmc->periodic_calibration && sdmmc->powersave_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
bool should_disable_sd_clock = false;
|
||||
@@ -1120,7 +1097,7 @@ static int _sdmmc_update_sdma(sdmmc_t *sdmmc)
|
||||
|
||||
static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out)
|
||||
{
|
||||
int has_req_or_check_busy = req || cmd->check_busy;
|
||||
bool has_req_or_check_busy = req || cmd->check_busy;
|
||||
if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, has_req_or_check_busy))
|
||||
return 0;
|
||||
|
||||
@@ -1158,13 +1135,13 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
||||
EPRINTFARGS("SDMMC%d: Transfer error!", sdmmc->id + 1);
|
||||
#endif
|
||||
DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result,
|
||||
sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3);
|
||||
sdmmc->regs->rspreg[0], sdmmc->regs->rspreg[1], sdmmc->regs->rspreg[2], sdmmc->regs->rspreg[3]);
|
||||
if (result)
|
||||
{
|
||||
if (cmd->rsp_type)
|
||||
{
|
||||
sdmmc->expected_rsp_type = cmd->rsp_type;
|
||||
result = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type);
|
||||
result = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, cmd->rsp_type);
|
||||
#ifdef ERROR_EXTRA_PRINTING
|
||||
if (!result)
|
||||
EPRINTFARGS("SDMMC%d: Unknown response type!", sdmmc->id + 1);
|
||||
@@ -1193,10 +1170,10 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
||||
*blkcnt_out = blkcnt;
|
||||
|
||||
if (req->is_auto_stop_trn)
|
||||
sdmmc->rsp3 = sdmmc->regs->rspreg3;
|
||||
sdmmc->stop_trn_rsp = sdmmc->regs->rspreg[3];
|
||||
}
|
||||
|
||||
if (cmd->check_busy || req)
|
||||
if (has_req_or_check_busy)
|
||||
{
|
||||
result = _sdmmc_wait_card_busy(sdmmc);
|
||||
#ifdef ERROR_EXTRA_PRINTING
|
||||
@@ -1248,7 +1225,7 @@ static void _sdmmc_config_sdmmc1_pads(bool discharge)
|
||||
u32 level = GPIO_LOW;
|
||||
u32 output = GPIO_OUTPUT_DISABLE;
|
||||
|
||||
// Set values for dicharging.
|
||||
// Set values for discharging.
|
||||
if (discharge)
|
||||
{
|
||||
function = GPIO_MODE_GPIO;
|
||||
@@ -1304,7 +1281,7 @@ static int _sdmmc_config_sdmmc1(bool t210b01)
|
||||
// Enable SD card power. Powers LDO2 also.
|
||||
PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_PULL_DOWN | 2;
|
||||
gpio_direction_output(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH);
|
||||
usleep(10000);
|
||||
usleep(10000); // Minimum 3 to 10 ms.
|
||||
|
||||
// Inform IO pads that voltage is gonna be 3.3V.
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_33V_SDMMC1;
|
||||
@@ -1385,7 +1362,7 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type)
|
||||
if (sdmmc->t210b01)
|
||||
vref_sel = 0;
|
||||
else
|
||||
sdmmc->manual_cal = 1;
|
||||
sdmmc->periodic_calibration = 1;
|
||||
break;
|
||||
|
||||
case SDMMC_2:
|
||||
@@ -1419,6 +1396,8 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type)
|
||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
||||
return 0;
|
||||
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
|
||||
// Calibrate pads.
|
||||
_sdmmc_autocal_execute(sdmmc, power);
|
||||
|
||||
@@ -1506,8 +1485,8 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
||||
if (!sdmmc->card_clock_enabled)
|
||||
return 0;
|
||||
|
||||
// Recalibrate periodically for SDMMC1.
|
||||
if (sdmmc->manual_cal && sdmmc->powersave_enabled)
|
||||
// Recalibrate periodically if needed.
|
||||
if (sdmmc->periodic_calibration && sdmmc->powersave_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
int should_disable_sd_clock = 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2023 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -101,6 +101,7 @@
|
||||
#define SDHCI_CMD_TYPE_SUSPEND (1U << 6)
|
||||
#define SDHCI_CMD_TYPE_RESUME (2U << 6)
|
||||
#define SDHCI_CMD_TYPE_ABORT (3U << 6)
|
||||
#define SDHCI_CMD_SPI_CS_LOW BIT(7)
|
||||
#define SDHCI_CMD_IDX(cmd) ((cmd) << 8)
|
||||
|
||||
|
||||
@@ -170,10 +171,10 @@
|
||||
#define SDHCI_INT_ERROR BIT(15)
|
||||
|
||||
/*! SDMMC error interrupt status and control. 0x32/0x36. */
|
||||
#define SDHCI_ERR_INT_TIMEOUT BIT(0)
|
||||
#define SDHCI_ERR_INT_CRC BIT(1)
|
||||
#define SDHCI_ERR_INT_END_BIT BIT(2)
|
||||
#define SDHCI_ERR_INT_INDEX BIT(3)
|
||||
#define SDHCI_ERR_INT_CMD_TIMEOUT BIT(0)
|
||||
#define SDHCI_ERR_INT_CMD_CRC BIT(1)
|
||||
#define SDHCI_ERR_INT_CMD_END_BIT BIT(2)
|
||||
#define SDHCI_ERR_INT_CMD_INDEX BIT(3)
|
||||
#define SDHCI_ERR_INT_DATA_TIMEOUT BIT(4)
|
||||
#define SDHCI_ERR_INT_DATA_CRC BIT(5)
|
||||
#define SDHCI_ERR_INT_DATA_END_BIT BIT(6)
|
||||
@@ -190,8 +191,8 @@
|
||||
#define SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR \
|
||||
(SDHCI_ERR_INT_AUTO_CMD12 | SDHCI_ERR_INT_DATA_END_BIT | \
|
||||
SDHCI_ERR_INT_DATA_CRC | SDHCI_ERR_INT_DATA_TIMEOUT | \
|
||||
SDHCI_ERR_INT_INDEX | SDHCI_ERR_INT_END_BIT | \
|
||||
SDHCI_ERR_INT_CRC | SDHCI_ERR_INT_TIMEOUT)
|
||||
SDHCI_ERR_INT_CMD_INDEX | SDHCI_ERR_INT_CMD_END_BIT | \
|
||||
SDHCI_ERR_INT_CMD_CRC | SDHCI_ERR_INT_CMD_TIMEOUT)
|
||||
|
||||
/*! Host Capability 1. 0x40. */
|
||||
#define SDHCI_CAP_TM_CLK_FREQ_MASK 0x3F
|
||||
@@ -285,14 +286,15 @@ typedef struct _sdmmc_t
|
||||
u32 card_clock;
|
||||
u32 clock_stopped;
|
||||
int powersave_enabled;
|
||||
int manual_cal;
|
||||
int periodic_calibration;
|
||||
int card_clock_enabled;
|
||||
int venclkctl_set;
|
||||
u32 venclkctl_tap;
|
||||
u32 expected_rsp_type;
|
||||
u32 dma_addr_next;
|
||||
u32 rsp[4];
|
||||
u32 rsp3;
|
||||
u32 stop_trn_rsp;
|
||||
u32 error_sts;
|
||||
int t210b01;
|
||||
} sdmmc_t;
|
||||
|
||||
@@ -323,7 +325,7 @@ void sdmmc_save_tap_value(sdmmc_t *sdmmc);
|
||||
void sdmmc_setup_drv_type(sdmmc_t *sdmmc, u32 type);
|
||||
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type);
|
||||
void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable);
|
||||
int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type);
|
||||
int sdmmc_get_cached_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 type);
|
||||
int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd);
|
||||
int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp);
|
||||
bool sdmmc_get_sd_inserted();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2023 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -39,10 +39,7 @@ typedef struct _t210_sdmmc_t
|
||||
/* 0x08 */ vu32 argument;
|
||||
/* 0x0C */ vu16 trnmod;
|
||||
/* 0x0E */ vu16 cmdreg;
|
||||
/* 0x10 */ vu32 rspreg0;
|
||||
/* 0x14 */ vu32 rspreg1;
|
||||
/* 0x18 */ vu32 rspreg2;
|
||||
/* 0x1C */ vu32 rspreg3;
|
||||
/* 0x10 */ vu32 rspreg[4];
|
||||
/* 0x20 */ vu32 bdata; // Buffer data port.
|
||||
/* 0x24 */ vu32 prnsts;
|
||||
/* 0x28 */ vu8 hostctl;
|
||||
|
||||
Reference in New Issue
Block a user