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
18 #include "sdmmc_common.h"
19
20 static const char* TAG = "sdmmc_init";
21
22 #define SDMMC_INIT_STEP(condition, function) \
23 do { \
24 if ((condition)) { \
25 esp_err_t err = (function)(card); \
26 if (err != ESP_OK) { \
27 ESP_LOGD(TAG, "%s: %s returned 0x%x", __func__, #function, err); \
28 return err; \
29 } \
30 } \
31 } while(0);
32
33
sdmmc_card_init(const sdmmc_host_t * config,sdmmc_card_t * card)34 esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card)
35 {
36 memset(card, 0, sizeof(*card));
37 memcpy(&card->host, config, sizeof(*config));
38 const bool is_spi = host_is_spi(card);
39 const bool always = true;
40 const bool io_supported = true;
41
42 /* Check if host flags are compatible with slot configuration. */
43 SDMMC_INIT_STEP(!is_spi, sdmmc_fix_host_flags);
44
45 /* Reset SDIO (CMD52, RES) before re-initializing IO (CMD5). */
46 SDMMC_INIT_STEP(io_supported, sdmmc_io_reset);
47
48 /* GO_IDLE_STATE (CMD0) command resets the card */
49 SDMMC_INIT_STEP(always, sdmmc_send_cmd_go_idle_state);
50
51 /* SEND_IF_COND (CMD8) command is used to identify SDHC/SDXC cards. */
52 SDMMC_INIT_STEP(always, sdmmc_init_sd_if_cond);
53
54 /* IO_SEND_OP_COND(CMD5), Determine if the card is an IO card. */
55 SDMMC_INIT_STEP(io_supported, sdmmc_init_io);
56
57 const bool is_mem = card->is_mem;
58 const bool is_sdio = !is_mem;
59
60 /* Enable CRC16 checks for data transfers in SPI mode */
61 SDMMC_INIT_STEP(is_spi, sdmmc_init_spi_crc);
62
63 /* Use SEND_OP_COND to set up card OCR */
64 SDMMC_INIT_STEP(is_mem, sdmmc_init_ocr);
65
66 const bool is_mmc = is_mem && card->is_mmc;
67 const bool is_sdmem = is_mem && !is_mmc;
68
69 ESP_LOGD(TAG, "%s: card type is %s", __func__,
70 is_sdio ? "SDIO" : is_mmc ? "MMC" : "SD");
71
72 /* Read the contents of CID register*/
73 SDMMC_INIT_STEP(is_mem, sdmmc_init_cid);
74
75 /* Assign RCA */
76 SDMMC_INIT_STEP(!is_spi, sdmmc_init_rca);
77
78 /* Read and decode the contents of CSD register */
79 SDMMC_INIT_STEP(is_mem, sdmmc_init_csd);
80
81 /* Decode the contents of mmc CID register */
82 SDMMC_INIT_STEP(is_mmc && !is_spi, sdmmc_init_mmc_decode_cid);
83
84 /* Switch the card from stand-by mode to data transfer mode (not needed if
85 * SPI interface is used). This is needed to issue SET_BLOCKLEN and
86 * SEND_SCR commands.
87 */
88 SDMMC_INIT_STEP(!is_spi, sdmmc_init_select_card);
89
90 /* SD memory cards:
91 * Set block len for SDSC cards to 512 bytes (same as SDHC)
92 * Read SCR
93 * Wait to enter data transfer state
94 */
95 SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_blocklen);
96 SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_scr);
97 SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_wait_data_ready);
98
99 /* MMC cards: read CXD */
100 SDMMC_INIT_STEP(is_mmc, sdmmc_init_mmc_read_ext_csd);
101
102 /* Try to switch card to HS mode if the card supports it.
103 * Set card->max_freq_khz value accordingly.
104 */
105 SDMMC_INIT_STEP(always, sdmmc_init_card_hs_mode);
106
107 /* Set bus width. One call for every kind of card, then one for the host */
108 if (!is_spi) {
109 SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_bus_width);
110 SDMMC_INIT_STEP(is_sdio, sdmmc_init_io_bus_width);
111 SDMMC_INIT_STEP(is_mmc, sdmmc_init_mmc_bus_width);
112 SDMMC_INIT_STEP(always, sdmmc_init_host_bus_width);
113 }
114
115 /* Switch to the host to use card->max_freq_khz frequency. */
116 SDMMC_INIT_STEP(always, sdmmc_init_host_frequency);
117
118 /* Sanity check after switching the bus mode and frequency */
119 SDMMC_INIT_STEP(is_sdmem, sdmmc_check_scr);
120 /* TODO: this is CMD line only, add data checks for eMMC */
121 SDMMC_INIT_STEP(is_mmc, sdmmc_init_mmc_check_csd);
122 /* TODO: add similar checks for SDIO */
123
124 return ESP_OK;
125 }
126