git subrepo clone --force --branch=exo2 https://github.com/m4xw/emummc

subrepo:
  subdir:   "emummc"
  merged:   "3791be9f"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "exo2"
  commit:   "3791be9f"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
This commit is contained in:
Michael Scire 2020-06-08 16:26:55 -07:00 committed by SciresM
parent 6c145d76c7
commit f82954e98b
29 changed files with 1653 additions and 871 deletions

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018-2019 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,
@ -20,6 +20,7 @@
#include <stdio.h>
#include "sdmmc.h"
#include "mmc.h"
#include "nx_sd.h"
#include "sd.h"
#include "../utils/types.h"
#include "../utils/util.h"
@ -188,6 +189,7 @@ static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *re
if (_sdmmc_storage_check_result(*resp))
if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state)
return 1;
return 0;
}
@ -201,6 +203,7 @@ static int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage)
{
sdmmc_cmd_t cmd;
sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0);
return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0);
}
@ -210,7 +213,9 @@ static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage, void *buf)
sdmmc_init_cmd(&cmd, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0);
if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0))
return 0;
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
return 1;
}
@ -225,7 +230,9 @@ static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage, void *buf)
sdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0);
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0))
return 0;
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
return 1;
}
@ -247,9 +254,9 @@ static int _sdmmc_storage_check_status(sdmmc_storage_t *storage)
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;
sdmmc_cmd_t cmdbuf;
sdmmc_req_t reqbuf;
u32 tmp = 0;
sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0);
@ -261,12 +268,13 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
reqbuf.is_auto_cmd12 = 1;
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;
}
@ -274,36 +282,58 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
{
if (!_sdmmc_storage_go_idle_state(storage))
return 0;
sdmmc_end(storage->sdmmc);
return 1;
}
static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write)
{
u8 *bbuf = (u8 *)buf;
bool first_reinit = false;
while (num_sectors)
{
u32 blkcnt = 0;
//Retry 9 times on error.
u32 retries = 10;
// Retry 5 times if failed.
u32 retries = 5;
do
{
reinit_try:
if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write))
goto out;
else
retries--;
msleep(100);
msleep(50);
} while (retries);
// Disk IO failure! Reinit SD Card to a lower speed.
if (storage->sdmmc->id == SDMMC_1)
{
int res;
if (!first_reinit)
res = nx_sd_initialize(true);
else
res = nx_sd_init_retry(true);
retries = 3;
first_reinit = true;
if (res)
goto reinit_try;
}
return 0;
out:;
DPRINTF("readwrite: %08X\n", blkcnt);
out:
DPRINTF("readwrite: %08X\n", blkcnt);
sector += blkcnt;
num_sectors -= blkcnt;
bbuf += 512 * blkcnt;
}
return 1;
}
@ -427,10 +457,10 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u
switch (power)
{
case SDMMC_POWER_1_8:
arg = 0x40000080; //Sector access, voltage.
arg = SD_OCR_CCS | SD_OCR_VDD_18;
break;
case SDMMC_POWER_3_3:
arg = 0x403F8000; //Sector access, voltage.
arg = SD_OCR_CCS | SD_OCR_VDD_27_34;
break;
default:
return 0;
@ -445,21 +475,24 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u
static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power)
{
u32 timeout = get_tmr_ms() + 1500;
u64 timeout = get_tmr_ms() + 1500;
while (1)
{
u32 cond = 0;
if (!_mmc_storage_get_op_cond_inner(storage, &cond, power))
break;
if (cond & MMC_CARD_BUSY)
{
if (cond & 0x40000000)
if (cond & SD_OCR_CCS)
storage->has_sector_access = 1;
return 1;
}
if (get_tmr_ms() > timeout)
break;
usleep(1000);
}
@ -589,6 +622,7 @@ static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width)
if (_sdmmc_storage_check_status(storage))
{
sdmmc_set_bus_width(storage->sdmmc, bus_width);
return 1;
}
@ -599,14 +633,19 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check)
{
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS)))
return 0;
if (check && !_sdmmc_storage_check_status(storage))
return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 2))
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS52))
return 0;
DPRINTF("[MMC] switched to HS\n");
DPRINTF("[MMC] switched to HS\n");
storage->csd.busspeed = 52;
if (check || _sdmmc_storage_check_status(storage))
return 1;
return 0;
}
@ -614,12 +653,16 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage)
{
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))
return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 3))
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS200))
return 0;
if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200))
if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS200, MMC_SEND_TUNING_BLOCK_HS200))
return 0;
DPRINTF("[MMC] switched to HS200\n");
DPRINTF("[MMC] switched to HS200\n");
storage->csd.busspeed = 200;
return _sdmmc_storage_check_status(storage);
}
@ -627,41 +670,46 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
{
if (!_mmc_storage_enable_HS200(storage))
return 0;
sdmmc_get_venclkctl(storage->sdmmc);
sdmmc_set_tap_value(storage->sdmmc);
if (!_mmc_storage_enable_HS(storage, 0))
return 0;
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8)))
return 0;
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 4))
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS400))
return 0;
DPRINTF("[MMC] switched to HS400\n");
DPRINTF("[MMC] switched to HS400\n");
storage->csd.busspeed = 400;
return _sdmmc_storage_check_status(storage);
}
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
{
//TODO: this should be a config item.
// --v
if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
if (sdmmc_get_io_power(storage->sdmmc) != SDMMC_POWER_1_8)
goto out;
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V &&
type == 4)
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == SDHCI_TIMING_MMC_HS400)
return _mmc_storage_enable_HS400(storage);
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
(sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4
&& card_type & EXT_CSD_CARD_TYPE_HS200_1_8V
&& (type == 4 || type == 3)))
&& (type == SDHCI_TIMING_MMC_HS400 || type == SDHCI_TIMING_MMC_HS200)))
return _mmc_storage_enable_HS200(storage);
out:;
out:
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
return _mmc_storage_enable_HS(storage, 1);
return 1;
}
@ -669,53 +717,54 @@ static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage)
{
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_LEVEL_2)))
return 0;
return _sdmmc_storage_check_status(storage);
}
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
{
memset(storage, 0, sizeof(sdmmc_storage_t));
storage->sdmmc = sdmmc;
storage->rca = 2; //TODO: this could be a config item.
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0))
if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_AUTO_CAL_DISABLE))
return 0;
DPRINTF("[MMC] after init\n");
DPRINTF("[MMC] after init\n");
usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor);
if (!_sdmmc_storage_go_idle_state(storage))
return 0;
DPRINTF("[MMC] went to idle state\n");
DPRINTF("[MMC] went to idle state\n");
if (!_mmc_storage_get_op_cond(storage, SDMMC_POWER_1_8))
return 0;
DPRINTF("[MMC] got op cond\n");
DPRINTF("[MMC] got op cond\n");
if (!_sdmmc_storage_get_cid(storage, storage->raw_cid))
return 0;
DPRINTF("[MMC] got cid\n");
DPRINTF("[MMC] got cid\n");
if (!_mmc_storage_set_relative_addr(storage))
return 0;
DPRINTF("[MMC] set relative addr\n");
DPRINTF("[MMC] set relative addr\n");
if (!_sdmmc_storage_get_csd(storage, storage->raw_csd))
return 0;
DPRINTF("[MMC] got csd\n");
DPRINTF("[MMC] got csd\n");
_mmc_storage_parse_csd(storage);
if (!sdmmc_setup_clock(storage->sdmmc, 1))
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_LS26))
return 0;
DPRINTF("[MMC] after setup clock\n");
DPRINTF("[MMC] after setup clock\n");
if (!_sdmmc_storage_select_card(storage))
return 0;
DPRINTF("[MMC] card selected\n");
DPRINTF("[MMC] card selected\n");
if (!_sdmmc_storage_set_blocklen(storage, 512))
return 0;
DPRINTF("[MMC] set blocklen to 512\n");
DPRINTF("[MMC] set blocklen to 512\n");
u32 *csd = (u32 *)storage->raw_csd;
//Check system specification version, only version 4.0 and later support below features.
@ -727,36 +776,29 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
if (!_mmc_storage_switch_buswidth(storage, bus_width))
return 0;
DPRINTF("[MMC] switched buswidth\n");
u8 *ext_csd = (u8 *)malloc(512);
if (!_mmc_storage_get_ext_csd(storage, ext_csd))
{
free(ext_csd);
DPRINTF("[MMC] switched buswidth\n");
u8 buf[512];
memset(buf, 0, sizeof(buf));
if (!_mmc_storage_get_ext_csd(storage, buf))
return 0;
}
free(ext_csd);
DPRINTF("[MMC] got ext_csd\n");
DPRINTF("[MMC] got ext_csd\n");
_mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd
/* 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)
if (0 && storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2))
{
_mmc_storage_enable_bkops(storage);
DPRINTF("[MMC] BKOPS enabled\n");
}
else
{
DPRINTF("[MMC] BKOPS disabled\n");
DPRINTF("[MMC] BKOPS enabled\n");
}
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
return 0;
DPRINTF("[MMC] succesfully switched to highspeed mode\n");
DPRINTF("[MMC] succesfully switched to HS mode\n");
sdmmc_sd_clock_ctrl(storage->sdmmc, 1);
sdmmc_card_clock_ctrl(storage->sdmmc, SDMMC_AUTO_CAL_ENABLE);
return 1;
}
@ -765,8 +807,10 @@ int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition)
{
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_PART_CONFIG, partition)))
return 0;
if (!_sdmmc_storage_check_status(storage))
return 0;
storage->partition = partition;
return 1;
}
@ -780,6 +824,7 @@ static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_st
u32 tmp;
if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask))
return 0;
return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out);
}
@ -787,6 +832,7 @@ static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp
{
if (!_sdmmc_storage_execute_cmd_type1(storage, MMC_APP_CMD, storage->rca << 16, 0, R1_STATE_TRAN))
return 0;
return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0);
}
@ -816,32 +862,27 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int
// 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);
DPRINTF("[SD] before _sd_storage_execute_app_cmd\n");
if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0))
return 0;
DPRINTF("[SD] before sdmmc_get_rsp\n");
return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3);
}
static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, int supports_low_voltage)
{
u32 timeout = get_tmr_ms() + 1500;
u64 timeout = get_tmr_ms() + 1500;
while (1)
{
u32 cond = 0;
if (!_sd_storage_get_op_cond_once(storage, &cond, is_version_1, supports_low_voltage))
{
DPRINTF("[SD] _sd_storage_get_op_cond_once failed\r\n");
break;
}
if (cond & MMC_CARD_BUSY)
{
if (cond & SD_OCR_CCS)
storage->has_sector_access = 1;
// Check if card supports 1.8V signaling.
if (cond & SD_ROCR_S18A && supports_low_voltage)
{
//The low voltage regulator configuration is valid for SDMMC1 only.
@ -852,7 +893,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
return 0;
storage->is_low_voltage = 1;
DPRINTF("-> switched to low voltage\n");
DPRINTF("-> switched to low voltage\n");
}
}
@ -863,8 +904,6 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
msleep(10); // Needs to be at least 10ms for some SD Cards
}
DPRINTF("[SD] _sd_storage_get_op_cond Timeout\r\n");
return 0;
}
@ -873,7 +912,7 @@ static int _sd_storage_get_rca(sdmmc_storage_t *storage)
sdmmc_cmd_t cmdbuf;
sdmmc_init_cmd(&cmdbuf, SD_SEND_RELATIVE_ADDR, 0, SDMMC_RSP_TYPE_4, 0);
u32 timeout = get_tmr_ms() + 1500;
u64 timeout = get_tmr_ms() + 1500;
while (1)
{
@ -991,34 +1030,37 @@ int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int group,
return _sdmmc_storage_check_result(tmp);
}
void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf)
void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u16 current_limit, u8 *buf)
{
u32 pwr = SD_SET_CURRENT_LIMIT_800;
u32 pwr = SD_SET_CURRENT_LIMIT_200;
if (current_limit & SD_MAX_CURRENT_800)
pwr = SD_SET_CURRENT_LIMIT_800;
else if (current_limit & SD_MAX_CURRENT_600)
pwr = SD_SET_CURRENT_LIMIT_600;
else if (current_limit & SD_MAX_CURRENT_400)
pwr = SD_SET_CURRENT_LIMIT_400;
_sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr);
while (pwr > 0)
if (((buf[15] >> 4) & 0x0F) == pwr)
{
pwr--;
_sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr);
if (((buf[15] >> 4) & 0x0F) == pwr)
switch (pwr)
{
case SD_SET_CURRENT_LIMIT_800:
DPRINTF("[SD] power limit raised to 800mA\n");
break;
}
switch (pwr)
{
case SD_SET_CURRENT_LIMIT_800:
DPRINTF("[SD] Power limit raised to 800mA\n");
break;
case SD_SET_CURRENT_LIMIT_600:
DPRINTF("[SD] Power limit raised to 600mA\n");
break;
case SD_SET_CURRENT_LIMIT_400:
DPRINTF("[SD] Power limit raised to 800mA\n");
break;
default:
case SD_SET_CURRENT_LIMIT_200:
DPRINTF("[SD] Power limit defaulted to 200mA\n");
break;
case SD_SET_CURRENT_LIMIT_600:
DPRINTF("[SD] power limit raised to 600mA\n");
break;
case SD_SET_CURRENT_LIMIT_400:
DPRINTF("[SD] power limit raised to 400mA\n");
break;
default:
case SD_SET_CURRENT_LIMIT_200:
DPRINTF("[SD] power limit defaulted to 200mA\n");
break;
}
}
}
@ -1026,62 +1068,91 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf)
{
if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type))
return 0;
DPRINTF("[SD] supports switch to (U)HS mode\n");
u32 type_out = buf[16] & 0xF;
if (type_out != hs_type)
return 0;
DPRINTF("[SD] supports selected (U)HS mode\n");
if ((((u16)buf[0] << 8) | buf[1]) < 0x320)
u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1];
DPRINTF("[SD] total max current: %d\n", total_pwr_consumption);
if (total_pwr_consumption <= 800)
{
if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, 0, hs_type))
return 0;
if (type_out != (buf[16] & 0xF))
return 0;
}
return 1;
return 1;
}
DPRINTF("[SD] card max current over limit\n");
return 0;
}
int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
{
// Try to raise the current limit to let the card perform better.
_sd_storage_set_current_limit(storage, buf);
if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4)
return 0;
if (!_sd_storage_switch_get(storage, buf))
return 0;
//gfx_hexdump(0, (u8 *)buf, 64);
u8 access_mode = buf[13];
u16 current_limit = buf[7] | buf[6] << 8;
// Try to raise the current limit to let the card perform better.
_sd_storage_set_current_limit(storage, current_limit, buf);
u32 hs_type = 0;
switch (type)
{
case 11:
case SDHCI_TIMING_UHS_SDR104:
case SDHCI_TIMING_UHS_SDR82:
// Fall through if not supported.
if (buf[13] & SD_MODE_UHS_SDR104)
if (access_mode & SD_MODE_UHS_SDR104)
{
type = 11;
hs_type = UHS_SDR104_BUS_SPEED;
DPRINTF("[SD] Bus speed set to SDR104\n");
storage->csd.busspeed = 104;
DPRINTF("[SD] bus speed set to SDR104\n");
switch (type)
{
case SDHCI_TIMING_UHS_SDR104:
storage->csd.busspeed = 104;
break;
case SDHCI_TIMING_UHS_SDR82:
storage->csd.busspeed = 82;
break;
}
break;
}
case 10:
if (buf[13] & SD_MODE_UHS_SDR50)
case SDHCI_TIMING_UHS_SDR50:
if (access_mode & SD_MODE_UHS_SDR50)
{
type = 10;
type = SDHCI_TIMING_UHS_SDR50;
hs_type = UHS_SDR50_BUS_SPEED;
DPRINTF("[SD] Bus speed set to SDR50\n");
DPRINTF("[SD] bus speed set to SDR50\n");
storage->csd.busspeed = 50;
break;
}
case 8:
if (!(buf[13] & SD_MODE_UHS_SDR12))
case SDHCI_TIMING_UHS_SDR25:
if (access_mode & SD_MODE_UHS_SDR25)
{
type = SDHCI_TIMING_UHS_SDR25;
hs_type = UHS_SDR50_BUS_SPEED;
DPRINTF("[SD] bus speed set to SDR25\n");
storage->csd.busspeed = 25;
break;
}
case SDHCI_TIMING_UHS_SDR12:
if (!(access_mode & SD_MODE_UHS_SDR12))
return 0;
type = 8;
type = SDHCI_TIMING_UHS_SDR12;
hs_type = UHS_SDR12_BUS_SPEED;
DPRINTF("[SD] Bus speed set to SDR12\n");
DPRINTF("[SD] bus speed set to SDR12\n");
storage->csd.busspeed = 12;
break;
default:
@ -1091,106 +1162,38 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
return 0;
DPRINTF("[SD] card accepted UHS\n");
if (!sdmmc_setup_clock(storage->sdmmc, type))
return 0;
if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
DPRINTF("[SD] setup clock\n");
if (!sdmmc_tuning_execute(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
return 0;
DPRINTF("[SD] config tuning\n");
return _sdmmc_storage_check_status(storage);
}
int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf)
int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf)
{
if (!_sd_storage_switch_get(storage, buf))
return 0;
if (!(buf[13] & SD_MODE_HIGH_SPEED))
//gfx_hexdump(0, (u8 *)buf, 64);
u8 access_mode = buf[13];
u16 current_limit = buf[7] | buf[6] << 8;
// Try to raise the current limit to let the card perform better.
_sd_storage_set_current_limit(storage, current_limit, buf);
if (!(access_mode & SD_MODE_HIGH_SPEED))
return 1;
if (!_sd_storage_enable_highspeed(storage, 1, buf))
if (!_sd_storage_enable_highspeed(storage, HIGH_SPEED_BUS_SPEED, buf))
return 0;
if (!_sdmmc_storage_check_status(storage))
return 0;
return sdmmc_setup_clock(storage->sdmmc, 7);
}
static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
{
// unstuff_bits supports only 4 u32 so break into 2 x 16byte groups
u32 raw_ssr1[4];
u32 raw_ssr2[4];
raw_ssr1[3] = *(u32 *)&storage->raw_ssr[12];
raw_ssr1[2] = *(u32 *)&storage->raw_ssr[8];
raw_ssr1[1] = *(u32 *)&storage->raw_ssr[4];
raw_ssr1[0] = *(u32 *)&storage->raw_ssr[0];
raw_ssr2[3] = *(u32 *)&storage->raw_ssr[28];
raw_ssr2[2] = *(u32 *)&storage->raw_ssr[24];
raw_ssr2[1] = *(u32 *)&storage->raw_ssr[20];
raw_ssr2[0] = *(u32 *)&storage->raw_ssr[16];
storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510 - 384, 2) & SD_BUS_WIDTH_4) ? 4 : 1;
switch(unstuff_bits(raw_ssr1, 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_ssr1, 440 - 384, 8);
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);
}
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);
return _sdmmc_storage_check_result(tmp);
return sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_HS25);
}
static void _sd_storage_parse_cid(sdmmc_storage_t *storage)
@ -1232,45 +1235,65 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
}
}
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
static bool _sdmmc_storage_supports_low_voltage(u32 bus_width, u32 type)
{
switch (type)
{
case SDHCI_TIMING_UHS_SDR12:
case SDHCI_TIMING_UHS_SDR25:
case SDHCI_TIMING_UHS_SDR50:
case SDHCI_TIMING_UHS_SDR104:
case SDHCI_TIMING_UHS_SDR82:
case SDHCI_TIMING_UHS_DDR50:
if (bus_width == SDMMC_BUS_WIDTH_4)
return true;
default:
return false;
}
}
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
{
u8 buf[512];
int is_version_1 = 0;
memset(buf, 0, sizeof(buf));
memset(storage, 0, sizeof(sdmmc_storage_t));
storage->sdmmc = sdmmc;
DPRINTF("[SD] before init\n");
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0))
if (!sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, SDMMC_AUTO_CAL_DISABLE))
return 0;
DPRINTF("[SD] after init\n");
DPRINTF("[SD] after init\n");
usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor);
if (!_sdmmc_storage_go_idle_state(storage))
return 0;
DPRINTF("[SD] went to idle state\n");
DPRINTF("[SD] went to idle state\n");
is_version_1 = _sd_storage_send_if_cond(storage);
if (is_version_1 == 2)
return 0;
DPRINTF("[SD] after send if cond\n");
DPRINTF("[SD] after send if cond\n");
if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11))
bool supports_low_voltage = _sdmmc_storage_supports_low_voltage(bus_width, type);
if (!_sd_storage_get_op_cond(storage, is_version_1, supports_low_voltage))
return 0;
DPRINTF("[SD] got op cond\n");
DPRINTF("[SD] got op cond\n");
if (!_sdmmc_storage_get_cid(storage, storage->raw_cid))
return 0;
DPRINTF("[SD] got cid\n");
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);
DPRINTF("[SD] got rca (= %04X)\n", storage->rca);
if (!_sdmmc_storage_get_csd(storage, storage->raw_csd))
return 0;
DPRINTF("[SD] got csd\n");
DPRINTF("[SD] got csd\n");
//Parse CSD.
_sd_storage_parse_csd(storage);
@ -1283,84 +1306,75 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
storage->sec_cnt = storage->csd.c_size << 10;
break;
default:
DPRINTF("[SD] Unknown CSD structure %d\n", storage->csd.structure);
DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure);
break;
}
if (!storage->is_low_voltage)
{
if (!sdmmc_setup_clock(storage->sdmmc, 6))
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12))
return 0;
DPRINTF("[SD] after setup clock\n");
DPRINTF("[SD] after setup clock\n");
}
if (!_sdmmc_storage_select_card(storage))
return 0;
DPRINTF("[SD] card selected\n");
DPRINTF("[SD] card selected\n");
if (!_sdmmc_storage_set_blocklen(storage, 512))
return 0;
DPRINTF("[SD] set blocklen to 512\n");
DPRINTF("[SD] set blocklen to 512\n");
u32 tmp = 0;
if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_CLR_CARD_DETECT, 0, 0, R1_STATE_TRAN))
return 0;
DPRINTF("[SD] cleared card detect\n");
DPRINTF("[SD] cleared card detect\n");
u8 *buf = (u8 *)malloc(512);
if (!_sd_storage_get_scr(storage, buf))
{
free(buf);
return 0;
}
DPRINTF("[SD] got scr\n");
//gfx_hexdump(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.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))
{
free(buf);
return 0;
}
sdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4);
DPRINTF("[SD] switched to wide bus width\n");
DPRINTF("[SD] switched to wide bus width\n");
}
else
{
DPRINTF("[SD] SD does not support wide bus width\n");
DPRINTF("[SD] SD does not support wide bus width\n");
}
if (storage->is_low_voltage)
{
if (!_sd_storage_enable_highspeed_low_volt(storage, type, buf))
{
free(buf);
if (!_sd_storage_enable_uhs_low_volt(storage, type, buf))
return 0;
}
DPRINTF("[SD] enabled highspeed (low voltage)\n");
DPRINTF("[SD] enabled UHS\n");
sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
}
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0)
else if (type != SDHCI_TIMING_SD_DS12 && (storage->scr.sda_vsn & 0xF) != 0)
{
if (!_sd_storage_enable_highspeed_high_volt(storage, buf))
{
free(buf);
if (!_sd_storage_enable_hs_high_volt(storage, buf))
return 0;
DPRINTF("[SD] enabled HS\n");
switch (bus_width)
{
case SDMMC_BUS_WIDTH_4:
storage->csd.busspeed = 25;
break;
case SDMMC_BUS_WIDTH_1:
storage->csd.busspeed = 6;
break;
}
DPRINTF("[SD] enabled highspeed (high voltage)\n");
storage->csd.busspeed = 25;
}
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;
}
@ -1400,17 +1414,17 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
memset(storage, 0, sizeof(sdmmc_storage_t));
storage->sdmmc = sdmmc;
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0))
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_DDR52, SDMMC_AUTO_CAL_DISABLE))
return 0;
DPRINTF("[gc] after init\n");
DPRINTF("[gc] after init\n");
usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor);
if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200))
if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_DDR52, MMC_SEND_TUNING_BLOCK_HS200))
return 0;
DPRINTF("[gc] after tuning\n");
DPRINTF("[gc] after tuning\n");
sdmmc_sd_clock_ctrl(sdmmc, 1);
sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
return 1;
}