Compare commits

...

7 Commits
v5.5.6 ... v1.3

Author SHA1 Message Date
Kostas Missos
8cb76be5fb CTCaer mod v1.3 2018-05-14 02:12:41 +03:00
Kostas Missos
075a9e0a9e Add missing include 2018-05-14 01:45:39 +03:00
Kostas Missos
bda777b1da Bugfixes
* Make button check delay 1s to avoid button repressing from "button ip" state
* Dumping: Fix part logic and honor user actions on ignoring errors
* Add time taken to dump emmc
2018-05-14 01:42:59 +03:00
Kostas Missos
eed1c6945d [Tools] Add fuse/kfuse dumping to SD 2018-05-14 01:39:00 +03:00
Kostas Missos
09267b884d [Info] Add eMMC and SD info printing 2018-05-14 01:38:10 +03:00
Kostas Missos
cbd964306d [sdmmc] Fixes Part 2
Now that the cid/csd/ssr/etc bytes/bitfields are correct:
* MMC/SD: Add cid/csd parsing and use new cid/csd variables
* SD: Add ssr (sd status) reading/parsing
2018-05-14 01:33:42 +03:00
Kostas Missos
4bfdee8b20 [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
2018-05-14 01:28:27 +03:00
6 changed files with 723 additions and 131 deletions

View File

@@ -46,6 +46,56 @@
#include "se_t210.h"
#include "hos.h"
#include "pkg1.h"
#include "mmc.h"
//TODO: ugly.
sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage;
FATFS sd_fs;
int sd_mounted;
int sd_mount()
{
if (sd_mounted)
return 1;
if (sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11) &&
f_mount(&sd_fs, "", 1) == FR_OK)
{
sd_mounted = 1;
return 1;
}
return 0;
}
void *sd_file_read(char *path)
{
FIL fp;
if (f_open(&fp, path, FA_READ) != FR_OK)
return NULL;
u32 size = f_size(&fp);
void *buf = malloc(size);
u8 *ptr = buf;
while (size > 0)
{
u32 rsize = MIN(size, 512);
if (f_read(&fp, ptr, rsize, NULL) != FR_OK)
{
free(buf);
return NULL;
}
ptr += rsize;
size -= rsize;
}
f_close(&fp);
return buf;
}
void panic(u32 val)
{
@@ -252,8 +302,36 @@ void print_fuseinfo()
gfx_printf(&gfx_con, "%k(Unlocked) fuse cache:\n\n%k", 0xFFFF9955, 0xFFFFFFFF);
gfx_hexdump(&gfx_con, 0x7000F900, (u8 *)0x7000F900, 0x2FC);
sleep(100000);
btn_wait();
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
sleep(1000000);
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (!sd_mount())
{
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n",
0xFF0000FF, 0xFFFFFFFF);
}
else
{
FIL fuseFp;
char fuseFilename[9];
memcpy(fuseFilename, "fuse.bin", 8);
fuseFilename[8] = 0;
if (f_open(&fuseFp, fuseFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
{
f_write(&fuseFp, (u8 *)0x7000F900, 0x2FC, NULL);
f_close(&fuseFp);
gfx_puts(&gfx_con, "\nDone!\n");
}
else
gfx_printf(&gfx_con, "%k\nError creating fuse.bin file.%k\n", 0xFF0000FF, 0xFFFFFFFF);
}
sleep(2000000);
btn_wait();
}
}
void print_kfuseinfo()
@@ -268,7 +346,248 @@ void print_kfuseinfo()
else
gfx_hexdump(&gfx_con, 0, (u8 *)buf, KFUSE_NUM_WORDS * 4);
sleep(100000);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
sleep(1000000);
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (!sd_mount())
{
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n",
0xFF0000FF, 0xFFFFFFFF);
}
else
{
FIL kfuseFp;
char kfuseFilename[10];
memcpy(kfuseFilename, "kfuse.bin", 9);
kfuseFilename[9] = 0;
if (f_open(&kfuseFp, kfuseFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
{
f_write(&kfuseFp, (u8 *)buf, KFUSE_NUM_WORDS * 4, NULL);
f_close(&kfuseFp);
gfx_puts(&gfx_con, "\nDone!\n");
}
else
gfx_printf(&gfx_con, "%k\nError creating kfuse.bin file.%k\n", 0xFF0000FF, 0xFFFFFFFF);
}
sleep(2000000);
btn_wait();
}
}
void print_mmc_info()
{
gfx_clear(&gfx_ctxt, 0xFF000000);
gfx_con_setpos(&gfx_con, 0, 0);
static const u32 SECTORS_TO_MIB_COEFF = 0x800;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if(!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF);
goto out;
}
else
{
u16 card_type;
u32 speed;
gfx_printf(&gfx_con, "%kCard IDentification:%k\n", 0xFFFFDD00, 0xFFFFFFFF);
switch (storage.csd.mmca_vsn)
{
case 0: /* MMC v1.0 - v1.2 */
case 1: /* MMC v1.4 */
gfx_printf(&gfx_con,
" Vendor ID: %03X\n\
Model: %c%c%c%c%c%c%c\n\
HW rev: %X\n\
FW rev: %X\n\
S/N: %03X\n\
Month/Year: %02d/%04d\n\n",
storage.cid.manfid,
storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2],
storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5],
storage.cid.prod_name[6], storage.cid.hwrev, storage.cid.fwrev,
storage.cid.serial, storage.cid.month, storage.cid.year);
break;
case 2: /* MMC v2.0 - v2.2 */
case 3: /* MMC v3.1 - v3.3 */
case 4: /* MMC v4 */
gfx_printf(&gfx_con,
" Vendor ID: %X\n\
Card/BGA: %X\n\
OEM ID: %02X\n\
Model: %c%c%c%c%c%c\n\
Prd Rev: %X\n\
S/N: %04X\n\
Month/Year: %02d/%04d\n\n",
storage.cid.manfid, storage.cid.card_bga, storage.cid.oemid,
storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2],
storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5],
storage.cid.prv, storage.cid.serial, storage.cid.month, storage.cid.year);
break;
default:
gfx_printf(&gfx_con, "%keMMC has unknown MMCA version %d%k\n", 0xFF0000FF, storage.csd.mmca_vsn, 0xFFFFFFFF);
break;
}
if (storage.csd.structure == 0)
gfx_printf(&gfx_con, "%kUnknown CSD structure%k\n", 0xFF0000FF, 0xFFFFFFFF);
else
{
gfx_printf(&gfx_con, "%kExtended Card-Specific Data V1.%d:%k\n",
0xFFFFDD00, storage.ext_csd.ext_struct, 0xFFFFFFFF);
card_type = storage.ext_csd.card_type;
u8 card_type_support[96];
u8 pos_type = 0;
if (card_type & EXT_CSD_CARD_TYPE_HS_26)
{
memcpy(card_type_support, "HS26", 4);
speed = (26 << 16) | 26;
pos_type += 4;
}
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
{
memcpy(card_type_support + pos_type, ", HS52", 6);
speed = (52 << 16) | 52;
pos_type += 6;
}
if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
{
memcpy(card_type_support + pos_type, ", DDR52_1.8V", 12);
speed = (52 << 16) | 104;
pos_type += 12;
}
if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
{
memcpy(card_type_support + pos_type, ", HS200_1.8V", 12);
speed = (200 << 16) | 200;
pos_type += 12;
}
if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
{
memcpy(card_type_support + pos_type, ", HS400_1.8V", 12);
speed = (200 << 16) | 400;
pos_type += 12;
}
card_type_support[pos_type] = 0;
gfx_printf(&gfx_con,
" Spec Version: %02X\n\
Extended Rev: 1.%d\n\
Dev Version: %d\n\
Cmd Classes: %02X\n\
Capacity: %s\n\
Max Speed: %d MB/s (%d MHz)\n\
Type Support: %s\n\n",
storage.csd.mmca_vsn, storage.ext_csd.rev, storage.ext_csd.dev_version, storage.csd.cmdclass,
storage.csd.capacity == (4096 * 512) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF, card_type_support);
u32 boot_size = storage.ext_csd.boot_mult << 17;
u32 rpmb_size = storage.ext_csd.rpmb_mult << 17;
gfx_printf(&gfx_con, "%keMMC Partitions:%k\n", 0xFFFFDD00, 0xFFFFFFFF);
gfx_printf(&gfx_con, " 1: %kBOOT0 %kSize: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF00FF96, 0xFFFFFFFF,
boot_size / 1024, boot_size / 1024 / 512);
gfx_printf(&gfx_con, " 2: %kBOOT1 %kSize: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF00FF96, 0xFFFFFFFF,
boot_size / 1024, boot_size / 1024 / 512);
gfx_printf(&gfx_con, " 3: %kRPMB %kSize: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF00FF96, 0xFFFFFFFF,
rpmb_size / 1024, rpmb_size / 1024 / 512);
gfx_printf(&gfx_con, " 0: %kGPP (USER) %kSize: %05d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF00FF96, 0xFFFFFFFF,
storage.sec_cnt / SECTORS_TO_MIB_COEFF, storage.sec_cnt);
gfx_printf(&gfx_con, "%kGPP (eMMC USER) partition table:%k\n", 0xFFFFDD00, 0xFFFFFFFF);
sdmmc_storage_set_mmc_partition(&storage, 0);
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
int gpp_idx = 0;
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
gfx_printf(&gfx_con, " %02d: %k%s%k\n Size: % 5d MiB (LBA Sectors 0x%07X, LBA Range: %08X-%08X)%k\n",
gpp_idx++, 0xFF14FDAE, part->name, 0xFFFFFFFF, (part->lba_end - part->lba_start + 1) / SECTORS_TO_MIB_COEFF,
part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end, 0xFFFFFFFF);
}
}
}
out:
sdmmc_storage_end(&storage);
sleep(1000000);
btn_wait();
}
void print_sdcard_info()
{
gfx_clear(&gfx_ctxt, 0xFF000000);
gfx_con_setpos(&gfx_con, 0, 0);
static const u32 SECTORS_TO_MIB_COEFF = 0x800;
if (!sd_mount())
{
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n",
0xFF0000FF, 0xFFFFFFFF);
}
else
{
u32 capacity;
gfx_printf(&gfx_con, "%kCard IDentification:%k\n", 0xFFFFDD00, 0xFFFFFFFF);
gfx_printf(&gfx_con,
" Vendor ID: %02x\n\
OEM ID: %c%c\n\
Model: %c%c%c%c%c\n\
HW rev: %X\n\
FW rev: %X\n\
S/N: %08x\n\
Month/Year: %02d/%04d\n\n",
sd_storage.cid.manfid, (sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF,
sd_storage.cid.prod_name[0], sd_storage.cid.prod_name[1], sd_storage.cid.prod_name[2],
sd_storage.cid.prod_name[3], sd_storage.cid.prod_name[4],
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
sd_storage.cid.month, sd_storage.cid.year);
gfx_printf(&gfx_con, "%kCard-Specific Data V%d.0:%k\n", 0xFFFFDD00, sd_storage.csd.structure + 1, 0xFFFFFFFF);
switch(sd_storage.csd.structure)
{
case 0:
capacity = (sd_storage.csd.capacity << sd_storage.csd.read_blkbits) / 1024 / 1024;
gfx_printf(&gfx_con,
" Cmd Classes: %02X\n\
Capacity: %d MiB\n",
sd_storage.csd.cmdclass, capacity);
break;
case 1:
capacity = (sd_storage.csd.c_size << sd_storage.csd.read_blkbits) / 1024;
gfx_printf(&gfx_con,
" Cmd Classes: %02X\n\
Capacity: %d MiB\n",
sd_storage.csd.cmdclass, capacity);
break;
}
gfx_printf(&gfx_con,
" Bus Width: %d\n\
Speed Class: %d\n\
UHS Grade: U%d\n\
Video Class: V%d\n\
App perf class: A%d\n\n",
sd_storage.ssr.bus_width, sd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade,
sd_storage.ssr.video_class, sd_storage.ssr.app_class);
gfx_puts(&gfx_con, "Acquiring FAT volume info...\n\n");
f_getfree("", &sd_fs.free_clst, NULL);
gfx_printf(&gfx_con, "%kFound %s volume:%k\n Free: %d MiB\n", 0xFFFFDD00,
sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", 0xFFFFFFFF,
sd_fs.free_clst * sd_fs.csize / SECTORS_TO_MIB_COEFF);
}
sleep(1000000);
btn_wait();
}
@@ -289,7 +608,8 @@ void print_tsec_key()
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
if (!pkg1_id)
{
gfx_printf(&gfx_con, "%kCould not identify package 1 version to read TSEC firmware (= '%s').%k\n", 0xFF0000FF, (char *)pkg1 + 0x10, 0xFFFFFFFF);
gfx_printf(&gfx_con, "%kCould not identify package 1 version to read TSEC firmware (= '%s').%k\n",
0xFF0000FF, (char *)pkg1 + 0x10, 0xFFFFFFFF);
goto out;
}
@@ -312,7 +632,7 @@ void print_tsec_key()
out:;
free(pkg1);
sdmmc_storage_end(&storage);
sleep(100000);
sleep(1000000);
btn_wait();
}
@@ -335,60 +655,11 @@ void power_off()
i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
}
//TODO: ugly.
sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage;
FATFS sd_fs;
int sd_mounted;
int sd_mount()
{
if (sd_mounted)
return 1;
if (sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11) &&
f_mount(&sd_fs, "", 1) == FR_OK)
{
sd_mounted = 1;
return 1;
}
return 0;
}
void *sd_file_read(char *path)
{
FIL fp;
if (f_open(&fp, path, FA_READ) != FR_OK)
return NULL;
u32 size = f_size(&fp);
void *buf = malloc(size);
u8 *ptr = buf;
while (size > 0)
{
u32 rsize = MIN(size, 512);
if (f_read(&fp, ptr, rsize, NULL) != FR_OK)
{
free(buf);
return NULL;
}
ptr += rsize;
size -= rsize;
}
f_close(&fp);
return buf;
}
int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
{
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
static const u32 MULTIPART_SPLIT_SIZE = (1u << 31);
static const u32 SECTORS_TO_MB_COEFF = 0x800;
static const u32 SECTORS_TO_MIB_COEFF = 0x800;
u32 totalSectors = part->lba_end - part->lba_start + 1;
u32 currPartIdx = 0;
@@ -406,9 +677,9 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
memcpy(partialIdxFilename, "partial.idx", 11);
partialIdxFilename[11] = 0;
gfx_printf(&gfx_con, "SD Card free space: %dMB, Total dump size %dMB\n",
sd_fs.free_clst * sd_fs.csize / SECTORS_TO_MB_COEFF,
totalSectors / SECTORS_TO_MB_COEFF);
gfx_printf(&gfx_con, "SD Card free space: %d MiB, Total dump size %d MiB\n",
sd_fs.free_clst * sd_fs.csize / SECTORS_TO_MIB_COEFF,
totalSectors / SECTORS_TO_MIB_COEFF);
// Check if the USER partition or the RAW eMMC fits the sd card free space
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
@@ -446,7 +717,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
}
// Check if filesystem is FAT32 or the free space is smaller and dump in parts
if (((sd_fs.fs_type != FS_EXFAT) || isSmallSdCard) && totalSectors > (FAT32_FILESIZE_LIMIT/NX_EMMC_BLOCKSIZE))
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT/NX_EMMC_BLOCKSIZE)) | isSmallSdCard)
{
static const u32 MULTIPART_SPLIT_SECTORS = MULTIPART_SPLIT_SIZE/NX_EMMC_BLOCKSIZE;
numSplitParts = (totalSectors+MULTIPART_SPLIT_SECTORS-1)/MULTIPART_SPLIT_SECTORS;
@@ -530,6 +801,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
free(buf);
return 0;
}
// Sd card fatal error.
if (res && !ignoreWriteErrors)
{
gfx_printf(&gfx_con, "%k\nPress any key and try again.%k\n",
@@ -564,25 +836,25 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
0xFF0000FF, num, lba_curr, ++retryCount, 0xFFFFFFFF);
sleep(500000);
if (retryCount >= 10)
if (retryCount >= 10)
goto out;
}
res = f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
if (res && !ignoreWriteErrors)
{
gfx_printf(&gfx_con, "%kFatal error %d when writing to SD Card%k\n\
Press VOL to abort and try again\nPress POWER to ignore errors (will produce a corrupt dump)",
gfx_printf(&gfx_con, "%k\nFatal error %d when writing to SD Card%k\n\n\
Press VOL to abort and try again.\nPress POWER to ignore errors (will produce a corrupt dump).\n",
0xFF0000FF, res, 0xFFFFFFFF);
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
bytesWritten = MULTIPART_SPLIT_SIZE - num * NX_EMMC_BLOCKSIZE;
currPartIdx--;
ignoreWriteErrors = 1;
}
else
{
ignoreWriteErrors = 1;
bytesWritten = MULTIPART_SPLIT_SIZE - num * NX_EMMC_BLOCKSIZE;
currPartIdx--;
}
}
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
@@ -612,8 +884,9 @@ out:;
if(partialDumpInProgress)
{
f_unlink(partialIdxFilename);
gfx_printf(&gfx_con, "\n\nYou can now join the files and get the complete raw eMMC dump.\n");
gfx_printf(&gfx_con, "\n\nYou can now join the files and get the complete raw eMMC dump.");
}
gfx_putc(&gfx_con, '\n');
return 1;
}
@@ -628,12 +901,13 @@ typedef enum
static void dump_emmc_selected(dumpType_t dumpType)
{
u32 timer = 0;
gfx_clear(&gfx_ctxt, 0xFF000000);
gfx_con_setpos(&gfx_con, 0, 0);
if (!sd_mount())
{
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
gfx_printf(&gfx_con, "%kFailed to init/mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
goto out;
}
else
@@ -652,6 +926,7 @@ static void dump_emmc_selected(dumpType_t dumpType)
}
int i = 0;
timer = get_tmr();
if (dumpType & DUMP_BOOT)
{
static const u32 BOOT_PART_SIZE = 0x400000;
@@ -717,11 +992,12 @@ static void dump_emmc_selected(dumpType_t dumpType)
}
}
gfx_printf(&gfx_con, "%kTime taken: %d seconds.%k\n", 0xFF00FF96, (get_tmr() - timer) / 1000000, 0xFFFFFFFF);
sdmmc_storage_end(&storage);
gfx_puts(&gfx_con, "Done. Press any key.\n");
gfx_puts(&gfx_con, "\nDone. Press any key.\n");
out:;
sleep(100000);
sleep(1000000);
btn_wait();
}
@@ -823,7 +1099,7 @@ out:;
free(pkg1);
free(secmon);
free(warmboot);
sleep(100000);
sleep(1000000);
btn_wait();
}
@@ -929,6 +1205,8 @@ ment_t ment_cinfo[] = {
MDEF_HANDLER("Print fuse info", print_fuseinfo),
MDEF_HANDLER("Print kfuse info", print_kfuseinfo),
MDEF_HANDLER("Print TSEC keys", print_tsec_key),
MDEF_HANDLER("Print eMMC info", print_mmc_info),
MDEF_HANDLER("Print SD Card info", print_sdcard_info),
MDEF_END()
};
menu_t menu_cinfo = {
@@ -962,7 +1240,7 @@ ment_t ment_top[] = {
};
menu_t menu_top = {
ment_top,
"hekate - ipl", 0, 0
"hekate - ipl (CTCaer mod v1.3)", 0, 0
};
extern void pivot_stack(u32 stack_top);

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,76 @@ 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 void _mmc_storage_parse_cid(sdmmc_storage_t *storage)
{
u32 *raw_cid = (u32 *)&(storage->raw_cid);
switch (storage->csd.mmca_vsn)
{
case 0: /* MMC v1.0 - v1.2 */
case 1: /* MMC v1.4 */
storage->cid.prod_name[6] = unstuff_bits(raw_cid, 48, 8);
storage->cid.manfid = unstuff_bits(raw_cid, 104, 24);
storage->cid.hwrev = unstuff_bits(raw_cid, 44, 4);
storage->cid.fwrev = unstuff_bits(raw_cid, 40, 4);
storage->cid.serial = unstuff_bits(raw_cid, 16, 24);
break;
case 2: /* MMC v2.0 - v2.2 */
case 3: /* MMC v3.1 - v3.3 */
case 4: /* MMC v4 */
storage->cid.manfid = unstuff_bits(raw_cid, 120, 8);
storage->cid.card_bga = unstuff_bits(raw_cid, 112, 2);
storage->cid.oemid = unstuff_bits(raw_cid, 104, 8);
storage->cid.prv = unstuff_bits(raw_cid, 48, 8);
storage->cid.serial = unstuff_bits(raw_cid, 16, 32);
break;
default:
break;
}
storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8);
storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8);
storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8);
storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8);
storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8);
storage->cid.prod_name[5] = unstuff_bits(raw_cid, 56, 8);
storage->cid.month = unstuff_bits(raw_cid, 12, 4);
storage->cid.year = unstuff_bits(raw_cid, 8, 4) + 1997;
if (storage->ext_csd.rev >= 5)
{
if (storage->cid.year < 2010)
storage->cid.year += 16;
}
}
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.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);
}
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 +330,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 +460,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,9 +468,10 @@ 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");
_mmc_storage_parse_csd(storage);
if (!sdmmc_setup_clock(storage->sdmmc, 1))
return 0;
@@ -412,7 +485,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 +503,28 @@ 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");
_mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd
//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 +562,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 +597,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 +656,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 +691,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 +783,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 +791,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;
@@ -712,8 +822,115 @@ int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf)
return sdmmc_setup_clock(storage->sdmmc, 7);
}
static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
{
u32 *raw_ssr = (u32 *)&(storage->raw_ssr);
storage->ssr.bus_width = unstuff_bits(raw_ssr, 510 - 384, 2) & SD_BUS_WIDTH_4 ? 4 : 1;
switch(unstuff_bits(raw_ssr, 440 - 384, 8))
{
case 0:
storage->ssr.speed_class = 0;
break;
case 1:
storage->ssr.speed_class = 2;
break;
case 2:
storage->ssr.speed_class = 4;
break;
case 3:
storage->ssr.speed_class = 6;
break;
case 4:
storage->ssr.speed_class = 10;
break;
default:
storage->ssr.speed_class = unstuff_bits(raw_ssr, 440 - 384, 8);
break;
}
storage->ssr.uhs_grade = unstuff_bits(raw_ssr, 396 - 384, 4);
storage->ssr.video_class = unstuff_bits(raw_ssr, 384 - 384, 8);
storage->ssr.app_class = unstuff_bits(raw_ssr + 16, 472 + 4 - 384, 4);
}
static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
{
sdmmc_cmd_t cmdbuf;
sdmmc_init_cmd(&cmdbuf, SD_APP_SD_STATUS, 0, SDMMC_RSP_TYPE_1, 0);
sdmmc_req_t reqbuf;
reqbuf.buf = buf;
reqbuf.blksize = 64;
reqbuf.num_sectors = 1;
reqbuf.is_write = 0;
reqbuf.is_multi_block = 0;
reqbuf.is_auto_cmd12 = 0;
if (!(storage->csd.cmdclass & CCC_APP_SPEC)) {
DPRINTF("[sd] ssr: Card lacks mandatory SD Status function\n");
return 0;
}
if (!_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, 0))
return 0;
u32 tmp = 0;
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
//Prepare buffer for unstuff_bits
for (int i = 0; i < 64; i+=4)
{
storage->raw_ssr[i + 3] = buf[i];
storage->raw_ssr[i + 2] = buf[i + 1];
storage->raw_ssr[i + 1] = buf[i + 2];
storage->raw_ssr[i] = buf[i + 3];
}
_sd_storage_parse_ssr(storage);
//gfx_hexdump(&gfx_con, 0, storage->raw_ssr, 64);
return _sdmmc_storage_check_result(tmp);
}
static void _sd_storage_parse_cid(sdmmc_storage_t *storage)
{
u32 *raw_cid = (u32 *)&(storage->raw_cid);
storage->cid.manfid = unstuff_bits(raw_cid, 120, 8);
storage->cid.oemid = unstuff_bits(raw_cid, 104, 16);
storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8);
storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8);
storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8);
storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8);
storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8);
storage->cid.hwrev = unstuff_bits(raw_cid, 60, 4);
storage->cid.fwrev = unstuff_bits(raw_cid, 56, 4);
storage->cid.serial = unstuff_bits(raw_cid, 24, 32);
storage->cid.month = unstuff_bits(raw_cid, 8, 4);
storage->cid.year = unstuff_bits(raw_cid, 12, 8) + 2000;
}
static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
{
u32 *raw_csd = (u32 *)&(storage->raw_csd);
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);
switch(storage->csd.structure)
{
case 0:
storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2);
break;
case 1:
storage->csd.c_size = (1 + unstuff_bits(raw_csd, 48, 22));
storage->csd.capacity = storage->csd.c_size << 10;
storage->csd.read_blkbits = 9;
break;
}
}
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,44 +944,40 @@ 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");
_sd_storage_parse_cid(storage);
if (!_sd_storage_get_rca(storage))
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");
//Parse CSD.
u32 *csd = (u32 *)storage->csd;
u32 csd_struct = unstuff_bits(csd, 126, 2);
switch (csd_struct)
_sd_storage_parse_csd(storage);
switch (storage->csd.structure)
{
case 0:
storage->sec_cnt = (1 + unstuff_bits(csd, 62, 12)) << (unstuff_bits(csd, 47, 3) + 2);
storage->sec_cnt = storage->csd.capacity;
break;
case 1:
storage->sec_cnt = (1 + unstuff_bits(csd, 48, 22)) << 10;
storage->sec_cnt = storage->csd.c_size << 10;
break;
default:
DPRINTF("[sd] Unknown CSD structure %d\n", csd_struct);
//TODO: I've encountered this with one of my SD cards, but
// according to the spec only version 0 and 1 are
// supposed to be in use (mine was version 2).
//return 0;
DPRINTF("[sd] Unknown CSD structure %d\n", storage->csd.structure);
break;
}
@@ -791,11 +1004,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 +1030,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))
{
@@ -829,6 +1042,10 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
sdmmc_sd_clock_ctrl(sdmmc, 1);
// Parse additional card info from sd status
if (_sd_storage_get_ssr(storage, buf))
DPRINTF("[sd] got sd status\n");
free(buf);
return 1;
}
@@ -845,7 +1062,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;