diff --git a/ipl/sdmmc.c b/ipl/sdmmc.c index bd21237..7d22347 100755 --- a/ipl/sdmmc.c +++ b/ipl/sdmmc.c @@ -386,7 +386,8 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check) return 0; if (!sdmmc_setup_clock(storage->sdmmc, 2)) 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; @@ -400,7 +401,8 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage) return 0; if (!sdmmc_config_tuning(storage->sdmmc, 3, 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); } @@ -417,7 +419,8 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage) return 0; if (!sdmmc_setup_clock(storage->sdmmc, 4)) return 0; - DPRINTF("[mmc] switched to HS400\n"); + DPRINTF("[MMC] switched to HS400\n"); + storage->csd.busspeed = 400; return _sdmmc_storage_check_status(storage); } @@ -460,42 +463,42 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0)) return 0; - DPRINTF("[mmc] after init\n"); + DPRINTF("[MMC] after init\n"); sleep(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)) 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. @@ -507,7 +510,7 @@ 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"); + DPRINTF("[MMC] switched buswidth\n"); u8 *ext_csd = (u8 *)malloc(512); if (!_mmc_storage_get_ext_csd(storage, ext_csd)) @@ -516,7 +519,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 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 //gfx_hexdump(&gfx_con, 0, ext_csd, 512); @@ -526,14 +529,14 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0) { _mmc_storage_enable_bkops(storage); - DPRINTF("[mmc] BKOPS enabled\n"); + DPRINTF("[MMC] BKOPS enabled\n"); } else - DPRINTF("[mmc] BKOPS disabled\n"); + 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"); + DPRINTF("[MMC] succesfully switched to highspeed mode\n"); sdmmc_sd_clock_ctrl(storage->sdmmc, 1); @@ -738,10 +741,13 @@ int _sd_storage_switch_get(sdmmc_storage_t *storage, void *buf) return _sdmmc_storage_check_result(tmp); } -int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int flag, u32 arg) +int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int group, u32 arg) { sdmmc_cmd_t cmdbuf; - sdmmc_init_cmd(&cmdbuf, SD_SWITCH, arg | (flag << 31) | 0xFFFFF0, SDMMC_RSP_TYPE_1, 0); + u32 switchcmd = mode << 31 | 0x00FFFFFF; + switchcmd &= ~(0xF << (group * 4)); + switchcmd |= arg << (group * 4); + sdmmc_init_cmd(&cmdbuf, SD_SWITCH, switchcmd, SDMMC_RSP_TYPE_1, 0); sdmmc_req_t reqbuf; reqbuf.buf = buf; @@ -759,6 +765,37 @@ int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int flag, u32 arg) return _sdmmc_storage_check_result(tmp); } +void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf) +{ + u32 pwr = SD_SET_CURRENT_LIMIT_800; + _sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); + + while (pwr > 0) + { + pwr--; + _sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); + if (((buf[15] >> 4) & 0x0F) == pwr) + 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; + } +} + 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)) @@ -782,6 +819,9 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf) int _sd_storage_enable_highspeed_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; @@ -797,14 +837,27 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 { type = 11; hs_type = UHS_SDR104_BUS_SPEED; + DPRINTF("[SD] Bus speed set to SDR104\n"); + storage->csd.busspeed = 104; break; } //Fall through. case 10: - if (!(buf[13] & SD_MODE_UHS_SDR50)) + if (buf[13] & SD_MODE_UHS_SDR50) + { + type = 10; + hs_type = UHS_SDR50_BUS_SPEED; + DPRINTF("[SD] Bus speed set to SDR50\n"); + storage->csd.busspeed = 50; + break; + } + case 8: + if (!(buf[13] & SD_MODE_UHS_SDR12)) return 0; - type = 10; - hs_type = UHS_SDR50_BUS_SPEED; + type = 8; + hs_type = UHS_SDR12_BUS_SPEED; + DPRINTF("[SD] Bus speed set to SDR12\n"); + storage->csd.busspeed = 12; break; default: return 0; @@ -893,7 +946,7 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) reqbuf.is_auto_cmd12 = 0; if (!(storage->csd.cmdclass & CCC_APP_SPEC)) { - DPRINTF("[sd] ssr: Card lacks mandatory SD Status function\n"); + DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n"); return 0; } @@ -964,35 +1017,35 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0)) return 0; - DPRINTF("[sd] after init\n"); + DPRINTF("[SD] after init\n"); sleep(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)) 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); @@ -1005,7 +1058,7 @@ 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; } @@ -1013,27 +1066,27 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 { if (!sdmmc_setup_clock(storage->sdmmc, 6)) 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)) return 0; //gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8); - DPRINTF("[sd] got scr\n"); + 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)) @@ -1044,10 +1097,10 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 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) { @@ -1056,7 +1109,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 free(buf); return 0; } - DPRINTF("[sd] enabled highspeed (low voltage)\n"); + DPRINTF("[SD] enabled highspeed (low voltage)\n"); } else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0) { @@ -1065,14 +1118,15 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 free(buf); return 0; } - DPRINTF("[sd] enabled highspeed (high voltage)\n"); + 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"); + DPRINTF("[SD] got sd status\n"); free(buf); return 1; diff --git a/ipl/sdmmc.h b/ipl/sdmmc.h index 33e7ffa..9a15feb 100755 --- a/ipl/sdmmc.h +++ b/ipl/sdmmc.h @@ -48,6 +48,7 @@ typedef struct _mmc_csd u32 write_blkbits; u32 capacity; u8 write_protect; + u16 busspeed; } mmc_csd_t; typedef struct _mmc_ext_csd diff --git a/ipl/sdmmc_driver.c b/ipl/sdmmc_driver.c index 77a9db1..d52f00d 100755 --- a/ipl/sdmmc_driver.c +++ b/ipl/sdmmc_driver.c @@ -1019,7 +1019,16 @@ void sdmmc_end(sdmmc_t *sdmmc) if (!sdmmc->clock_stopped) { _sdmmc_sd_clock_disable(sdmmc); + // Disable SDMMC power. _sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF); + + // Disable SD card power. + if (sdmmc->id == SDMMC_1) + { + gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); + sleep(1000); // To power cycle min 1ms without power is needed. + } + _sdmmc_get_clkcon(sdmmc); clock_sdmmc_disable(sdmmc->id); sdmmc->clock_stopped = 1;