From b7cd970493659848d407cc5a8792079408791ea2 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 24 May 2022 11:35:06 -0500 Subject: [PATCH] sd: add stub for SDIO support Add stub code for SDIO support, capable of verifying card responds to CMD5. This commit also changes the architecture of the SDIO probe step to make adding new protocol support more streamlined, and enable compiling out support for undesired protocols. Signed-off-by: Daniel DeGrasse --- drivers/disk/Kconfig.sdmmc | 1 + subsys/sd/CMakeLists.txt | 4 +- subsys/sd/Kconfig | 11 ++++ subsys/sd/sd.c | 103 +++++---------------------------- subsys/sd/sdio.c | 78 +++++++++++++++++++++++++ subsys/sd/sdio_priv.h | 16 +++++ subsys/sd/sdmmc.c | 87 ++++++++++------------------ tests/subsys/sd/sdmmc/prj.conf | 1 + 8 files changed, 152 insertions(+), 149 deletions(-) create mode 100644 subsys/sd/sdio.c create mode 100644 subsys/sd/sdio_priv.h 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