sdmmc_init.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*
  2. * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
  3. * Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include "sdmmc_common.h"
  18. static const char* TAG = "sdmmc_init";
  19. #define SDMMC_INIT_STEP(condition, function) \
  20. do { \
  21. if ((condition)) { \
  22. esp_err_t err = (function)(card); \
  23. if (err != ESP_OK) { \
  24. ESP_LOGD(TAG, "%s: %s returned 0x%x", __func__, #function, err); \
  25. return err; \
  26. } \
  27. } \
  28. } while(0);
  29. esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card)
  30. {
  31. memset(card, 0, sizeof(*card));
  32. memcpy(&card->host, config, sizeof(*config));
  33. const bool is_spi = host_is_spi(card);
  34. const bool always = true;
  35. const bool io_supported = true;
  36. /* Check if host flags are compatible with slot configuration. */
  37. SDMMC_INIT_STEP(!is_spi, sdmmc_fix_host_flags);
  38. /* Reset SDIO (CMD52, RES) before re-initializing IO (CMD5). */
  39. SDMMC_INIT_STEP(io_supported, sdmmc_io_reset);
  40. /* GO_IDLE_STATE (CMD0) command resets the card */
  41. SDMMC_INIT_STEP(always, sdmmc_send_cmd_go_idle_state);
  42. /* SEND_IF_COND (CMD8) command is used to identify SDHC/SDXC cards. */
  43. SDMMC_INIT_STEP(always, sdmmc_init_sd_if_cond);
  44. /* IO_SEND_OP_COND(CMD5), Determine if the card is an IO card. */
  45. SDMMC_INIT_STEP(io_supported, sdmmc_init_io);
  46. const bool is_mem = card->is_mem;
  47. const bool is_sdio = !is_mem;
  48. /* Enable CRC16 checks for data transfers in SPI mode */
  49. SDMMC_INIT_STEP(is_spi, sdmmc_init_spi_crc);
  50. /* Use SEND_OP_COND to set up card OCR */
  51. SDMMC_INIT_STEP(is_mem, sdmmc_init_ocr);
  52. const bool is_mmc = is_mem && card->is_mmc;
  53. const bool is_sdmem = is_mem && !is_mmc;
  54. ESP_LOGD(TAG, "%s: card type is %s", __func__,
  55. is_sdio ? "SDIO" : is_mmc ? "MMC" : "SD");
  56. /* Read and decode the contents of CID register and assign RCA */
  57. SDMMC_INIT_STEP(always, sdmmc_init_cid);
  58. /* Read and decode the contents of CSD register */
  59. SDMMC_INIT_STEP(is_mem, sdmmc_init_csd);
  60. /* Switch the card from stand-by mode to data transfer mode (not needed if
  61. * SPI interface is used). This is needed to issue SET_BLOCKLEN and
  62. * SEND_SCR commands.
  63. */
  64. SDMMC_INIT_STEP(!is_spi, sdmmc_init_select_card);
  65. /* SD memory cards:
  66. * Set block len for SDSC cards to 512 bytes (same as SDHC)
  67. * Read SCR
  68. * Wait to enter data transfer state
  69. */
  70. SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_blocklen);
  71. SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_scr);
  72. SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_wait_data_ready);
  73. /* MMC cards: read CXD */
  74. SDMMC_INIT_STEP(is_mmc, sdmmc_init_mmc_read_ext_csd);
  75. /* Try to switch card to HS mode if the card supports it.
  76. * Set card->max_freq_khz value accordingly.
  77. */
  78. SDMMC_INIT_STEP(always, sdmmc_init_card_hs_mode);
  79. /* Set bus width. One call for every kind of card, then one for the host */
  80. if (!is_spi) {
  81. SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_bus_width);
  82. SDMMC_INIT_STEP(is_sdio, sdmmc_init_io_bus_width);
  83. SDMMC_INIT_STEP(is_mmc, sdmmc_init_mmc_bus_width);
  84. SDMMC_INIT_STEP(always, sdmmc_init_host_bus_width);
  85. }
  86. /* Switch to the host to use card->max_freq_khz frequency. */
  87. SDMMC_INIT_STEP(always, sdmmc_init_host_frequency);
  88. /* Sanity check after switching the bus mode and frequency */
  89. SDMMC_INIT_STEP(is_sdmem, sdmmc_check_scr);
  90. /* TODO: add similar checks for eMMC and SDIO */
  91. return ESP_OK;
  92. }