mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-28 09:30:58 +01:00
fusee: work around some dual-init SDMMC issues
This commit is contained in:
parent
ef9adabb40
commit
eaf8e559d6
@ -15,6 +15,13 @@
|
||||
|
||||
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. */
|
||||
static struct mmc g_sd_mmc = {0};
|
||||
static bool g_sd_initialized = false;
|
||||
@ -26,7 +33,7 @@ int initialize_sd_mmc(void) {
|
||||
}
|
||||
|
||||
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) {
|
||||
g_sd_initialized = true;
|
||||
return 0;
|
||||
|
@ -140,7 +140,7 @@ enum sdmmc_clock_dividers {
|
||||
MMC_CLOCK_DIVIDER_SDR12 = 31, // 16.5, from the TRM table
|
||||
MMC_CLOCK_DIVIDER_SDR25 = 15, // 8.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 */
|
||||
MMC_CLOCK_DIVIDER_HS26 = 30, // 16, from the TRM table
|
||||
@ -568,11 +568,11 @@ struct PACKED sdmmc_function_status {
|
||||
|
||||
/* support for various speed modes */
|
||||
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 sdr25_support : 1;
|
||||
uint16_t sdr50_support : 1;
|
||||
uint16_t sdr104_support : 1;
|
||||
uint16_t ddr50_support : 1;
|
||||
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.
|
||||
*
|
||||
* @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;
|
||||
|
||||
return original_loglevel;
|
||||
}
|
||||
|
||||
|
||||
@ -887,9 +891,9 @@ static int sdmmc1_enable_supplies(struct mmc *mmc)
|
||||
pinmux->dmic3_clk = PINMUX_SELECT_FUNCTION0;
|
||||
gpio_configure_mode(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_MODE_GPIO);
|
||||
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);
|
||||
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
|
||||
// Re-enable the clock, if necessary.
|
||||
if (enable_after) {
|
||||
sdmmc_clock_enable(mmc, true);
|
||||
@ -2902,13 +2907,17 @@ static int sdmmc_mmc_wait_for_card_readiness(struct mmc *mmc)
|
||||
int rc;
|
||||
uint32_t response[4];
|
||||
|
||||
|
||||
while (true) {
|
||||
|
||||
uint32_t response_masked;
|
||||
|
||||
// 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,
|
||||
MMC_CHECKS_NONE, 0x40000080, response, 0, false, false, NULL);
|
||||
sdmmc_set_loglevel(original_loglevel);
|
||||
|
||||
if (rc) {
|
||||
mmc_print(mmc, "ERROR: could not read the card's operating conditions!");
|
||||
return rc;
|
||||
@ -2953,8 +2962,10 @@ static int sdmmc_sd_wait_for_card_readiness(struct mmc *mmc, uint32_t *response)
|
||||
while (true) {
|
||||
|
||||
// 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,
|
||||
MMC_RESPONSE_LEN48, MMC_CHECKS_NONE, argument, response);
|
||||
sdmmc_set_loglevel(original_loglevel);
|
||||
if (rc) {
|
||||
mmc_print(mmc, "ERROR: could not read the card's operating conditions!");
|
||||
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);
|
||||
|
||||
// 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) {
|
||||
rc = mmc->switch_to_low_voltage(mmc);
|
||||
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 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)
|
||||
{
|
||||
int rc;
|
||||
|
||||
// Get a reference to the registers for the relevant SDMMC controller.
|
||||
mmc->controller = controller;
|
||||
mmc->regs = sdmmc_get_regs(controller);
|
||||
mmc->allow_voltage_switching = false;
|
||||
|
||||
// Set the defaults for the card, including the default function pointers
|
||||
// for the assumed card type, and the per-controller options.
|
||||
|
@ -150,6 +150,7 @@ struct mmc {
|
||||
/* Controller properties */
|
||||
const char *name;
|
||||
bool use_dma;
|
||||
bool allow_voltage_switching;
|
||||
unsigned int timeout;
|
||||
enum tegra_named_gpio card_detect_gpio;
|
||||
enum sdmmc_write_permission write_enable;
|
||||
@ -221,17 +222,22 @@ enum sdmmc_partition {
|
||||
* Sets the current SDMMC debugging loglevel.
|
||||
*
|
||||
* @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 controller The controller number to be initialized. Either SWITCH_MICROSD or SWITCH_EMMC.
|
||||
* @param mmc The SDMMC structure to be initiailized with the device state.
|
||||
* @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 New Issue
Block a user