kopia lustrzana https://github.com/espressif/esp-idf
Merge branch 'bugfix/sdmmc_host_cclk_lp' into 'master'
sdmmc: keep clock enabled for the duration of ACMD41 Closes IDF-6004 See merge request espressif/esp-idf!20470pull/11112/head
commit
da6041e1b5
|
@ -40,6 +40,7 @@ extern "C" {
|
||||||
.get_bus_width = &sdmmc_host_get_slot_width, \
|
.get_bus_width = &sdmmc_host_get_slot_width, \
|
||||||
.set_bus_ddr_mode = &sdmmc_host_set_bus_ddr_mode, \
|
.set_bus_ddr_mode = &sdmmc_host_set_bus_ddr_mode, \
|
||||||
.set_card_clk = &sdmmc_host_set_card_clk, \
|
.set_card_clk = &sdmmc_host_set_card_clk, \
|
||||||
|
.set_cclk_always_on = &sdmmc_host_set_cclk_always_on, \
|
||||||
.do_transaction = &sdmmc_host_do_transaction, \
|
.do_transaction = &sdmmc_host_do_transaction, \
|
||||||
.deinit = &sdmmc_host_deinit, \
|
.deinit = &sdmmc_host_deinit, \
|
||||||
.io_int_enable = sdmmc_host_io_int_enable, \
|
.io_int_enable = sdmmc_host_io_int_enable, \
|
||||||
|
@ -204,6 +205,19 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz);
|
||||||
*/
|
*/
|
||||||
esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled);
|
esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable or disable always-on card clock
|
||||||
|
* When cclk_always_on is false, the host controller is allowed to shut down
|
||||||
|
* the card clock between the commands. When cclk_always_on is true, the clock
|
||||||
|
* is generated even if no command is in progress.
|
||||||
|
* @param slot slot number
|
||||||
|
* @param cclk_always_on enable or disable always-on clock
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_ERR_INVALID_ARG if the slot number is invalid
|
||||||
|
*/
|
||||||
|
esp_err_t sdmmc_host_set_cclk_always_on(int slot, bool cclk_always_on);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send command to the card and get response
|
* @brief Send command to the card and get response
|
||||||
*
|
*
|
||||||
|
|
|
@ -175,6 +175,7 @@ typedef struct {
|
||||||
size_t (*get_bus_width)(int slot); /*!< host function to get bus width */
|
size_t (*get_bus_width)(int slot); /*!< host function to get bus width */
|
||||||
esp_err_t (*set_bus_ddr_mode)(int slot, bool ddr_enable); /*!< host function to set DDR mode */
|
esp_err_t (*set_bus_ddr_mode)(int slot, bool ddr_enable); /*!< host function to set DDR mode */
|
||||||
esp_err_t (*set_card_clk)(int slot, uint32_t freq_khz); /*!< host function to set card clock frequency */
|
esp_err_t (*set_card_clk)(int slot, uint32_t freq_khz); /*!< host function to set card clock frequency */
|
||||||
|
esp_err_t (*set_cclk_always_on)(int slot, bool cclk_always_on); /*!< host function to set whether the clock is always enabled */
|
||||||
esp_err_t (*do_transaction)(int slot, sdmmc_command_t* cmdinfo); /*!< host function to do a transaction */
|
esp_err_t (*do_transaction)(int slot, sdmmc_command_t* cmdinfo); /*!< host function to do a transaction */
|
||||||
union {
|
union {
|
||||||
esp_err_t (*deinit)(void); /*!< host function to deinitialize the driver */
|
esp_err_t (*deinit)(void); /*!< host function to deinitialize the driver */
|
||||||
|
|
|
@ -609,6 +609,20 @@ esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled)
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t sdmmc_host_set_cclk_always_on(int slot, bool cclk_always_on)
|
||||||
|
{
|
||||||
|
if (!(slot == 0 || slot == 1)) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
if (cclk_always_on) {
|
||||||
|
SDMMC.clkena.cclk_low_power &= ~BIT(slot);
|
||||||
|
} else {
|
||||||
|
SDMMC.clkena.cclk_low_power |= BIT(slot);
|
||||||
|
}
|
||||||
|
sdmmc_host_clock_update_command(slot);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static void sdmmc_host_dma_init(void)
|
static void sdmmc_host_dma_init(void)
|
||||||
{
|
{
|
||||||
SDMMC.ctrl.dma_enable = 1;
|
SDMMC.ctrl.dma_enable = 1;
|
||||||
|
|
|
@ -45,6 +45,7 @@ typedef int sdspi_dev_handle_t;
|
||||||
.get_bus_width = NULL, \
|
.get_bus_width = NULL, \
|
||||||
.set_bus_ddr_mode = NULL, \
|
.set_bus_ddr_mode = NULL, \
|
||||||
.set_card_clk = &sdspi_host_set_card_clk, \
|
.set_card_clk = &sdspi_host_set_card_clk, \
|
||||||
|
.set_cclk_always_on = NULL, \
|
||||||
.do_transaction = &sdspi_host_do_transaction, \
|
.do_transaction = &sdspi_host_do_transaction, \
|
||||||
.deinit_p = &sdspi_host_remove_device, \
|
.deinit_p = &sdspi_host_remove_device, \
|
||||||
.io_int_enable = &sdspi_host_io_int_enable, \
|
.io_int_enable = &sdspi_host_io_int_enable, \
|
||||||
|
|
|
@ -107,6 +107,19 @@ esp_err_t sdmmc_send_cmd_send_op_cond(sdmmc_card_t* card, uint32_t ocr, uint32_t
|
||||||
{
|
{
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
|
|
||||||
|
/* If the host supports this, keep card clock enabled
|
||||||
|
* from the start of ACMD41 until the card is idle.
|
||||||
|
* (Ref. SD spec, section 4.4 "Clock control".)
|
||||||
|
*/
|
||||||
|
if (card->host.set_cclk_always_on != NULL) {
|
||||||
|
err = card->host.set_cclk_always_on(card->host.slot, true);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s: set_cclk_always_on (1) err=0x%x", __func__, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
ESP_LOGV(TAG, "%s: keeping clock on during ACMD41", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
sdmmc_command_t cmd = {
|
sdmmc_command_t cmd = {
|
||||||
.arg = ocr,
|
.arg = ocr,
|
||||||
.flags = SCF_CMD_BCR | SCF_RSP_R3,
|
.flags = SCF_CMD_BCR | SCF_RSP_R3,
|
||||||
|
@ -131,7 +144,7 @@ esp_err_t sdmmc_send_cmd_send_op_cond(sdmmc_card_t* card, uint32_t ocr, uint32_t
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
if (--err_cnt == 0) {
|
if (--err_cnt == 0) {
|
||||||
ESP_LOGD(TAG, "%s: sdmmc_send_app_cmd err=0x%x", __func__, err);
|
ESP_LOGD(TAG, "%s: sdmmc_send_app_cmd err=0x%x", __func__, err);
|
||||||
return err;
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGV(TAG, "%s: ignoring err=0x%x", __func__, err);
|
ESP_LOGV(TAG, "%s: ignoring err=0x%x", __func__, err);
|
||||||
continue;
|
continue;
|
||||||
|
@ -151,13 +164,29 @@ esp_err_t sdmmc_send_cmd_send_op_cond(sdmmc_card_t* card, uint32_t ocr, uint32_t
|
||||||
}
|
}
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nretries == 0) {
|
if (nretries == 0) {
|
||||||
return ESP_ERR_TIMEOUT;
|
err = ESP_ERR_TIMEOUT;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ocrp) {
|
if (ocrp) {
|
||||||
*ocrp = MMC_R3(cmd.response);
|
*ocrp = MMC_R3(cmd.response);
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
|
||||||
|
err = ESP_OK;
|
||||||
|
done:
|
||||||
|
|
||||||
|
if (card->host.set_cclk_always_on != NULL) {
|
||||||
|
esp_err_t err_cclk_dis = card->host.set_cclk_always_on(card->host.slot, false);
|
||||||
|
if (err_cclk_dis != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s: set_cclk_always_on (2) err=0x%x", __func__, err);
|
||||||
|
/* If we failed to disable clock, don't overwrite 'err' to return the original error */
|
||||||
|
}
|
||||||
|
ESP_LOGV(TAG, "%s: clock always-on mode disabled", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t sdmmc_send_cmd_read_ocr(sdmmc_card_t *card, uint32_t *ocrp)
|
esp_err_t sdmmc_send_cmd_read_ocr(sdmmc_card_t *card, uint32_t *ocrp)
|
||||||
|
|
Ładowanie…
Reference in New Issue