diff --git a/drivers/disk/Kconfig.sdmmc b/drivers/disk/Kconfig.sdmmc index d2e7a0347ae..1b65adccc4e 100644 --- a/drivers/disk/Kconfig.sdmmc +++ b/drivers/disk/Kconfig.sdmmc @@ -28,6 +28,7 @@ config SDMMC_VOLUME_NAME config SDMMC_SUBSYS bool "SDMMC access via SD subsystem" select SD_STACK + select SDMMC_STACK select SDHC default y depends on DT_HAS_ZEPHYR_SDMMC_DISK_ENABLED diff --git a/subsys/sd/CMakeLists.txt b/subsys/sd/CMakeLists.txt index f56f2dd4920..0de1eb1fabf 100644 --- a/subsys/sd/CMakeLists.txt +++ b/subsys/sd/CMakeLists.txt @@ -4,5 +4,7 @@ if (CONFIG_SD_STACK) zephyr_interface_library_named(SD) zephyr_library() - zephyr_library_sources (sd.c sdmmc.c) + zephyr_library_sources(sd.c) + zephyr_library_sources_ifdef(CONFIG_SDMMC_STACK sdmmc.c) + zephyr_library_sources_ifdef(CONFIG_SDIO_STACK sdio.c) endif() diff --git a/subsys/sd/Kconfig b/subsys/sd/Kconfig index 04724b82dec..9999213a422 100644 --- a/subsys/sd/Kconfig +++ b/subsys/sd/Kconfig @@ -15,6 +15,17 @@ module = SD module-str = SD stack source "subsys/logging/Kconfig.template.log_config" +config SDMMC_STACK + bool "SDMMC protocol support" + help + Enable SDMMC protocol support. Required for SD memory cards to + function. + +config SDIO_STACK + bool "SDIO protocol support" + help + Enable SDIO protocol support. Required for SD I/O cards to function. + config SD_INIT_TIMEOUT int "Timeout while initializing SD card" default 1500 diff --git a/subsys/sd/sd.c b/subsys/sd/sd.c index fc86e1abb51..839d1d1124f 100644 --- a/subsys/sd/sd.c +++ b/subsys/sd/sd.c @@ -14,6 +14,7 @@ #include "sd_utils.h" #include "sdmmc_priv.h" +#include "sdio_priv.h" LOG_MODULE_REGISTER(sd, CONFIG_SD_LOG_LEVEL); @@ -159,71 +160,6 @@ static int sd_init_io(struct sd_card *card) return 0; } -/* - * Sends CMD5 to SD card, and uses response to determine if card - * is SDIO or SDMMC card. Return 0 if SDIO card, positive value if not, or - * negative errno on error - */ -int sd_test_sdio(struct sd_card *card) -{ - struct sdhc_command cmd = {0}; - int ret; - - cmd.opcode = SDIO_SEND_OP_COND; - cmd.arg = 0; - cmd.response_type = (SD_RSP_TYPE_R4 | SD_SPI_RSP_TYPE_R4); - cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; - ret = sdhc_request(card->sdhc, &cmd, NULL); - if (ret) { - /* - * We are just probing card, and it is likely an SD. - * return error - */ - card->type = CARD_SDMMC; - return SD_NOT_SDIO; - } - /* Check the number of I/O functions */ - card->num_io = ((cmd.response[0] & SDIO_OCR_IO_NUMBER) - >> SDIO_OCR_IO_NUMBER_SHIFT); - if ((card->num_io == 0) | ((cmd.response[0] & SDIO_IO_OCR_MASK) == 0)) { - if (cmd.response[0] & SDIO_OCR_MEM_PRESENT_FLAG) { - /* Card is not an SDIO card. */ - card->type = CARD_SDMMC; - return SD_NOT_SDIO; - } - /* Card is not a valid SD device. We do not support it */ - return -ENOTSUP; - } - /* Since we got a valid OCR response, - * we know this card is an SDIO card. - */ - card->type = CARD_SDIO; - return 0; -} - -/* - * Check SD card type - * Uses SDIO OCR response to determine what type of card is present. - */ -static int sd_check_card_type(struct sd_card *card) -{ - int ret; - - /* Test if the card response to CMD5 (only SDIO cards will) */ - /* Note that CMD5 can take many retries */ - ret = sd_test_sdio(card); - if ((ret == SD_NOT_SDIO) && card->type == CARD_SDMMC) { - LOG_INF("Detected SD card"); - return 0; - } else if ((ret == 0) && card->type == CARD_SDIO) { - LOG_INF("Detected SDIO card"); - return 0; - } - LOG_ERR("No usable card type was found"); - return -ENOTSUP; -} - - /* * Performs init flow described in section 3.6 of SD specification. */ @@ -243,33 +179,20 @@ static int sd_command_init(struct sd_card *card) if (ret) { return ret; } - /* Use CMD5 to determine card type */ - ret = sd_check_card_type(card); - if (ret) { - LOG_ERR("Unusable card"); - return -ENOTSUP; +#ifdef CONFIG_SDIO_STACK + /* Attempt to initialize SDIO card */ + if (!sdio_card_init(card)) { + return 0; } - if (card->type == CARD_SDMMC) { - /* - * Reset the card first- CMD5 sent to see if it is SDIO card - * may have left it in error state - */ - ret = sd_common_init(card); - if (ret) { - LOG_ERR("Init after CMD5 failed"); - return ret; - } - /* Perform memory card initialization */ - ret = sdmmc_card_init(card); - } else if (card->type == CARD_SDIO) { - LOG_ERR("SDIO cards not currently supported"); - return -ENOTSUP; +#endif /* CONFIG_SDIO_STACK */ +#ifdef CONFIG_SDMMC_STACK + /* Attempt to initialize SDMMC card */ + if (!sdmmc_card_init(card)) { + return 0; } - if (ret) { - LOG_ERR("Card init failed"); - return ret; - } - return 0; +#endif /* CONFIG_SDIO_STACK */ + /* Unknown card type */ + return -ENOTSUP; } /* Initializes SD/SDIO card */ diff --git a/subsys/sd/sdio.c b/subsys/sd/sdio.c new file mode 100644 index 00000000000..cdf02814443 --- /dev/null +++ b/subsys/sd/sdio.c @@ -0,0 +1,78 @@ +/* + * Copyright 2022 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "sd_utils.h" + +LOG_MODULE_DECLARE(sd, CONFIG_SD_LOG_LEVEL); + +/* + * Send SDIO OCR using CMD5 + */ +int sdio_send_ocr(struct sd_card *card, uint32_t ocr) +{ + struct sdhc_command cmd = {0}; + int ret; + int retries; + + cmd.opcode = SDIO_SEND_OP_COND; + cmd.arg = ocr; + cmd.response_type = (SD_RSP_TYPE_R4 | SD_SPI_RSP_TYPE_R4); + cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; + /* Send OCR5 to initialize card */ + for (retries = 0; retries < CONFIG_SD_OCR_RETRY_COUNT; retries++) { + ret = sdhc_request(card->sdhc, &cmd, NULL); + if (ret) { + if (ocr == 0) { + /* Just probing card, likely not SDIO */ + return SD_NOT_SDIO; + } + return ret; + } + if (ocr == 0) { + /* We are probing card, check number of IO functions */ + card->num_io = (cmd.response[0] & SDIO_OCR_IO_NUMBER) + >> SDIO_OCR_IO_NUMBER_SHIFT; + if ((card->num_io == 0) || + ((cmd.response[0] & SDIO_IO_OCR_MASK) == 0)) { + if (cmd.response[0] & SDIO_OCR_MEM_PRESENT_FLAG) { + /* Card is not an SDIO card */ + return SD_NOT_SDIO; + } + /* Card is not a supported SD device */ + return -ENOTSUP; + } + /* Card has IO present, return zero to + * indicate SDIO card + */ + return 0; + } + } +} + +/* + * Initialize an SDIO card for use with subsystem + */ +int sdio_card_init(struct sd_card *card) +{ + int ret; + + /* Probe card with SDIO OCR CM5 */ + ret = sdio_send_ocr(card, 0); + if (ret) { + return ret; + } + /* Card responded to ACMD41, type is SDIO */ + card->type = CARD_SDIO; + /* No support for SDIO */ + return -ENOTSUP; +} diff --git a/subsys/sd/sdio_priv.h b/subsys/sd/sdio_priv.h new file mode 100644 index 00000000000..ce646d53054 --- /dev/null +++ b/subsys/sd/sdio_priv.h @@ -0,0 +1,16 @@ +/* + * Copyright 2022 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#ifndef ZEPHYR_SUBSYS_SD_SDIO_PRIV_H_ +#define ZEPHYR_SUBSYS_SD_SDIO_PRIV_H_ + +#include +#include + +int sdio_card_init(struct sd_card *card); + +#endif /* ZEPHYR_SUBSYS_SD_SDIO_PRIV_H_ */ diff --git a/subsys/sd/sdmmc.c b/subsys/sd/sdmmc.c index a383288f0d8..9384192d78d 100644 --- a/subsys/sd/sdmmc.c +++ b/subsys/sd/sdmmc.c @@ -230,31 +230,15 @@ static int sdmmc_app_command(struct sd_card *card, int relative_card_address) return 0; } -/* Reads OCR from SPI mode card using CMD58 */ -static int sdmmc_spi_send_ocr(struct sd_card *card, uint32_t arg) -{ - struct sdhc_command cmd; - int ret; - - cmd.opcode = SD_SPI_READ_OCR; - cmd.arg = arg; - cmd.response_type = SD_SPI_RSP_TYPE_R3; - - ret = sdhc_request(card->sdhc, &cmd, NULL); - - card->ocr = cmd.response[1]; - return ret; -} - /* Sends OCR to card using ACMD41 */ -static int sdmmc_send_ocr(struct sd_card *card, int ocr_arg) +static int sdmmc_send_ocr(struct sd_card *card, int ocr) { struct sdhc_command cmd; int ret; int retries; cmd.opcode = SD_APP_SEND_OP_COND; - cmd.arg = ocr_arg; + cmd.arg = ocr; cmd.response_type = (SD_RSP_TYPE_R3 | SD_SPI_RSP_TYPE_R1); cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; /* Send initialization ACMD41 */ @@ -271,7 +255,7 @@ static int sdmmc_send_ocr(struct sd_card *card, int ocr_arg) /* OCR failed */ return ret; } - if (ocr_arg == 0) { + if (ocr == 0) { /* Just probing, don't wait for card to exit busy state */ return 0; } @@ -970,52 +954,39 @@ int sdmmc_card_init(struct sd_card *card) int ret; uint32_t ocr_arg = 0U; - if (card->host_props.is_spi && IS_ENABLED(CONFIG_SDHC_SUPPORTS_SPI_MODE)) { - /* SD card needs CMD58 before ACMD41 to read OCR */ - ret = sdmmc_spi_send_ocr(card, 0); - if (ret) { - /* Card is not an SD card */ - return ret; - } - if (card->flags & SD_SDHC_FLAG) { - ocr_arg |= SD_OCR_HOST_CAP_FLAG; - } - ret = sdmmc_send_ocr(card, ocr_arg); - if (ret) { - return ret; - } - /* Send second CMD58 to get CCS bit */ - ret = sdmmc_spi_send_ocr(card, ocr_arg); - } else if (IS_ENABLED(CONFIG_SDHC_SUPPORTS_NATIVE_MODE)) { - /* Send initial probing OCR */ - ret = sdmmc_send_ocr(card, 0); - if (ret) { - /* Card is not an SD card */ - return ret; - } - if (card->flags & SD_SDHC_FLAG) { - /* High capacity card. See if host supports 1.8V */ - if (card->host_props.host_caps.vol_180_support) { - ocr_arg |= SD_OCR_SWITCH_18_REQ_FLAG; - } - /* Set host high capacity support flag */ - ocr_arg |= SD_OCR_HOST_CAP_FLAG; + /* First send a probing OCR using ACMD41. Note that SPI cards also + * accept CMD58 at this point, but we skip this command as it is not + * required by the spec. + */ + ret = sdmmc_send_ocr(card, ocr_arg); + if (ret) { + return ret; + } + /* Card responded to ACMD41, type is SDMMC */ + card->type = CARD_SDMMC; + + if (card->flags & SD_SDHC_FLAG) { + /* High capacity card. See if host supports 1.8V */ + if (card->host_props.host_caps.vol_180_support) { + ocr_arg |= SD_OCR_SWITCH_18_REQ_FLAG; } + /* Set host high capacity support flag */ + ocr_arg |= SD_OCR_HOST_CAP_FLAG; + } + if (IS_ENABLED(CONFIG_SDHC_SUPPORTS_NATIVE_MODE)) { /* Set voltage window */ if (card->host_props.host_caps.vol_300_support) { ocr_arg |= SD_OCR_VDD29_30FLAG; } ocr_arg |= (SD_OCR_VDD32_33FLAG | SD_OCR_VDD33_34FLAG); - /* Momentary delay before initialization OCR. Some cards will - * never leave busy state if init OCR is sent too soon after - * probing OCR - */ - k_busy_wait(100); - /* Send SD OCR to card to initialize it */ - ret = sdmmc_send_ocr(card, ocr_arg); - } else { - return -ENOTSUP; } + /* Momentary delay before initialization OCR. Some cards will + * never leave busy state if init OCR is sent too soon after + * probing OCR + */ + k_busy_wait(100); + /* Send SD OCR to card to initialize it */ + ret = sdmmc_send_ocr(card, ocr_arg); if (ret) { LOG_ERR("Failed to query card OCR"); return ret; diff --git a/tests/subsys/sd/sdmmc/prj.conf b/tests/subsys/sd/sdmmc/prj.conf index 9f430a1f475..46b8b135cbe 100644 --- a/tests/subsys/sd/sdmmc/prj.conf +++ b/tests/subsys/sd/sdmmc/prj.conf @@ -2,5 +2,6 @@ CONFIG_TEST=y CONFIG_ZTEST=y CONFIG_SDHC=y CONFIG_SD_STACK=y +CONFIG_SDMMC_STACK=y CONFIG_LOG=y CONFIG_ZTEST_NEW_API=y