mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-26 13:52:21 +00:00
fusee: work around some dual-init SDMMC issues
This commit is contained in:
parent
ef9adabb40
commit
eaf8e559d6
3 changed files with 44 additions and 16 deletions
|
@ -15,6 +15,13 @@
|
||||||
|
|
||||||
static bool g_ahb_redirect_enabled = false;
|
static bool g_ahb_redirect_enabled = false;
|
||||||
|
|
||||||
|
// Only use voltage switching in stage2 and later.
|
||||||
|
#ifdef FUSEE_STAGE1_SRC
|
||||||
|
#define MMC_VOLTAGE_SWITCHING_ALLOWED false
|
||||||
|
#else
|
||||||
|
#define MMC_VOLTAGE_SWITCHING_ALLOWED true
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Global sd struct. */
|
/* Global sd struct. */
|
||||||
static struct mmc g_sd_mmc = {0};
|
static struct mmc g_sd_mmc = {0};
|
||||||
static bool g_sd_initialized = false;
|
static bool g_sd_initialized = false;
|
||||||
|
@ -26,7 +33,7 @@ int initialize_sd_mmc(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_sd_initialized) {
|
if (!g_sd_initialized) {
|
||||||
int rc = sdmmc_init(&g_sd_mmc, SWITCH_MICROSD);
|
int rc = sdmmc_init(&g_sd_mmc, SWITCH_MICROSD, MMC_VOLTAGE_SWITCHING_ALLOWED);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
g_sd_initialized = true;
|
g_sd_initialized = true;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -140,7 +140,7 @@ enum sdmmc_clock_dividers {
|
||||||
MMC_CLOCK_DIVIDER_SDR12 = 31, // 16.5, from the TRM table
|
MMC_CLOCK_DIVIDER_SDR12 = 31, // 16.5, from the TRM table
|
||||||
MMC_CLOCK_DIVIDER_SDR25 = 15, // 8.5, from the table
|
MMC_CLOCK_DIVIDER_SDR25 = 15, // 8.5, from the table
|
||||||
MMC_CLOCK_DIVIDER_SDR50 = 7, // 4.5, from the table
|
MMC_CLOCK_DIVIDER_SDR50 = 7, // 4.5, from the table
|
||||||
MMC_CLOCK_DIVIDER_SDR104 = 2, // 2, from the datasheet
|
MMC_CLOCK_DIVIDER_SDR104 = 4, // 2, from the datasheet
|
||||||
|
|
||||||
/* Clock dividers: MMC */
|
/* Clock dividers: MMC */
|
||||||
MMC_CLOCK_DIVIDER_HS26 = 30, // 16, from the TRM table
|
MMC_CLOCK_DIVIDER_HS26 = 30, // 16, from the TRM table
|
||||||
|
@ -568,11 +568,11 @@ struct PACKED sdmmc_function_status {
|
||||||
|
|
||||||
/* support for various speed modes */
|
/* support for various speed modes */
|
||||||
uint16_t group1_support_reserved1 : 8;
|
uint16_t group1_support_reserved1 : 8;
|
||||||
uint16_t ddr50_support : 1;
|
|
||||||
uint16_t sdr104_support : 1;
|
|
||||||
uint16_t sdr50_support : 1;
|
|
||||||
uint16_t sdr25_support : 1;
|
|
||||||
uint16_t sdr12_support : 1;
|
uint16_t sdr12_support : 1;
|
||||||
|
uint16_t sdr25_support : 1;
|
||||||
|
uint16_t sdr50_support : 1;
|
||||||
|
uint16_t sdr104_support : 1;
|
||||||
|
uint16_t ddr50_support : 1;
|
||||||
uint16_t group1_support_reserved2 : 3;
|
uint16_t group1_support_reserved2 : 3;
|
||||||
|
|
||||||
|
|
||||||
|
@ -631,10 +631,14 @@ static const uint16_t sdmmc_bounce_dma_boundary = MMC_DMA_BOUNDARY_8K;
|
||||||
* Sets the current SDMMC debugging loglevel.
|
* Sets the current SDMMC debugging loglevel.
|
||||||
*
|
*
|
||||||
* @param loglevel Current log level. A higher value prints more logs.
|
* @param loglevel Current log level. A higher value prints more logs.
|
||||||
|
* @return The loglevel prior to when this was applied, for easy restoration.
|
||||||
*/
|
*/
|
||||||
void sdmmc_set_loglevel(int loglevel)
|
int sdmmc_set_loglevel(int loglevel)
|
||||||
{
|
{
|
||||||
|
int original_loglevel = sdmmc_loglevel;
|
||||||
sdmmc_loglevel = loglevel;
|
sdmmc_loglevel = loglevel;
|
||||||
|
|
||||||
|
return original_loglevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -887,9 +891,9 @@ static int sdmmc1_enable_supplies(struct mmc *mmc)
|
||||||
pinmux->dmic3_clk = PINMUX_SELECT_FUNCTION0;
|
pinmux->dmic3_clk = PINMUX_SELECT_FUNCTION0;
|
||||||
gpio_configure_mode(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_MODE_GPIO);
|
gpio_configure_mode(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_MODE_GPIO);
|
||||||
gpio_configure_direction(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_DIRECTION_OUTPUT);
|
gpio_configure_direction(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_DIRECTION_OUTPUT);
|
||||||
|
|
||||||
|
// Bring up the SD card fixed regulator.
|
||||||
gpio_write(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_LEVEL_HIGH);
|
gpio_write(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_LEVEL_HIGH);
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1415,6 +1419,7 @@ static int sdmmc_apply_clock_speed(struct mmc *mmc, enum sdmmc_bus_speed speed,
|
||||||
mmc_print(mmc, "TODO: double the data rate here!");
|
mmc_print(mmc, "TODO: double the data rate here!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Re-enable the clock, if necessary.
|
// Re-enable the clock, if necessary.
|
||||||
if (enable_after) {
|
if (enable_after) {
|
||||||
sdmmc_clock_enable(mmc, true);
|
sdmmc_clock_enable(mmc, true);
|
||||||
|
@ -2902,13 +2907,17 @@ static int sdmmc_mmc_wait_for_card_readiness(struct mmc *mmc)
|
||||||
int rc;
|
int rc;
|
||||||
uint32_t response[4];
|
uint32_t response[4];
|
||||||
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
uint32_t response_masked;
|
uint32_t response_masked;
|
||||||
|
|
||||||
// Ask the SD card to identify its state. It will respond with readiness and a capacity magic.
|
// Ask the SD card to identify its state. It will respond with readiness and a capacity magic.
|
||||||
|
int original_loglevel = sdmmc_set_loglevel(0);
|
||||||
rc = sdmmc_send_command(mmc, CMD_SEND_OPERATING_CONDITIONS, MMC_RESPONSE_LEN48,
|
rc = sdmmc_send_command(mmc, CMD_SEND_OPERATING_CONDITIONS, MMC_RESPONSE_LEN48,
|
||||||
MMC_CHECKS_NONE, 0x40000080, response, 0, false, false, NULL);
|
MMC_CHECKS_NONE, 0x40000080, response, 0, false, false, NULL);
|
||||||
|
sdmmc_set_loglevel(original_loglevel);
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
mmc_print(mmc, "ERROR: could not read the card's operating conditions!");
|
mmc_print(mmc, "ERROR: could not read the card's operating conditions!");
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -2953,8 +2962,10 @@ static int sdmmc_sd_wait_for_card_readiness(struct mmc *mmc, uint32_t *response)
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
// Ask the SD card to identify its state.
|
// Ask the SD card to identify its state.
|
||||||
|
int original_loglevel = sdmmc_set_loglevel(0);
|
||||||
rc = sdmmc_send_simple_app_command(mmc, CMD_APP_SEND_OP_COND,
|
rc = sdmmc_send_simple_app_command(mmc, CMD_APP_SEND_OP_COND,
|
||||||
MMC_RESPONSE_LEN48, MMC_CHECKS_NONE, argument, response);
|
MMC_RESPONSE_LEN48, MMC_CHECKS_NONE, argument, response);
|
||||||
|
sdmmc_set_loglevel(original_loglevel);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
mmc_print(mmc, "ERROR: could not read the card's operating conditions!");
|
mmc_print(mmc, "ERROR: could not read the card's operating conditions!");
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -3071,7 +3082,7 @@ static int sdmmc_sd_card_init(struct mmc *mmc)
|
||||||
mmc->uses_block_addressing = !!(ocr & MMC_SD_OPERATING_COND_HIGH_CAPACITY);
|
mmc->uses_block_addressing = !!(ocr & MMC_SD_OPERATING_COND_HIGH_CAPACITY);
|
||||||
|
|
||||||
// If the card supports using 1V8, drop down using lower voltages.
|
// If the card supports using 1V8, drop down using lower voltages.
|
||||||
if (ocr & MMC_SD_OPERATING_COND_ACCEPTS_1V8) {
|
if (mmc->allow_voltage_switching && ocr & MMC_SD_OPERATING_COND_ACCEPTS_1V8) {
|
||||||
if (mmc->operating_voltage != MMC_VOLTAGE_1V8) {
|
if (mmc->operating_voltage != MMC_VOLTAGE_1V8) {
|
||||||
rc = mmc->switch_to_low_voltage(mmc);
|
rc = mmc->switch_to_low_voltage(mmc);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -3369,14 +3380,18 @@ static int sdmmc_initialize_defaults(struct mmc *mmc)
|
||||||
* @param mmc The SDMMC structure to be initiailized with the device state.
|
* @param mmc The SDMMC structure to be initiailized with the device state.
|
||||||
* @param controler The controller description to be used; usually SWITCH_EMMC
|
* @param controler The controller description to be used; usually SWITCH_EMMC
|
||||||
* or SWITCH_MICROSD.
|
* or SWITCH_MICROSD.
|
||||||
|
* @param allow_voltage_switching True if we should allow voltage switching,
|
||||||
|
* which may not make sense if we're about to chainload to another component,
|
||||||
|
* a la fusee stage1.
|
||||||
*/
|
*/
|
||||||
int sdmmc_init(struct mmc *mmc, enum sdmmc_controller controller)
|
int sdmmc_init(struct mmc *mmc, enum sdmmc_controller controller, bool allow_voltage_switching)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
// Get a reference to the registers for the relevant SDMMC controller.
|
// Get a reference to the registers for the relevant SDMMC controller.
|
||||||
mmc->controller = controller;
|
mmc->controller = controller;
|
||||||
mmc->regs = sdmmc_get_regs(controller);
|
mmc->regs = sdmmc_get_regs(controller);
|
||||||
|
mmc->allow_voltage_switching = false;
|
||||||
|
|
||||||
// Set the defaults for the card, including the default function pointers
|
// Set the defaults for the card, including the default function pointers
|
||||||
// for the assumed card type, and the per-controller options.
|
// for the assumed card type, and the per-controller options.
|
||||||
|
|
|
@ -150,6 +150,7 @@ struct mmc {
|
||||||
/* Controller properties */
|
/* Controller properties */
|
||||||
const char *name;
|
const char *name;
|
||||||
bool use_dma;
|
bool use_dma;
|
||||||
|
bool allow_voltage_switching;
|
||||||
unsigned int timeout;
|
unsigned int timeout;
|
||||||
enum tegra_named_gpio card_detect_gpio;
|
enum tegra_named_gpio card_detect_gpio;
|
||||||
enum sdmmc_write_permission write_enable;
|
enum sdmmc_write_permission write_enable;
|
||||||
|
@ -221,17 +222,22 @@ enum sdmmc_partition {
|
||||||
* Sets the current SDMMC debugging loglevel.
|
* Sets the current SDMMC debugging loglevel.
|
||||||
*
|
*
|
||||||
* @param loglevel Current log level. A higher value prints more logs.
|
* @param loglevel Current log level. A higher value prints more logs.
|
||||||
|
* @return The loglevel prior to when this was applied, for easy restoration.
|
||||||
*/
|
*/
|
||||||
void sdmmc_set_loglevel(int loglevel);
|
int sdmmc_set_loglevel(int loglevel);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiailzes an SDMMC controller for use with an eMMC or SD card device.
|
* Set up a new SDMMC driver.
|
||||||
*
|
*
|
||||||
* @param mmc An (uninitialized) structure for the MMC device.
|
* @param mmc The SDMMC structure to be initiailized with the device state.
|
||||||
* @param controller The controller number to be initialized. Either SWITCH_MICROSD or SWITCH_EMMC.
|
* @param controler The controller description to be used; usually SWITCH_EMMC
|
||||||
|
* or SWITCH_MICROSD.
|
||||||
|
* @param allow_voltage_switching True if we should allow voltage switching,
|
||||||
|
* which may not make sense if we're about to chainload to another component,
|
||||||
|
* a la fusee stage1.
|
||||||
*/
|
*/
|
||||||
int sdmmc_init(struct mmc *mmc, enum sdmmc_controller controller);
|
int sdmmc_init(struct mmc *mmc, enum sdmmc_controller controller, bool allow_voltage_switching);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue