diff --git a/drivers/disk/CMakeLists.txt b/drivers/disk/CMakeLists.txt index 20ac00a246a..7a80a05cfcd 100644 --- a/drivers/disk/CMakeLists.txt +++ b/drivers/disk/CMakeLists.txt @@ -10,7 +10,6 @@ zephyr_library_sources_ifdef(CONFIG_DISK_DRIVER_RAM ramdisk.c) zephyr_library_sources_ifdef(CONFIG_SDMMC_OVER_SPI sdmmc_spi.c) zephyr_library_sources_ifdef(CONFIG_SDMMC_STM32 sdmmc_stm32.c) -zephyr_library_sources_ifdef(CONFIG_SDMMC_USDHC usdhc.c) zephyr_library_sources_ifdef(CONFIG_SDMMC_SUBSYS sdmmc_subsys.c) endif() diff --git a/drivers/disk/Kconfig.sdmmc b/drivers/disk/Kconfig.sdmmc index ec24ea1d70c..671e3240c65 100644 --- a/drivers/disk/Kconfig.sdmmc +++ b/drivers/disk/Kconfig.sdmmc @@ -3,7 +3,6 @@ # SPDX-License-Identifier: Apache-2.0 DT_COMPAT_ZEPHYR_MMC_SPI_SLOT := zephyr,mmc-spi-slot -DT_COMPAT_NXP_USDHC := nxp,imx-usdhc DT_COMPAT_ST_STM32_SDMMC := st,stm32-sdmmc DT_COMPAT_ZEPHYR_MMC := zephyr,sdmmc-disk @@ -42,18 +41,6 @@ config SDMMC_SUBSYS help Enable SDMMC access via SD subsystem -config SDMMC_USDHC - bool "NXP i.MXRT USDHC driver" - depends on (HAS_MCUX_USDHC1 || HAS_MCUX_USDHC2) - default $(dt_compat_enabled,$(DT_COMPAT_NXP_USDHC)) - help - File system on a SDHC card accessed over - NXP USDHC. - -if SDMMC_USDHC -source "drivers/disk/Kconfig.usdhc" -endif - config SDMMC_STM32 bool "STM32 SDMMC driver" depends on HAS_STM32CUBE diff --git a/drivers/disk/Kconfig.usdhc b/drivers/disk/Kconfig.usdhc deleted file mode 100644 index bbaede52ff2..00000000000 --- a/drivers/disk/Kconfig.usdhc +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2021 NXP -# SPDX-License-Identifier: Apache-2.0 - -# USDHC peripheral require the SD card to power cycle after DAT3 is -# pulled low -config SDMMC_USDHC_DAT3_PWR_TOGGLE - bool - help - USDHC peripheral requires the SD card power to be cycled after DAT3 is - pulled high, before the USDHC peripheral can detect the SD card via DAT3 - pull - -config SDMMC_USDHC_DAT3_PWR_DELAY - int - default 0 - help - Period in milliseconds to delay between powering off the SD card and - applying power again, whenever the SD card power will be cycled. diff --git a/drivers/disk/usdhc.c b/drivers/disk/usdhc.c deleted file mode 100644 index 1dadd8bbc06..00000000000 --- a/drivers/disk/usdhc.c +++ /dev/null @@ -1,3058 +0,0 @@ -/* - * Copyright (c) 2019 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT nxp_imx_usdhc - -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_PINCTRL -#include -#define PINCTRL_STATE_SLOW PINCTRL_STATE_PRIV_START -#define PINCTRL_STATE_MED (PINCTRL_STATE_PRIV_START + 1U) -#define PINCTRL_STATE_FAST (PINCTRL_STATE_PRIV_START + 2U) -#define PINCTRL_STATE_NOPULL (PINCTRL_STATE_PRIV_START + 3U) -#endif - -#include "sdmmc_sdhc.h" - -#include -LOG_MODULE_REGISTER(usdhc, CONFIG_SDMMC_LOG_LEVEL); - -enum usdhc_cmd_type { - USDHC_CMD_TYPE_NORMAL = 0U, - /*!< Normal command */ - USDHC_CMD_TYPE_SUSPEND = 1U, - /*!< Suspend command */ - USDHC_CMD_TYPE_RESUME = 2U, - /*!< Resume command */ - USDHC_CMD_TYPE_ABORT = 3U, - /*!< Abort command */ - USDHC_CMD_TYPE_EMPTY = 4U, - /*!< Empty command */ -}; - -enum usdhc_status_flag { - USDHC_CMD_INHIBIT_FLAG = - USDHC_PRES_STATE_CIHB_MASK, - /*!< Command inhibit */ - USDHC_DATA_INHIBIT_FLAG = - USDHC_PRES_STATE_CDIHB_MASK, - /*!< Data inhibit */ - USDHC_DATA_LINE_ACTIVE_FLAG = - USDHC_PRES_STATE_DLA_MASK, - /*!< Data line active */ - USDHC_SD_CLK_STATUS_FLAG = - USDHC_PRES_STATE_SDSTB_MASK, - /*!< SD bus clock stable */ - USDHC_WRITE_ACTIVE_FLAG = - USDHC_PRES_STATE_WTA_MASK, - /*!< Write transfer active */ - USDHC_READ_ACTIVE_FLAG = - USDHC_PRES_STATE_RTA_MASK, - /*!< Read transfer active */ - USDHC_BUF_WRITE_ENABLE_FLAG = - USDHC_PRES_STATE_BWEN_MASK, - /*!< Buffer write enable */ - USDHC_BUF_READ_ENABLE_FLAG = - USDHC_PRES_STATE_BREN_MASK, - /*!< Buffer read enable */ - USDHC_RETUNING_REQ_FLAG = - USDHC_PRES_STATE_RTR_MASK, - /*!< re-tuning request flag ,only used for SDR104 mode */ - USDHC_DELAY_SETTING_DONE_FLAG = - USDHC_PRES_STATE_TSCD_MASK, - /*!< delay setting finished flag */ - USDHC_CARD_INSERTED_FLAG = - USDHC_PRES_STATE_CINST_MASK, - /*!< Card inserted */ - USDHC_CMD_LINE_LEVEL_FLAG = - USDHC_PRES_STATE_CLSL_MASK, - /*!< Command line signal level */ - USDHC_DATA0_LINE_LEVEL_FLAG = - 1U << USDHC_PRES_STATE_DLSL_SHIFT, - /*!< Data0 line signal level */ - USDHC_DATA1_LINE_LEVEL_FLAG = - 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 1U), - /*!< Data1 line signal level */ - USDHC_DATA2_LINE_LEVEL_FLAG = - 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 2U), - /*!< Data2 line signal level */ - USDHC_DATA3_LINE_LEVEL_FLAG = - 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 3U), - /*!< Data3 line signal level */ - USDHC_DATA4_LINE_LEVEL_FLAG = - 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 4U), - /*!< Data4 line signal level */ - USDHC_DATA5_LINE_LEVEL_FLAG = - 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 5U), - /*!< Data5 line signal level */ - USDHC_DATA6_LINE_LEVEL_FLAG = - 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 6U), - /*!< Data6 line signal level */ - USDHC_DATA7_LINE_LEVEL_FLAG = - (int)(1U << (USDHC_PRES_STATE_DLSL_SHIFT + 7U)), - /*!< Data7 line signal level */ -}; - -enum usdhc_transfer_flag { - USDHC_ENABLE_DMA_FLAG = - USDHC_MIX_CTRL_DMAEN_MASK, - /*!< Enable DMA */ - - USDHC_CMD_TYPE_SUSPEND_FLAG = - (USDHC_CMD_XFR_TYP_CMDTYP(1U)), - /*!< Suspend command */ - USDHC_CMD_TYPE_RESUME_FLAG = - (USDHC_CMD_XFR_TYP_CMDTYP(2U)), - /*!< Resume command */ - USDHC_CMD_TYPE_ABORT_FLAG = - (USDHC_CMD_XFR_TYP_CMDTYP(3U)), - /*!< Abort command */ - - USDHC_BLOCK_COUNT_FLAG = - USDHC_MIX_CTRL_BCEN_MASK, - /*!< Enable block count */ - USDHC_AUTO_CMD12_FLAG = - USDHC_MIX_CTRL_AC12EN_MASK, - /*!< Enable auto CMD12 */ - USDHC_DATA_READ_FLAG = - USDHC_MIX_CTRL_DTDSEL_MASK, - /*!< Enable data read */ - USDHC_MULTIPLE_BLOCK_FLAG = - USDHC_MIX_CTRL_MSBSEL_MASK, - /*!< Multiple block data read/write */ - USDHC_AUTO_CMD23FLAG = - USDHC_MIX_CTRL_AC23EN_MASK, - /*!< Enable auto CMD23 */ - USDHC_RSP_LEN_136_FLAG = - USDHC_CMD_XFR_TYP_RSPTYP(1U), - /*!< 136 bit response length */ - USDHC_RSP_LEN_48_FLAG = - USDHC_CMD_XFR_TYP_RSPTYP(2U), - /*!< 48 bit response length */ - USDHC_RSP_LEN_48_BUSY_FLAG = - USDHC_CMD_XFR_TYP_RSPTYP(3U), - /*!< 48 bit response length with busy status */ - - USDHC_CRC_CHECK_FLAG = - USDHC_CMD_XFR_TYP_CCCEN_MASK, - /*!< Enable CRC check */ - USDHC_IDX_CHECK_FLAG = - USDHC_CMD_XFR_TYP_CICEN_MASK, - /*!< Enable index check */ - USDHC_DATA_PRESENT_FLAG = - USDHC_CMD_XFR_TYP_DPSEL_MASK, - /*!< Data present flag */ -}; - -enum usdhc_int_status_flag { - USDHC_INT_CMD_DONE_FLAG = - USDHC_INT_STATUS_CC_MASK, - /*!< Command complete */ - USDHC_INT_DATA_DONE_FLAG = - USDHC_INT_STATUS_TC_MASK, - /*!< Data complete */ - USDHC_INT_BLK_GAP_EVENT_FLAG = - USDHC_INT_STATUS_BGE_MASK, - /*!< Block gap event */ - USDHC_INT_DMA_DONE_FLAG = - USDHC_INT_STATUS_DINT_MASK, - /*!< DMA interrupt */ - USDHC_INT_BUF_WRITE_READY_FLAG = - USDHC_INT_STATUS_BWR_MASK, - /*!< Buffer write ready */ - USDHC_INT_BUF_READ_READY_FLAG = - USDHC_INT_STATUS_BRR_MASK, - /*!< Buffer read ready */ - USDHC_INT_CARD_INSERTED_FLAG = - USDHC_INT_STATUS_CINS_MASK, - /*!< Card inserted */ - USDHC_INT_CARD_REMOVED_FLAG = - USDHC_INT_STATUS_CRM_MASK, - /*!< Card removed */ - USDHC_INT_CARD_INTERRUPT_FLAG = - USDHC_INT_STATUS_CINT_MASK, - /*!< Card interrupt */ - - USDHC_INT_RE_TUNING_EVENT_FLAG = - USDHC_INT_STATUS_RTE_MASK, - /*!< Re-Tuning event,only for SD3.0 SDR104 mode */ - USDHC_INT_TUNING_PASS_FLAG = - USDHC_INT_STATUS_TP_MASK, - /*!< SDR104 mode tuning pass flag */ - USDHC_INT_TUNING_ERR_FLAG = - USDHC_INT_STATUS_TNE_MASK, - /*!< SDR104 tuning error flag */ - - USDHC_INT_CMD_TIMEOUT_FLAG = - USDHC_INT_STATUS_CTOE_MASK, - /*!< Command timeout error */ - USDHC_INT_CMD_CRC_ERR_FLAG = - USDHC_INT_STATUS_CCE_MASK, - /*!< Command CRC error */ - USDHC_INT_CMD_ENDBIT_ERR_FLAG = - USDHC_INT_STATUS_CEBE_MASK, - /*!< Command end bit error */ - USDHC_INT_CMD_IDX_ERR_FLAG = - USDHC_INT_STATUS_CIE_MASK, - /*!< Command index error */ - USDHC_INT_DATA_TIMEOUT_FLAG = - USDHC_INT_STATUS_DTOE_MASK, - /*!< Data timeout error */ - USDHC_INT_DATA_CRC_ERR_FLAG = - USDHC_INT_STATUS_DCE_MASK, - /*!< Data CRC error */ - USDHC_INT_DATA_ENDBIT_ERR_FLAG = - USDHC_INT_STATUS_DEBE_MASK, - /*!< Data end bit error */ - USDHC_INT_AUTO_CMD12_ERR_FLAG = - USDHC_INT_STATUS_AC12E_MASK, - /*!< Auto CMD12 error */ - USDHC_INT_DMA_ERR_FLAG = - USDHC_INT_STATUS_DMAE_MASK, - /*!< DMA error */ - - USDHC_INT_CMD_ERR_FLAG = - (USDHC_INT_CMD_TIMEOUT_FLAG | - USDHC_INT_CMD_CRC_ERR_FLAG | - USDHC_INT_CMD_ENDBIT_ERR_FLAG | - USDHC_INT_CMD_IDX_ERR_FLAG), - /*!< Command error */ - USDHC_INT_DATA_ERR_FLAG = - (USDHC_INT_DATA_TIMEOUT_FLAG | - USDHC_INT_DATA_CRC_ERR_FLAG | - USDHC_INT_DATA_ENDBIT_ERR_FLAG | - USDHC_INT_AUTO_CMD12_ERR_FLAG), - /*!< Data error */ - USDHC_INT_ERR_FLAG = - (USDHC_INT_CMD_ERR_FLAG | - USDHC_INT_DATA_ERR_FLAG | - USDHC_INT_DMA_ERR_FLAG), - /*!< All error */ - USDHC_INT_DATA_FLAG = - (USDHC_INT_DATA_DONE_FLAG | - USDHC_INT_DMA_DONE_FLAG | - USDHC_INT_BUF_WRITE_READY_FLAG | - USDHC_INT_BUF_READ_READY_FLAG | - USDHC_INT_DATA_ERR_FLAG | - USDHC_INT_DMA_ERR_FLAG), - /*!< Data interrupts */ - USDHC_INT_CMD_FLAG = - (USDHC_INT_CMD_DONE_FLAG | - USDHC_INT_CMD_ERR_FLAG), - /*!< Command interrupts */ - USDHC_INT_CARD_DETECT_FLAG = - (USDHC_INT_CARD_INSERTED_FLAG | - USDHC_INT_CARD_REMOVED_FLAG), - /*!< Card detection interrupts */ - USDHC_INT_SDR104_TUNING_FLAG = - (USDHC_INT_RE_TUNING_EVENT_FLAG | - USDHC_INT_TUNING_PASS_FLAG | - USDHC_INT_TUNING_ERR_FLAG), - - USDHC_INT_ALL_FLAGS = - (USDHC_INT_BLK_GAP_EVENT_FLAG | - USDHC_INT_CARD_INTERRUPT_FLAG | - USDHC_INT_CMD_FLAG | - USDHC_INT_DATA_FLAG | - USDHC_INT_ERR_FLAG | - USDHC_INT_SDR104_TUNING_FLAG), - /*!< All flags mask */ -}; - -enum usdhc_data_bus_width { - USDHC_DATA_BUS_WIDTH_1BIT = 0U, - /*!< 1-bit mode */ - USDHC_DATA_BUS_WIDTH_4BIT = 1U, - /*!< 4-bit mode */ - USDHC_DATA_BUS_WIDTH_8BIT = 2U, - /*!< 8-bit mode */ -}; - -#define USDHC_MAX_BLOCK_COUNT \ - (USDHC_BLK_ATT_BLKCNT_MASK >> \ - USDHC_BLK_ATT_BLKCNT_SHIFT) - -struct usdhc_cmd { - uint32_t index; /*cmd idx*/ - uint32_t argument; /*cmd arg*/ - enum usdhc_cmd_type cmd_type; - enum sdhc_rsp_type rsp_type; - uint32_t response[4U]; - uint32_t rsp_err_flags; - uint32_t flags; -}; - -struct usdhc_data { - bool cmd12; - /* Enable auto CMD12 */ - bool cmd23; - /* Enable auto CMD23 */ - bool ignore_err; - /* Enable to ignore error event - * to read/write all the data - */ - bool data_enable; - uint8_t data_type; - /* this is used to distinguish - * the normal/tuning/boot data - */ - uint32_t block_size; - /* Block size - */ - uint32_t block_count; - /* Block count - */ - uint32_t *rx_data; - /* Buffer to save data read - */ - const uint32_t *tx_data; - /* Data buffer to write - */ -}; - -enum usdhc_dma_mode { - USDHC_DMA_SIMPLE = 0U, - /* external DMA - */ - USDHC_DMA_ADMA1 = 1U, - /* ADMA1 is selected - */ - USDHC_DMA_ADMA2 = 2U, - /* ADMA2 is selected - */ - USDHC_EXT_DMA = 3U, - /* external dma mode select - */ -}; - -enum usdhc_burst_len { - USDHC_INCR_BURST_LEN = 0x01U, - /* enable burst len for INCR - */ - USDHC_INCR4816_BURST_LEN = 0x02U, - /* enable burst len for INCR4/INCR8/INCR16 - */ - USDHC_INCR4816_BURST_LEN_WRAP = 0x04U, - /* enable burst len for INCR4/8/16 WRAP - */ -}; - -struct usdhc_adma_config { - enum usdhc_dma_mode dma_mode; - /* DMA mode - */ - enum usdhc_burst_len burst_len; - /* burst len config - */ - uint32_t *adma_table; - /* ADMA table address, - * can't be null if transfer way is ADMA1/ADMA2 - */ - uint32_t adma_table_words; - /* ADMA table length united as words, - * can't be 0 if transfer way is ADMA1/ADMA2 - */ -}; - -struct usdhc_context { - bool cmd_only; - struct usdhc_cmd cmd; - struct usdhc_data data; - struct usdhc_adma_config dma_cfg; -}; - -enum usdhc_endian_mode { - USDHC_BIG_ENDIAN = 0U, - /* Big endian mode - */ - USDHC_HALF_WORD_BIG_ENDIAN = 1U, - /* Half word big endian mode - */ - USDHC_LITTLE_ENDIAN = 2U, - /* Little endian mode - */ -}; - -struct usdhc_config { - USDHC_Type *base; - const struct device *clock_dev; - clock_control_subsys_t clock_subsys; - uint8_t nusdhc; - - char *pwr_name; - uint8_t pwr_pin; - gpio_dt_flags_t pwr_flags; - - char *detect_name; - uint8_t detect_pin; - gpio_dt_flags_t detect_flags; - - bool detect_dat3; - - bool no_1_8_v; - - uint32_t data_timeout; - /* Data timeout value - */ - enum usdhc_endian_mode endian; - /* Endian mode - */ - uint8_t read_watermark; - /* Watermark level for DMA read operation. - * Available range is 1 ~ 128. - */ - uint8_t write_watermark; - /* Watermark level for DMA write operation. - * Available range is 1 ~ 128. - */ - uint8_t read_burst_len; - /* Read burst len - */ - uint8_t write_burst_len; - /* Write burst len - */ -#ifdef CONFIG_PINCTRL - const struct pinctrl_dev_config *pincfg; - /* Pin configuration - */ -#endif -}; - -struct usdhc_capability { - uint32_t max_blk_len; - uint32_t max_blk_cnt; - uint32_t host_flags; -}; - -enum host_detect_type { - SD_DETECT_GPIO_CD, - /* sd card detect by CD pin through GPIO - */ - SD_DETECT_HOST_CD, - /* sd card detect by CD pin through host - */ - SD_DETECT_HOST_DATA3, - /* sd card detect by DAT3 pin through host - */ -}; - -struct usdhc_client_info { - uint32_t busclk_hz; - uint32_t relative_addr; - uint32_t version; - uint32_t card_flags; - uint32_t raw_cid[4U]; - uint32_t raw_csd[4U]; - uint32_t raw_scr[2U]; - uint32_t raw_ocr; - struct sd_cid cid; - struct sd_csd csd; - struct sd_scr scr; - uint32_t sd_block_count; - uint32_t sd_block_size; - enum sd_timing_mode sd_timing; - enum sd_driver_strength driver_strength; - enum sd_max_current max_current; - enum sd_voltage voltage; -}; - -struct usdhc_priv { - bool host_ready; - uint8_t status; - - const struct device *pwr_gpio; - const struct device *detect_gpio; - struct gpio_callback detect_cb; - - enum host_detect_type detect_type; - bool inserted; - - uint32_t src_clk_hz; - - const struct usdhc_config *config; - struct usdhc_capability host_capability; - - struct usdhc_client_info card_info; - - struct usdhc_context op_context; -}; - -enum usdhc_xfer_data_type { - USDHC_XFER_NORMAL = 0U, - /* transfer normal read/write data - */ - USDHC_XFER_TUNING = 1U, - /* transfer tuning data - */ - USDHC_XFER_BOOT = 2U, - /* transfer boot data - */ - USDHC_XFER_BOOT_CONTINUOUS = 3U, - /* transfer boot data continuous - */ -}; - -#define USDHC_ADMA1_ADDRESS_ALIGN (4096U) -#define USDHC_ADMA1_LENGTH_ALIGN (4096U) -#define USDHC_ADMA2_ADDRESS_ALIGN (4U) -#define USDHC_ADMA2_LENGTH_ALIGN (4U) - -#define USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT (16U) -#define USDHC_ADMA2_DESCRIPTOR_LENGTH_MASK (0xFFFFU) -#define USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY \ - (USDHC_ADMA2_DESCRIPTOR_LENGTH_MASK - 3U) - -#define SWAP_WORD_BYTE_SEQUENCE(x) (__REV(x)) -#define SWAP_HALF_WROD_BYTE_SEQUENCE(x) (__REV16(x)) - -#define SDMMCHOST_NOT_SUPPORT 0U - -#define CARD_BUS_FREQ_50MHZ (0U) -#define CARD_BUS_FREQ_100MHZ0 (1U) -#define CARD_BUS_FREQ_100MHZ1 (2U) -#define CARD_BUS_FREQ_200MHZ (3U) - -#define CARD_BUS_STRENGTH_0 (0U) -#define CARD_BUS_STRENGTH_1 (1U) -#define CARD_BUS_STRENGTH_2 (2U) -#define CARD_BUS_STRENGTH_3 (3U) -#define CARD_BUS_STRENGTH_4 (4U) -#define CARD_BUS_STRENGTH_5 (5U) -#define CARD_BUS_STRENGTH_6 (6U) -#define CARD_BUS_STRENGTH_7 (7U) - -#define USDHC_DAT3_PULL_DOWN 0U /*!< Data 3 pull down */ -#define USDHC_DAT3_PULL_UP 1U /*!< Data 3 pull up */ -#define USDHC_WAIT_IDLE_TIMEOUT 600U - -enum usdhc_adma_flag { - USDHC_ADMA_SINGLE_FLAG = 0U, - USDHC_ADMA_MUTI_FLAG = 1U, -}; - -enum usdhc_adma2_descriptor_flag { - USDHC_ADMA2_VALID_FLAG = (1U << 0U), - /* Valid flag - */ - USDHC_ADMA2_END_FLAG = (1U << 1U), - /* End flag - */ - USDHC_ADMA2_INT_FLAG = (1U << 2U), - /* Interrupt flag - */ - USDHC_ADMA2_ACTIVITY1_FLAG = (1U << 4U), - /* Activity 1 mask - */ - USDHC_ADMA2_ACTIVITY2_FLAG = (1U << 5U), - /* Activity 2 mask - */ - - USDHC_ADMA2_NOP_FLAG = - (USDHC_ADMA2_VALID_FLAG), - /* No operation - */ - USDHC_ADMA2_RESERVED_FLAG = - (USDHC_ADMA2_ACTIVITY1_FLAG | - USDHC_ADMA2_VALID_FLAG), - /* Reserved - */ - USDHC_ADMA2_XFER_FLAG = - (USDHC_ADMA2_ACTIVITY2_FLAG | - USDHC_ADMA2_VALID_FLAG), - /* Transfer type - */ - USDHC_ADMA2_LINK_FLAG = - (USDHC_ADMA2_ACTIVITY1_FLAG | - USDHC_ADMA2_ACTIVITY2_FLAG | - USDHC_ADMA2_VALID_FLAG), - /* Link type - */ -}; - -struct usdhc_adma2_descriptor { - uint32_t attribute; - /*!< The control and status field */ - const uint32_t *address; - /*!< The address field */ -}; - -enum usdhc_card_flag { - USDHC_HIGH_CAPACITY_FLAG = - (1U << 1U), - /* Support high capacity - */ - USDHC_4BIT_WIDTH_FLAG = - (1U << 2U), - /* Support 4-bit data width - */ - USDHC_SDHC_FLAG = - (1U << 3U), - /* Card is SDHC - */ - USDHC_SDXC_FLAG = - (1U << 4U), - /* Card is SDXC - */ - USDHC_VOL_1_8V_FLAG = - (1U << 5U), - /* card support 1.8v voltage - */ - USDHC_SET_BLK_CNT_CMD23_FLAG = - (1U << 6U), - /* card support cmd23 flag - */ - USDHC_SPEED_CLASS_CONTROL_CMD_FLAG = - (1U << 7U), - /* card support speed class control flag - */ -}; - -enum usdhc_capability_flag { - USDHC_SUPPORT_ADMA_FLAG = - USDHC_HOST_CTRL_CAP_ADMAS_MASK, - /*!< Support ADMA */ - USDHC_SUPPORT_HIGHSPEED_FLAG = - USDHC_HOST_CTRL_CAP_HSS_MASK, - /*!< Support high-speed */ - USDHC_SUPPORT_DMA_FLAG = - USDHC_HOST_CTRL_CAP_DMAS_MASK, - /*!< Support DMA */ - USDHC_SUPPORT_SUSPEND_RESUME_FLAG = - USDHC_HOST_CTRL_CAP_SRS_MASK, - /*!< Support suspend/resume */ - USDHC_SUPPORT_V330_FLAG = - USDHC_HOST_CTRL_CAP_VS33_MASK, - /*!< Support voltage 3.3V */ - USDHC_SUPPORT_V300_FLAG = - USDHC_HOST_CTRL_CAP_VS30_MASK, - /*!< Support voltage 3.0V */ - USDHC_SUPPORT_V180_FLAG = - USDHC_HOST_CTRL_CAP_VS18_MASK, - /*!< Support voltage 1.8V */ - /* Put additional two flags in - * HTCAPBLT_MBL's position. - */ - USDHC_SUPPORT_4BIT_FLAG = - (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0U), - /*!< Support 4 bit mode */ - USDHC_SUPPORT_8BIT_FLAG = - (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1U), - /*!< Support 8 bit mode */ - /* sd version 3.0 new feature */ - USDHC_SUPPORT_DDR50_FLAG = - USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK, - /*!< support DDR50 mode */ - -#if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) &&\ - (!FSL_FEATURE_USDHC_HAS_SDR104_MODE) - USDHC_SUPPORT_SDR104_FLAG = 0, - /*!< not support SDR104 mode */ -#else - USDHC_SUPPORT_SDR104_FLAG = - USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK, - /*!< support SDR104 mode */ -#endif -#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) &&\ - (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) - USDHC_SUPPORT_SDR50_FLAG = 0U, - /*!< not support SDR50 mode */ -#else - USDHC_SUPPORT_SDR50_FLAG = - USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK, - /*!< support SDR50 mode */ -#endif -}; - -#define NXP_SDMMC_MAX_VOLTAGE_RETRIES (1000U) - -#define CARD_DATA0_STATUS_MASK USDHC_DATA0_LINE_LEVEL_FLAG -#define CARD_DATA1_STATUS_MASK USDHC_DATA1_LINE_LEVEL_FLAG -#define CARD_DATA2_STATUS_MASK USDHC_DATA2_LINE_LEVEL_FLAG -#define CARD_DATA3_STATUS_MASK USDHC_DATA3_LINE_LEVEL_FLAG -#define CARD_DATA0_NOT_BUSY USDHC_DATA0_LINE_LEVEL_FLAG - -#define SDHC_STANDARD_TUNING_START (10U) -/*!< standard tuning start point */ -#define SDHC_TUINIG_STEP (2U) -/*!< standard tuning step */ -#define SDHC_RETUNING_TIMER_COUNT (0U) -/*!< Re-tuning timer */ - -#define USDHC_MAX_DVS \ - ((USDHC_SYS_CTRL_DVS_MASK >> \ - USDHC_SYS_CTRL_DVS_SHIFT) + 1U) -#define USDHC_MAX_CLKFS \ - ((USDHC_SYS_CTRL_SDCLKFS_MASK >> \ - USDHC_SYS_CTRL_SDCLKFS_SHIFT) + 1U) -#define USDHC_PREV_DVS(x) ((x) -= 1U) -#define USDHC_PREV_CLKFS(x, y) ((x) >>= (y)) - -#define SDMMCHOST_SUPPORT_SDR104_FREQ SD_CLOCK_208MHZ - -#define USDHC_ADMA_TABLE_WORDS (8U) -#define USDHC_ADMA2_ADDR_ALIGN (4U) -#define USDHC_READ_BURST_LEN (8U) -#define USDHC_WRITE_BURST_LEN (8U) -#define USDHC_DATA_TIMEOUT (0xFU) - -#define USDHC_READ_WATERMARK_LEVEL (0x80U) -#define USDHC_WRITE_WATERMARK_LEVEL (0x80U) - -enum usdhc_reset { - USDHC_RESET_ALL = - USDHC_SYS_CTRL_RSTA_MASK, - /*!< Reset all except card detection */ - USDHC_RESET_CMD = - USDHC_SYS_CTRL_RSTC_MASK, - /*!< Reset command line */ - USDHC_RESET_DATA = - USDHC_SYS_CTRL_RSTD_MASK, - /*!< Reset data line */ - -#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) &&\ - (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) - USDHC_RESET_TUNING = 0U, - /*!< no reset tuning circuit bit */ -#else - USDHC_RESET_TUNING = USDHC_SYS_CTRL_RSTT_MASK, - /*!< reset tuning circuit */ -#endif - - USDHC_RESETS_All = - (USDHC_RESET_ALL | - USDHC_RESET_CMD | - USDHC_RESET_DATA | - USDHC_RESET_TUNING), - /*!< All reset types */ -}; - -static void usdhc_millsec_delay(unsigned int cycles_to_wait) -{ - unsigned int start = sys_clock_cycle_get_32(); - - while (sys_clock_cycle_get_32() - start < (cycles_to_wait * 1000)) - ; -} - -uint32_t g_usdhc_boot_dummy __aligned(64); -uint32_t g_usdhc_rx_dummy[2048] __aligned(64); - -static int usdhc_adma2_descriptor_cfg( - uint32_t *adma_table, uint32_t adma_table_words, - const uint32_t *data_addr, uint32_t data_size, uint32_t flags) -{ - uint32_t min_entries, start_entry = 0U; - uint32_t max_entries = (adma_table_words * sizeof(uint32_t)) / - sizeof(struct usdhc_adma2_descriptor); - struct usdhc_adma2_descriptor *adma2_addr = - (struct usdhc_adma2_descriptor *)(adma_table); - uint32_t i, dma_buf_len = 0U; - - if ((uint32_t)data_addr % USDHC_ADMA2_ADDRESS_ALIGN) { - return -EIO; - } - /* Add non aligned access support. - */ - if (data_size % sizeof(uint32_t)) { - /* make the data length as word-aligned */ - data_size += sizeof(uint32_t) - (data_size % sizeof(uint32_t)); - } - - /* Check if ADMA descriptor's number is enough. */ - if (!(data_size % USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)) { - min_entries = data_size / - USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY; - } else { - min_entries = ((data_size / - USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U); - } - /* calculate the start entry for multiple descriptor mode, - * ADMA engine is not stop, so update the descriptor - * data address and data size is enough - */ - if (flags == USDHC_ADMA_MUTI_FLAG) { - for (i = 0U; i < max_entries; i++) { - if (!(adma2_addr[i].attribute & USDHC_ADMA2_VALID_FLAG)) - break; - } - start_entry = i; - /* add one entry for dummy entry */ - min_entries += 1U; - } - - if ((min_entries + start_entry) > max_entries) { - return -EIO; - } - - for (i = start_entry; i < (min_entries + start_entry); i++) { - if (data_size > USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) { - dma_buf_len = - USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY; - } else { - dma_buf_len = (data_size == 0U ? sizeof(uint32_t) : - data_size); - /* adma don't support 0 data length transfer - * descriptor - */ - } - - /* Each descriptor for ADMA2 is 64-bit in length */ - adma2_addr[i].address = (data_size == 0U) ? - &g_usdhc_boot_dummy : data_addr; - adma2_addr[i].attribute = (dma_buf_len << - USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT); - adma2_addr[i].attribute |= - (data_size == 0U) ? 0U : - (USDHC_ADMA2_XFER_FLAG | USDHC_ADMA2_INT_FLAG); - data_addr += (dma_buf_len / sizeof(uint32_t)); - - if (data_size != 0U) - data_size -= dma_buf_len; - } - - /* add a dummy valid ADMA descriptor for multiple descriptor mode, - * this is useful when transfer boot data, the ADMA - * engine will not stop at block gap - */ - if (flags == USDHC_ADMA_MUTI_FLAG) { - adma2_addr[start_entry + 1U].attribute |= USDHC_ADMA2_XFER_FLAG; - } else { - adma2_addr[i - 1U].attribute |= USDHC_ADMA2_END_FLAG; - /* set the end bit */ - } - - return 0; -} - -static int usdhc_Internal_dma_cfg(struct usdhc_priv *priv, - struct usdhc_adma_config *dma_cfg, - const uint32_t *data_addr) -{ - USDHC_Type *base = priv->config->base; - bool cmd23 = priv->op_context.data.cmd23; - - if (dma_cfg->dma_mode == USDHC_DMA_SIMPLE) { - /* check DMA data buffer address align or not */ - if (((uint32_t)data_addr % USDHC_ADMA2_ADDRESS_ALIGN) != 0U) { - return -EIO; - } - /* in simple DMA mode if use auto CMD23, - * address should load to ADMA addr, - * and block count should load to DS_ADDR - */ - if (cmd23) - base->ADMA_SYS_ADDR = (uint32_t)data_addr; - else - base->DS_ADDR = (uint32_t)data_addr; - } else { - /* When use ADMA, disable simple DMA */ - base->DS_ADDR = 0U; - base->ADMA_SYS_ADDR = (uint32_t)(dma_cfg->adma_table); - } - -#if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) - /* select DMA mode */ - base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK); - base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dma_cfg->dma_mode); -#else - /* select DMA mode and config the burst length */ - base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK | - USDHC_PROT_CTRL_BURST_LEN_EN_MASK); - base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dma_cfg->dma_mode) | - USDHC_PROT_CTRL_BURST_LEN_EN(dma_cfg->burst_len); -#endif - /* enable DMA */ - base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK; - - return 0; -} - - -static int usdhc_adma_table_cfg(struct usdhc_priv *priv, uint32_t flags) -{ - int error = -EIO; - struct usdhc_data *data = &priv->op_context.data; - struct usdhc_adma_config *dma_cfg = &priv->op_context.dma_cfg; - uint32_t boot_dummy_off = data->data_type == USDHC_XFER_BOOT_CONTINUOUS ? - sizeof(uint32_t) : 0U; - const uint32_t *data_addr = (const uint32_t *)((uint32_t)((!data->rx_data) ? - data->tx_data : data->rx_data) + boot_dummy_off); - uint32_t data_size = data->block_size * data->block_count - boot_dummy_off; - - switch (dma_cfg->dma_mode) { - case USDHC_DMA_SIMPLE: - error = 0; - break; - - case USDHC_DMA_ADMA1: - error = -EINVAL; - break; - - case USDHC_DMA_ADMA2: - error = usdhc_adma2_descriptor_cfg(dma_cfg->adma_table, - dma_cfg->adma_table_words, data_addr, data_size, flags); - break; - default: - return -EINVAL; - } - - /* for internal dma, internal DMA configurations should not update - * the configurations when continuous transfer the - * boot data, only the DMA descriptor need update - */ - if ((!error) && (data->data_type != USDHC_XFER_BOOT_CONTINUOUS)) { - error = usdhc_Internal_dma_cfg(priv, dma_cfg, data_addr); - } - - return error; -} - -static int usdhc_data_xfer_cfg(struct usdhc_priv *priv, - bool en_dma) -{ - USDHC_Type *base = priv->config->base; - uint32_t mix_ctrl = base->MIX_CTRL; - struct usdhc_data *data = NULL; - uint32_t *flag = &priv->op_context.cmd.flags; - - if (!priv->op_context.cmd_only) - data = &priv->op_context.data; - - if (data != NULL) { - if (data->data_type == USDHC_XFER_BOOT_CONTINUOUS) { - /* clear stop at block gap request */ - base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK; - /* continuous transfer data */ - base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK; - return 0; - } - - /* check data inhibit flag */ - if (base->PRES_STATE & USDHC_DATA_INHIBIT_FLAG) - return -EBUSY; - /* check transfer block count */ - if ((data->block_count > USDHC_MAX_BLOCK_COUNT) || - (!data->tx_data && !data->rx_data)) - return -EINVAL; - - /* config mix parameter */ - mix_ctrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | - USDHC_MIX_CTRL_BCEN_MASK | - USDHC_MIX_CTRL_DTDSEL_MASK | - USDHC_MIX_CTRL_AC12EN_MASK); - - if (data->rx_data) { - mix_ctrl |= USDHC_MIX_CTRL_DTDSEL_MASK; - } - - if (data->block_count > 1U) { - mix_ctrl |= USDHC_MIX_CTRL_MSBSEL_MASK | - USDHC_MIX_CTRL_BCEN_MASK; - /* auto command 12 */ - if (data->cmd12) { - mix_ctrl |= USDHC_MIX_CTRL_AC12EN_MASK; - } - } - - /* auto command 23, auto send set block count cmd before - * multiple read/write - */ - if ((data->cmd23)) { - mix_ctrl |= USDHC_MIX_CTRL_AC23EN_MASK; - base->VEND_SPEC2 |= - USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK; - /* config the block count to DS_ADDR */ - base->DS_ADDR = data->block_count; - } else { - mix_ctrl &= ~USDHC_MIX_CTRL_AC23EN_MASK; - base->VEND_SPEC2 &= - (~USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK); - } - - if (data->data_type != USDHC_XFER_BOOT) { - /* config data block size/block count */ - base->BLK_ATT = - ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | - USDHC_BLK_ATT_BLKCNT_MASK)) | - (USDHC_BLK_ATT_BLKSIZE(data->block_size) | - USDHC_BLK_ATT_BLKCNT(data->block_count))); - } else { - mix_ctrl |= USDHC_MIX_CTRL_MSBSEL_MASK | - USDHC_MIX_CTRL_BCEN_MASK; - base->PROT_CTRL |= - USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK; - } - - /* data present flag */ - *flag |= USDHC_DATA_PRESENT_FLAG; - /* Disable useless interrupt */ - if (en_dma) { - base->INT_SIGNAL_EN &= - ~(USDHC_INT_BUF_WRITE_READY_FLAG | - USDHC_INT_BUF_READ_READY_FLAG | - USDHC_INT_DMA_DONE_FLAG); - base->INT_STATUS_EN &= - ~(USDHC_INT_BUF_WRITE_READY_FLAG | - USDHC_INT_BUF_READ_READY_FLAG | - USDHC_INT_DMA_DONE_FLAG); - } else { - base->INT_SIGNAL_EN |= - USDHC_INT_BUF_WRITE_READY_FLAG | - USDHC_INT_BUF_READ_READY_FLAG; - base->INT_STATUS_EN |= - USDHC_INT_BUF_WRITE_READY_FLAG | - USDHC_INT_BUF_READ_READY_FLAG; - } - } else { - /* clear data flags */ - mix_ctrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | - USDHC_MIX_CTRL_BCEN_MASK | - USDHC_MIX_CTRL_DTDSEL_MASK | - USDHC_MIX_CTRL_AC12EN_MASK | - USDHC_MIX_CTRL_AC23EN_MASK); - - if (base->PRES_STATE & USDHC_CMD_INHIBIT_FLAG) - return -EBUSY; - } - - /* config the mix parameter */ - base->MIX_CTRL = mix_ctrl; - - return 0; -} - -static void usdhc_send_cmd(USDHC_Type *base, struct usdhc_cmd *command) -{ - uint32_t xfer_type = base->CMD_XFR_TYP; - uint32_t flags = command->flags; - - if (!(base->PRES_STATE & USDHC_CMD_INHIBIT_FLAG) - && (command->cmd_type != USDHC_CMD_TYPE_EMPTY)) { - /* Define the flag corresponding to each response type. */ - switch (command->rsp_type) { - case SDHC_RSP_TYPE_NONE: - break; - case SDHC_RSP_TYPE_R1: /* Response 1 */ - case SDHC_RSP_TYPE_R5: /* Response 5 */ - case SDHC_RSP_TYPE_R6: /* Response 6 */ - case SDHC_RSP_TYPE_R7: /* Response 7 */ - flags |= (USDHC_RSP_LEN_48_FLAG | - USDHC_CRC_CHECK_FLAG | - USDHC_IDX_CHECK_FLAG); - break; - - case SDHC_RSP_TYPE_R1b: /* Response 1 with busy */ - case SDHC_RSP_TYPE_R5b: /* Response 5 with busy */ - flags |= (USDHC_RSP_LEN_48_BUSY_FLAG | - USDHC_CRC_CHECK_FLAG | - USDHC_IDX_CHECK_FLAG); - break; - - case SDHC_RSP_TYPE_R2: /* Response 2 */ - flags |= (USDHC_RSP_LEN_136_FLAG | - USDHC_CRC_CHECK_FLAG); - break; - - case SDHC_RSP_TYPE_R3: /* Response 3 */ - case SDHC_RSP_TYPE_R4: /* Response 4 */ - flags |= (USDHC_RSP_LEN_48_FLAG); - break; - - default: - break; - } - - if (command->cmd_type == USDHC_CMD_TYPE_ABORT) - flags |= USDHC_CMD_TYPE_ABORT_FLAG; - - /* config cmd index */ - xfer_type &= ~(USDHC_CMD_XFR_TYP_CMDINX_MASK | - USDHC_CMD_XFR_TYP_CMDTYP_MASK | - USDHC_CMD_XFR_TYP_CICEN_MASK | - USDHC_CMD_XFR_TYP_CCCEN_MASK | - USDHC_CMD_XFR_TYP_RSPTYP_MASK | - USDHC_CMD_XFR_TYP_DPSEL_MASK); - - xfer_type |= - (((command->index << USDHC_CMD_XFR_TYP_CMDINX_SHIFT) & - USDHC_CMD_XFR_TYP_CMDINX_MASK) | - ((flags) & (USDHC_CMD_XFR_TYP_CMDTYP_MASK | - USDHC_CMD_XFR_TYP_CICEN_MASK | - USDHC_CMD_XFR_TYP_CCCEN_MASK | - USDHC_CMD_XFR_TYP_RSPTYP_MASK | - USDHC_CMD_XFR_TYP_DPSEL_MASK))); - - /* config the command xfertype and argument */ - base->CMD_ARG = command->argument; - base->CMD_XFR_TYP = xfer_type; - } - - if (command->cmd_type == USDHC_CMD_TYPE_EMPTY) { - /* disable CMD done interrupt for empty command */ - base->INT_SIGNAL_EN &= ~USDHC_INT_SIGNAL_EN_CCIEN_MASK; - } -} - -static int usdhc_cmd_rsp(struct usdhc_priv *priv) -{ - uint32_t i; - USDHC_Type *base = priv->config->base; - struct usdhc_cmd *cmd = &priv->op_context.cmd; - - if (cmd->rsp_type != SDHC_RSP_TYPE_NONE) { - cmd->response[0U] = base->CMD_RSP0; - if (cmd->rsp_type == SDHC_RSP_TYPE_R2) { - cmd->response[1U] = base->CMD_RSP1; - cmd->response[2U] = base->CMD_RSP2; - cmd->response[3U] = base->CMD_RSP3; - - i = 4U; - /* R3-R2-R1-R0(lowest 8 bit is invalid bit) - * has the same format - * as R2 format in SD specification document - * after removed internal CRC7 and end bit. - */ - do { - cmd->response[i - 1U] <<= 8U; - if (i > 1U) { - cmd->response[i - 1U] |= - ((cmd->response[i - 2U] & - 0xFF000000U) >> 24U); - } - i--; - } while (i); - } - } - /* check response error flag */ - if ((cmd->rsp_err_flags) && - ((cmd->rsp_type == SDHC_RSP_TYPE_R1) || - (cmd->rsp_type == SDHC_RSP_TYPE_R1b) || - (cmd->rsp_type == SDHC_RSP_TYPE_R6) || - (cmd->rsp_type == SDHC_RSP_TYPE_R5))) { - if (((cmd->rsp_err_flags) & (cmd->response[0U]))) - return -EIO; - } - - return 0; -} - -static int usdhc_wait_cmd_done(struct usdhc_priv *priv, - bool poll_cmd) -{ - int error = 0; - uint32_t int_status = 0U; - USDHC_Type *base = priv->config->base; - - /* check if need polling command done or not */ - if (poll_cmd) { - /* Wait command complete or USDHC encounters error. */ - while (!(int_status & (USDHC_INT_CMD_DONE_FLAG | - USDHC_INT_CMD_ERR_FLAG))) { - int_status = base->INT_STATUS; - } - - if ((int_status & USDHC_INT_TUNING_ERR_FLAG) || - (int_status & USDHC_INT_CMD_ERR_FLAG)) { - error = -EIO; - } - /* Receive response when command completes successfully. */ - if (!error) { - error = usdhc_cmd_rsp(priv); - } else { - LOG_ERR("CMD%d Polling ERROR", - priv->op_context.cmd.index); - } - - base->INT_STATUS = (USDHC_INT_CMD_DONE_FLAG | - USDHC_INT_CMD_ERR_FLAG | - USDHC_INT_TUNING_ERR_FLAG); - } - - return error; -} - -static inline void usdhc_write_data(USDHC_Type *base, uint32_t data) -{ - base->DATA_BUFF_ACC_PORT = data; -} - -static inline uint32_t usdhc_read_data(USDHC_Type *base) -{ - return base->DATA_BUFF_ACC_PORT; -} - -static uint32_t usdhc_read_data_port(struct usdhc_priv *priv, - uint32_t xfered_words) -{ - USDHC_Type *base = priv->config->base; - struct usdhc_data *data = &priv->op_context.data; - uint32_t i, total_words, remaing_words; - /* The words can be read at this time. */ - uint32_t watermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_RD_WML_MASK) >> - USDHC_WTMK_LVL_RD_WML_SHIFT); - - /* If DMA is enable, do not need to polling data port */ - if (!(base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK)) { - /*Add non aligned access support.*/ - if (data->block_size % sizeof(uint32_t)) { - data->block_size += - sizeof(uint32_t) - - (data->block_size % sizeof(uint32_t)); - /* make the block size as word-aligned */ - } - - total_words = ((data->block_count * data->block_size) / - sizeof(uint32_t)); - - if (watermark >= total_words) { - remaing_words = total_words; - } else if ((watermark < total_words) && - ((total_words - xfered_words) >= watermark)) { - remaing_words = watermark; - } else { - remaing_words = (total_words - xfered_words); - } - - i = 0U; - while (i < remaing_words) { - data->rx_data[xfered_words++] = usdhc_read_data(base); - i++; - } - } - - return xfered_words; -} - -static int usdhc_read_data_port_sync(struct usdhc_priv *priv) -{ - USDHC_Type *base = priv->config->base; - struct usdhc_data *data = &priv->op_context.data; - uint32_t total_words; - uint32_t xfered_words = 0U, int_status = 0U; - int error = 0; - - if (data->block_size % sizeof(uint32_t)) { - data->block_size += - sizeof(uint32_t) - - (data->block_size % sizeof(uint32_t)); - } - - total_words = - ((data->block_count * data->block_size) / - sizeof(uint32_t)); - - while ((!error) && (xfered_words < total_words)) { - while (!(int_status & (USDHC_INT_BUF_READ_READY_FLAG | - USDHC_INT_DATA_ERR_FLAG | - USDHC_INT_TUNING_ERR_FLAG))) - int_status = base->INT_STATUS; - - /* during std tuning process, software do not need to read data, - * but wait BRR is enough - */ - if ((data->data_type == USDHC_XFER_TUNING) && - (int_status & USDHC_INT_BUF_READ_READY_FLAG)) { - base->INT_STATUS = USDHC_INT_BUF_READ_READY_FLAG | - USDHC_INT_TUNING_PASS_FLAG; - - return 0; - } else if ((int_status & USDHC_INT_TUNING_ERR_FLAG)) { - base->INT_STATUS = USDHC_INT_TUNING_ERR_FLAG; - /* if tuning error occur ,return directly */ - error = -EIO; - } else if ((int_status & USDHC_INT_DATA_ERR_FLAG)) { - if (!(data->ignore_err)) - error = -EIO; - /* clear data error flag */ - base->INT_STATUS = USDHC_INT_DATA_ERR_FLAG; - } - - if (!error) { - xfered_words = usdhc_read_data_port(priv, xfered_words); - /* clear buffer read ready */ - base->INT_STATUS = USDHC_INT_BUF_READ_READY_FLAG; - int_status = 0U; - } - } - - /* Clear data complete flag after the last read operation. */ - base->INT_STATUS = USDHC_INT_DATA_DONE_FLAG; - - return error; -} - -static uint32_t usdhc_write_data_port(struct usdhc_priv *priv, - uint32_t xfered_words) -{ - USDHC_Type *base = priv->config->base; - struct usdhc_data *data = &priv->op_context.data; - uint32_t i, total_words, remaing_words; - /* Words can be wrote at this time. */ - uint32_t watermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_WR_WML_MASK) >> - USDHC_WTMK_LVL_WR_WML_SHIFT); - - /* If DMA is enable, do not need to polling data port */ - if (!(base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK)) { - if (data->block_size % sizeof(uint32_t)) { - data->block_size += - sizeof(uint32_t) - - (data->block_size % sizeof(uint32_t)); - } - - total_words = - ((data->block_count * data->block_size) / - sizeof(uint32_t)); - - if (watermark >= total_words) { - remaing_words = total_words; - } else if ((watermark < total_words) && - ((total_words - xfered_words) >= watermark)) { - remaing_words = watermark; - } else { - remaing_words = (total_words - xfered_words); - } - - i = 0U; - while (i < remaing_words) { - usdhc_write_data(base, data->tx_data[xfered_words++]); - i++; - } - } - - return xfered_words; -} - -static status_t usdhc_write_data_port_sync(struct usdhc_priv *priv) -{ - USDHC_Type *base = priv->config->base; - struct usdhc_data *data = &priv->op_context.data; - uint32_t total_words; - uint32_t xfered_words = 0U, int_status = 0U; - int error = 0; - - if (data->block_size % sizeof(uint32_t)) { - data->block_size += - sizeof(uint32_t) - (data->block_size % sizeof(uint32_t)); - } - - total_words = (data->block_count * data->block_size) / sizeof(uint32_t); - - while ((!error) && (xfered_words < total_words)) { - while (!(int_status & (USDHC_INT_BUF_WRITE_READY_FLAG | - USDHC_INT_DATA_ERR_FLAG | - USDHC_INT_TUNING_ERR_FLAG))) { - int_status = base->INT_STATUS; - } - - if (int_status & USDHC_INT_TUNING_ERR_FLAG) { - base->INT_STATUS = USDHC_INT_TUNING_ERR_FLAG; - /* if tuning error occur ,return directly */ - return -EIO; - } else if (int_status & USDHC_INT_DATA_ERR_FLAG) { - if (!(data->ignore_err)) - error = -EIO; - /* clear data error flag */ - base->INT_STATUS = USDHC_INT_DATA_ERR_FLAG; - } - - if (!error) { - xfered_words = usdhc_write_data_port(priv, - xfered_words); - /* clear buffer write ready */ - base->INT_STATUS = USDHC_INT_BUF_WRITE_READY_FLAG; - int_status = 0U; - } - } - - /* Wait write data complete or data transfer error - * after the last writing operation. - */ - while (!(int_status & (USDHC_INT_DATA_DONE_FLAG | - USDHC_INT_DATA_ERR_FLAG))) { - int_status = base->INT_STATUS; - } - - if (int_status & USDHC_INT_DATA_ERR_FLAG) { - if (!(data->ignore_err)) - error = -EIO; - } - base->INT_STATUS = USDHC_INT_DATA_DONE_FLAG | - USDHC_INT_DATA_ERR_FLAG; - - return error; -} - -static int usdhc_data_sync_xfer(struct usdhc_priv *priv, bool en_dma) -{ - int error = 0; - uint32_t int_status = 0U; - USDHC_Type *base = priv->config->base; - struct usdhc_data *data = &priv->op_context.data; - - if (en_dma) { - /* Wait data complete or USDHC encounters error. */ - while (!((int_status & - (USDHC_INT_DATA_DONE_FLAG | USDHC_INT_DATA_ERR_FLAG | - USDHC_INT_CMD_ERR_FLAG | USDHC_INT_TUNING_ERR_FLAG)))) { - int_status = base->INT_STATUS; - } - - if (int_status & USDHC_INT_TUNING_ERR_FLAG) { - error = -EIO; - } else if ((int_status & (USDHC_INT_DATA_ERR_FLAG | - USDHC_INT_DMA_ERR_FLAG))) { - if ((!(data->ignore_err)) || - (int_status & - USDHC_INT_DATA_TIMEOUT_FLAG)) { - error = -EIO; - } - } - /* load dummy data */ - if ((data->data_type == USDHC_XFER_BOOT_CONTINUOUS) && (!error)) - *(data->rx_data) = g_usdhc_boot_dummy; - - base->INT_STATUS = (USDHC_INT_DATA_DONE_FLAG | - USDHC_INT_DATA_ERR_FLAG | - USDHC_INT_DMA_ERR_FLAG | - USDHC_INT_TUNING_PASS_FLAG | - USDHC_INT_TUNING_ERR_FLAG); - } else { - if (data->rx_data) { - error = usdhc_read_data_port_sync(priv); - } else { - error = usdhc_write_data_port_sync(priv); - } - } - return error; -} - -static int usdhc_xfer(struct usdhc_priv *priv) -{ - int error = -EIO; - struct usdhc_data *data = NULL; - bool en_dma = true, execute_tuning; - USDHC_Type *base = priv->config->base; - - if (!priv->op_context.cmd_only) { - data = &priv->op_context.data; - if (data->data_type == USDHC_XFER_TUNING) - execute_tuning = true; - else - execute_tuning = false; - } else { - execute_tuning = false; - } - - /*check re-tuning request*/ - if ((base->INT_STATUS & USDHC_INT_RE_TUNING_EVENT_FLAG)) { - base->INT_STATUS = USDHC_INT_RE_TUNING_EVENT_FLAG; - return -EAGAIN; - } - - /* Update ADMA descriptor table according to different DMA mode - * (no DMA, ADMA1, ADMA2). - */ - - if (data && (!execute_tuning) && priv->op_context.dma_cfg.adma_table) - error = usdhc_adma_table_cfg(priv, - (data->data_type & USDHC_XFER_BOOT) ? - USDHC_ADMA_MUTI_FLAG : USDHC_ADMA_SINGLE_FLAG); - - /* if the DMA descriptor configure fail or not needed , disable it */ - if (error) { - en_dma = false; - /* disable DMA, using polling mode in this situation */ - base->MIX_CTRL &= ~USDHC_MIX_CTRL_DMAEN_MASK; - base->PROT_CTRL &= ~USDHC_PROT_CTRL_DMASEL_MASK; - } - - /* config the data transfer parameter */ - error = usdhc_data_xfer_cfg(priv, en_dma); - if (error) - return error; - /* send command first */ - usdhc_send_cmd(base, &priv->op_context.cmd); - /* wait command done */ - error = usdhc_wait_cmd_done(priv, (data == NULL) || - (data->data_type == USDHC_XFER_NORMAL)); - /* wait transfer data finish */ - if (data && (!error)) { - return usdhc_data_sync_xfer(priv, en_dma); - } - - return error; -} - -static inline void usdhc_select_1_8_vol(USDHC_Type *base, bool en_1_8_v) -{ - if (en_1_8_v) - base->VEND_SPEC |= USDHC_VEND_SPEC_VSELECT_MASK; - else - base->VEND_SPEC &= ~USDHC_VEND_SPEC_VSELECT_MASK; -} - -static inline void usdhc_force_clk_on(USDHC_Type *base, bool on) -{ - if (on) - base->VEND_SPEC |= USDHC_VEND_SPEC_FRC_SDCLK_ON_MASK; - else - base->VEND_SPEC &= ~USDHC_VEND_SPEC_FRC_SDCLK_ON_MASK; -} - -static void usdhc_tuning(USDHC_Type *base, uint32_t start, uint32_t step, bool enable) -{ - uint32_t tuning_ctrl = 0U; - - if (enable) { - /* feedback clock */ - base->MIX_CTRL |= USDHC_MIX_CTRL_FBCLK_SEL_MASK; - /* config tuning start and step */ - tuning_ctrl = base->TUNING_CTRL; - tuning_ctrl &= ~(USDHC_TUNING_CTRL_TUNING_START_TAP_MASK | - USDHC_TUNING_CTRL_TUNING_STEP_MASK); - tuning_ctrl |= (USDHC_TUNING_CTRL_TUNING_START_TAP(start) | - USDHC_TUNING_CTRL_TUNING_STEP(step) | - USDHC_TUNING_CTRL_STD_TUNING_EN_MASK); - base->TUNING_CTRL = tuning_ctrl; - - /* excute tuning */ - base->AUTOCMD12_ERR_STATUS |= - (USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | - USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK); - } else { - /* disable the standard tuning */ - base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK; - /* clear excute tuning */ - base->AUTOCMD12_ERR_STATUS &= - ~(USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | - USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK); - } -} - -int usdhc_adjust_tuning_timing(USDHC_Type *base, uint32_t delay) -{ - uint32_t clk_tune_ctrl = 0U; - - clk_tune_ctrl = base->CLK_TUNE_CTRL_STATUS; - - clk_tune_ctrl &= ~USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK; - - clk_tune_ctrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(delay); - - /* load the delay setting */ - base->CLK_TUNE_CTRL_STATUS = clk_tune_ctrl; - /* check delay setting error */ - if (base->CLK_TUNE_CTRL_STATUS & - (USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | - USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK)) - return -EIO; - - return 0; -} - -static inline void usdhc_set_bus_width(USDHC_Type *base, - enum usdhc_data_bus_width width) -{ - base->PROT_CTRL = ((base->PROT_CTRL & ~USDHC_PROT_CTRL_DTW_MASK) | - USDHC_PROT_CTRL_DTW(width)); -} - -static int usdhc_execute_tuning(struct usdhc_priv *priv) -{ - bool tuning_err = true; - int ret; - USDHC_Type *base = priv->config->base; - - /* enable the standard tuning */ - usdhc_tuning(base, SDHC_STANDARD_TUNING_START, SDHC_TUINIG_STEP, true); - - while (true) { - /* send tuning block */ - ret = usdhc_xfer(priv); - if (ret) { - return ret; - } - usdhc_millsec_delay(10); - - /*wait excute tuning bit clear*/ - if ((base->AUTOCMD12_ERR_STATUS & - USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK)) { - continue; - } - - /* if tuning error , re-tuning again */ - if ((base->CLK_TUNE_CTRL_STATUS & - (USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK | - USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK)) && - tuning_err) { - tuning_err = false; - /* enable the standard tuning */ - usdhc_tuning(base, SDHC_STANDARD_TUNING_START, - SDHC_TUINIG_STEP, true); - usdhc_adjust_tuning_timing(base, - SDHC_STANDARD_TUNING_START); - } else { - break; - } - } - - /* delay to wait the host controller stable */ - usdhc_millsec_delay(1000); - - /* check tuning result*/ - if (!(base->AUTOCMD12_ERR_STATUS & - USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK)) { - return -EIO; - } - - /* Enable auto retuning */ - base->MIX_CTRL |= USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK; - - return 0; -} - -static int usdhc_vol_switch(struct usdhc_priv *priv) -{ - USDHC_Type *base = priv->config->base; - int retry = 0xffff; - - while (base->PRES_STATE & - (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | - CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY)) { - retry--; - if (retry <= 0) { - return -EACCES; - } - } - - /* host switch to 1.8V */ - usdhc_select_1_8_vol(base, true); - - usdhc_millsec_delay(20000U); - - /*enable force clock on*/ - usdhc_force_clk_on(base, true); - /* delay 1ms,not exactly correct when use while */ - usdhc_millsec_delay(20000U); - /*disable force clock on*/ - usdhc_force_clk_on(base, false); - - /* check data line and cmd line status */ - retry = 0xffff; - while (!(base->PRES_STATE & - (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | - CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY))) { - retry--; - if (retry <= 0) { - return -EBUSY; - } - } - - return 0; -} - -static inline void usdhc_op_ctx_init(struct usdhc_priv *priv, - bool cmd_only, uint8_t cmd_idx, uint32_t arg, enum sdhc_rsp_type rsp_type) -{ - struct usdhc_cmd *cmd = &priv->op_context.cmd; - struct usdhc_data *data = &priv->op_context.data; - - priv->op_context.cmd_only = cmd_only; - - memset((char *)cmd, 0, sizeof(struct usdhc_cmd)); - memset((char *)data, 0, sizeof(struct usdhc_data)); - - cmd->index = cmd_idx; - cmd->argument = arg; - cmd->rsp_type = rsp_type; -} - -static int usdhc_select_fun(struct usdhc_priv *priv, - uint32_t group, uint32_t function) -{ - const struct usdhc_config *config = priv->config; - uint32_t *fun_status; - uint16_t fun_grp_info[6U] = {0}; - uint32_t current_fun_status = 0U, arg; - struct usdhc_cmd *cmd = &priv->op_context.cmd; - struct usdhc_data *data = &priv->op_context.data; - int ret; - - /* check if card support CMD6 */ - if ((priv->card_info.version <= SD_SPEC_VER1_0) || - (!(priv->card_info.csd.cmd_class & SD_CMD_CLASS_SWITCH))) { - return -EINVAL; - } - - /* Check if card support high speed mode. */ - arg = (SD_SWITCH_CHECK << 31U | 0x00FFFFFFU); - arg &= ~((uint32_t)(0xFU) << (group * 4U)); - arg |= (function << (group * 4U)); - usdhc_op_ctx_init(priv, 0, SDHC_SWITCH, arg, SDHC_RSP_TYPE_R1); - - data->block_size = 64U; - data->block_count = 1U; - data->rx_data = &g_usdhc_rx_dummy[0]; - ret = usdhc_xfer(priv); - if (ret || (cmd->response[0U] & SDHC_R1ERR_All_FLAG)) - return -EIO; - - fun_status = data->rx_data; - - /* Switch function status byte sequence - * from card is big endian(MSB first). - */ - switch (config->endian) { - case USDHC_LITTLE_ENDIAN: - fun_status[0U] = SWAP_WORD_BYTE_SEQUENCE(fun_status[0U]); - fun_status[1U] = SWAP_WORD_BYTE_SEQUENCE(fun_status[1U]); - fun_status[2U] = SWAP_WORD_BYTE_SEQUENCE(fun_status[2U]); - fun_status[3U] = SWAP_WORD_BYTE_SEQUENCE(fun_status[3U]); - fun_status[4U] = SWAP_WORD_BYTE_SEQUENCE(fun_status[4U]); - break; - case USDHC_BIG_ENDIAN: - break; - case USDHC_HALF_WORD_BIG_ENDIAN: - fun_status[0U] = SWAP_HALF_WROD_BYTE_SEQUENCE(fun_status[0U]); - fun_status[1U] = SWAP_HALF_WROD_BYTE_SEQUENCE(fun_status[1U]); - fun_status[2U] = SWAP_HALF_WROD_BYTE_SEQUENCE(fun_status[2U]); - fun_status[3U] = SWAP_HALF_WROD_BYTE_SEQUENCE(fun_status[3U]); - fun_status[4U] = SWAP_HALF_WROD_BYTE_SEQUENCE(fun_status[4U]); - break; - default: - return -ENOTSUP; - } - - fun_grp_info[5U] = (uint16_t)fun_status[0U]; - fun_grp_info[4U] = (uint16_t)(fun_status[1U] >> 16U); - fun_grp_info[3U] = (uint16_t)(fun_status[1U]); - fun_grp_info[2U] = (uint16_t)(fun_status[2U] >> 16U); - fun_grp_info[1U] = (uint16_t)(fun_status[2U]); - fun_grp_info[0U] = (uint16_t)(fun_status[3U] >> 16U); - current_fun_status = ((fun_status[3U] & 0xFFU) << 8U) | - (fun_status[4U] >> 24U); - - /* check if function is support */ - if (((fun_grp_info[group] & (1 << function)) == 0U) || - ((current_fun_status >> - (group * 4U)) & 0xFU) != function) { - return -ENOTSUP; - } - - /* Switch to high speed mode. */ - usdhc_op_ctx_init(priv, 0, SDHC_SWITCH, arg, SDHC_RSP_TYPE_R1); - - data->block_size = 64U; - data->block_count = 1U; - data->rx_data = &g_usdhc_rx_dummy[0]; - - cmd->argument = (SD_SWITCH_SET << 31U | 0x00FFFFFFU); - cmd->argument &= ~((uint32_t)(0xFU) << (group * 4U)); - cmd->argument |= (function << (group * 4U)); - - ret = usdhc_xfer(priv); - if (ret || (cmd->response[0U] & SDHC_R1ERR_All_FLAG)) - return -EIO; - /* Switch function status byte sequence - * from card is big endian(MSB first). - */ - switch (config->endian) { - case USDHC_LITTLE_ENDIAN: - fun_status[3U] = SWAP_WORD_BYTE_SEQUENCE(fun_status[3U]); - fun_status[4U] = SWAP_WORD_BYTE_SEQUENCE(fun_status[4U]); - break; - case USDHC_BIG_ENDIAN: - break; - case USDHC_HALF_WORD_BIG_ENDIAN: - fun_status[3U] = SWAP_HALF_WROD_BYTE_SEQUENCE(fun_status[3U]); - fun_status[4U] = SWAP_HALF_WROD_BYTE_SEQUENCE(fun_status[4U]); - break; - default: - return -ENOTSUP; - } - /* According to the "switch function status[bits 511~0]" return - * by switch command in mode "set function": - * -check if group 1 is successfully changed to function 1 by checking - * if bits 379~376 equal value 1; - */ - current_fun_status = ((fun_status[3U] & 0xFFU) << 8U) | - (fun_status[4U] >> 24U); - - if (((current_fun_status >> - (group * 4U)) & 0xFU) != function) { - return -EINVAL; - } - - return 0; -} - -uint32_t usdhc_set_sd_clk(USDHC_Type *base, uint32_t src_clk_hz, uint32_t sd_clk_hz) -{ - uint32_t total_div = 0U; - uint32_t divisor = 0U; - uint32_t prescaler = 0U; - uint32_t sysctl = 0U; - uint32_t nearest_freq = 0U; - - - __ASSERT_NO_MSG(src_clk_hz != 0U); - __ASSERT_NO_MSG(sd_clk_hz != 0); - - if (sd_clk_hz > src_clk_hz) { - sd_clk_hz = src_clk_hz; - } - - /* calculate total divisor first */ - total_div = src_clk_hz / sd_clk_hz; - if (total_div > (USDHC_MAX_CLKFS * USDHC_MAX_DVS)) { - return 0U; - } - - if (total_div) { - /* calculate the divisor (src_clk_hz / divisor) <= sd_clk_hz */ - if ((src_clk_hz / total_div) > sd_clk_hz) - total_div++; - - /* divide the total divisor to div and prescaler */ - if (total_div > USDHC_MAX_DVS) { - prescaler = total_div / USDHC_MAX_DVS; - /* prescaler must be a value which equal 2^n and - * smaller than SDHC_MAX_CLKFS - */ - while (((USDHC_MAX_CLKFS % prescaler) != 0U) || - (prescaler == 1U)) - prescaler++; - /* calculate the divisor */ - divisor = total_div / prescaler; - /* fine tuning the divisor until - * divisor * prescaler >= total_div - */ - while ((divisor * prescaler) < total_div) { - divisor++; - if (divisor > USDHC_MAX_DVS) { - if ((prescaler <<= 1U) > - USDHC_MAX_CLKFS) { - return 0; - } - divisor = total_div / prescaler; - } - } - } else { - /* in this situation , divisor and SDCLKFS - * can generate same clock - * use SDCLKFS - */ - if (((total_div % 2U) != 0U) & (total_div != 1U)) { - divisor = total_div; - prescaler = 1U; - } else { - divisor = 1U; - prescaler = total_div; - } - } - nearest_freq = src_clk_hz / (divisor == 0U ? 1U : divisor) / - prescaler; - } else { - /* in this condition , src_clk_hz = busClock_Hz, */ - /* in DDR mode , set SDCLKFS to 0, divisor = 0, actually the - * total divider = 2U - */ - divisor = 0U; - prescaler = 0U; - nearest_freq = src_clk_hz; - } - - /* calculate the value write to register */ - if (divisor != 0U) { - USDHC_PREV_DVS(divisor); - } - /* calculate the value write to register */ - if (prescaler != 0U) { - USDHC_PREV_CLKFS(prescaler, 1U); - } - - /* Set the SD clock frequency divisor, SD clock frequency select, - * data timeout counter value. - */ - sysctl = base->SYS_CTRL; - sysctl &= ~(USDHC_SYS_CTRL_DVS_MASK | - USDHC_SYS_CTRL_SDCLKFS_MASK); - sysctl |= (USDHC_SYS_CTRL_DVS(divisor) | - USDHC_SYS_CTRL_SDCLKFS(prescaler)); - base->SYS_CTRL = sysctl; - - /* Wait until the SD clock is stable. */ - while (!(base->PRES_STATE & USDHC_PRES_STATE_SDSTB_MASK)) { - ; - } - - return nearest_freq; -} - -static void usdhc_enable_ddr_mode(USDHC_Type *base, - bool enable, uint32_t nibble_pos) -{ - uint32_t prescaler = (base->SYS_CTRL & USDHC_SYS_CTRL_SDCLKFS_MASK) >> - USDHC_SYS_CTRL_SDCLKFS_SHIFT; - - if (enable) { - base->MIX_CTRL &= ~USDHC_MIX_CTRL_NIBBLE_POS_MASK; - base->MIX_CTRL |= (USDHC_MIX_CTRL_DDR_EN_MASK | - USDHC_MIX_CTRL_NIBBLE_POS(nibble_pos)); - prescaler >>= 1U; - } else { - base->MIX_CTRL &= ~USDHC_MIX_CTRL_DDR_EN_MASK; - - if (prescaler == 0U) { - prescaler += 1U; - } else { - prescaler <<= 1U; - } - } - - base->SYS_CTRL = (base->SYS_CTRL & (~USDHC_SYS_CTRL_SDCLKFS_MASK)) | - USDHC_SYS_CTRL_SDCLKFS(prescaler); -} - -static int usdhc_select_bus_timing(struct usdhc_priv *priv) -{ - const struct usdhc_config *config = priv->config; - int error = -EIO; - - if (priv->card_info.voltage != SD_VOL_1_8_V) { - /* Switch the card to high speed mode */ - if (priv->host_capability.host_flags & - USDHC_SUPPORT_HIGHSPEED_FLAG) { - /* group 1, function 1 ->high speed mode*/ - error = usdhc_select_fun(priv, SD_GRP_TIMING_MODE, - SD_TIMING_SDR25_HIGH_SPEED_MODE); - /* If the result isn't "switching to - * high speed mode(50MHZ) - * successfully or card doesn't support - * high speed - * mode". Return failed status. - */ - if (!error) { - priv->card_info.sd_timing = - SD_TIMING_SDR25_HIGH_SPEED_MODE; - priv->card_info.busclk_hz = - usdhc_set_sd_clk(config->base, - priv->src_clk_hz, - SD_CLOCK_50MHZ); - } else if (error == -ENOTSUP) { - /* if not support high speed, - * keep the card work at default mode - */ - return 0; - } - } else { - /* if not support high speed, - * keep the card work at default mode - */ - return 0; - } - } else if ((USDHC_SUPPORT_SDR104_FLAG != - SDMMCHOST_NOT_SUPPORT) || - (USDHC_SUPPORT_SDR50_FLAG != SDMMCHOST_NOT_SUPPORT) || - (USDHC_SUPPORT_DDR50_FLAG != SDMMCHOST_NOT_SUPPORT)) { - /* card is in UHS_I mode */ - switch (priv->card_info.sd_timing) { - /* if not select timing mode, - * sdmmc will handle it automatically - */ - case SD_TIMING_SDR12_DFT_MODE: - case SD_TIMING_SDR104_MODE: - error = usdhc_select_fun(priv, SD_GRP_TIMING_MODE, - SD_TIMING_SDR104_MODE); - if (!error) { - priv->card_info.sd_timing = - SD_TIMING_SDR104_MODE; - priv->card_info.busclk_hz = - usdhc_set_sd_clk(config->base, - priv->src_clk_hz, - SDMMCHOST_SUPPORT_SDR104_FREQ); - break; - } - case SD_TIMING_DDR50_MODE: - error = usdhc_select_fun(priv, SD_GRP_TIMING_MODE, - SD_TIMING_DDR50_MODE); - if (!error) { - priv->card_info.sd_timing = - SD_TIMING_DDR50_MODE; - priv->card_info.busclk_hz = - usdhc_set_sd_clk( - config->base, - priv->src_clk_hz, - SD_CLOCK_50MHZ); - usdhc_enable_ddr_mode(config->base, true, 0U); - } - break; - case SD_TIMING_SDR50_MODE: - error = usdhc_select_fun(priv, - SD_GRP_TIMING_MODE, - SD_TIMING_SDR50_MODE); - if (!error) { - priv->card_info.sd_timing = - SD_TIMING_SDR50_MODE; - priv->card_info.busclk_hz = - usdhc_set_sd_clk( - config->base, - priv->src_clk_hz, - SD_CLOCK_100MHZ); - } - break; - case SD_TIMING_SDR25_HIGH_SPEED_MODE: - error = usdhc_select_fun(priv, SD_GRP_TIMING_MODE, - SD_TIMING_SDR25_HIGH_SPEED_MODE); - if (!error) { - priv->card_info.sd_timing = - SD_TIMING_SDR25_HIGH_SPEED_MODE; - priv->card_info.busclk_hz = - usdhc_set_sd_clk( - config->base, - priv->src_clk_hz, - SD_CLOCK_50MHZ); - } - break; - - default: - break; - } - } - - /* SDR50 and SDR104 mode need tuning */ - if ((priv->card_info.sd_timing == SD_TIMING_SDR50_MODE) || - (priv->card_info.sd_timing == SD_TIMING_SDR104_MODE)) { - struct usdhc_cmd *cmd = &priv->op_context.cmd; - struct usdhc_data *data = &priv->op_context.data; - - /* config IO strength in IOMUX*/ - if (priv->card_info.sd_timing == SD_TIMING_SDR50_MODE) { -#ifdef CONFIG_PINCTRL - pinctrl_apply_state(priv->config->pincfg, PINCTRL_STATE_MED); -#else - imxrt_usdhc_pinmux(config->nusdhc, false, - CARD_BUS_FREQ_100MHZ1, - CARD_BUS_STRENGTH_7); -#endif /* CONFIG_PINCTRL */ - } else { -#ifdef CONFIG_PINCTRL - pinctrl_apply_state(priv->config->pincfg, PINCTRL_STATE_FAST); -#else - imxrt_usdhc_pinmux(config->nusdhc, false, - CARD_BUS_FREQ_200MHZ, - CARD_BUS_STRENGTH_7); -#endif /* CONFIG_PINCTRL */ - } - /* execute tuning */ - priv->op_context.cmd_only = 0; - - memset((char *)cmd, 0, sizeof(struct usdhc_cmd)); - memset((char *)data, 0, sizeof(struct usdhc_data)); - - cmd->index = SDHC_SEND_TUNING_BLOCK; - cmd->rsp_type = SDHC_RSP_TYPE_R1; - - data->block_size = 64; - data->block_count = 1U; - data->rx_data = &g_usdhc_rx_dummy[0]; - data->data_type = USDHC_XFER_TUNING; - error = usdhc_execute_tuning(priv); - if (error) - return error; - } else { -#ifdef CONFIG_PINCTRL - pinctrl_apply_state(priv->config->pincfg, PINCTRL_STATE_SLOW); -#else - imxrt_usdhc_pinmux(config->nusdhc, false, - CARD_BUS_FREQ_100MHZ1, - CARD_BUS_STRENGTH_4); -#endif /* CONFIG_PINCTRL */ - } - - return error; -} - -static int usdhc_send_status(struct usdhc_priv *priv) -{ - int retry = 10, ret = -ETIMEDOUT; - struct usdhc_cmd *cmd = &priv->op_context.cmd; - - usdhc_op_ctx_init(priv, true, SDHC_SEND_STATUS, - priv->card_info.relative_addr << 16U, - SDHC_RSP_TYPE_R1); - while (retry--) { - ret = usdhc_xfer(priv); - if (ret) { - LOG_DBG("Send CMD13 failed with host error %d", ret); - continue; - } else { - if (((cmd->response[0U] & SDHC_R1READY_FOR_DATA) != 0U) && - (SD_R1_CURRENT_STATE(cmd->response[0U]) != SDMMC_R1_PROGRAM)) { - /* Card is idle */ - ret = 0; - } else { - ret = -EBUSY; - } - break; - } - } - return ret; -} - -static int usdhc_poll_card_status_busy(struct usdhc_priv *priv, - uint32_t timeout_ms) -{ - USDHC_Type *base = priv->config->base; - uint32_t timeout_us = timeout_ms * 1000; - int card_busy, ret = -ETIMEDOUT; - - while (timeout_us) { - /* Check card status */ - card_busy = (base->PRES_STATE & USDHC_DATA0_LINE_LEVEL_FLAG) != - USDHC_DATA0_LINE_LEVEL_FLAG; - if (!card_busy) { - /* Send status to SD card and return from wait */ - ret = usdhc_send_status(priv); - if (!ret) { - break; - } - } else { - /* Delay 125us to throttle the polling rate */ - k_busy_wait(125); - timeout_us -= 125; - } - } - return ret; -} - -static int usdhc_write_sector(void *bus_data, const uint8_t *buf, uint32_t sector, - uint32_t count) -{ - struct usdhc_priv *priv = bus_data; - struct usdhc_cmd *cmd = &priv->op_context.cmd; - struct usdhc_data *data = &priv->op_context.data; - - memset((char *)cmd, 0, sizeof(struct usdhc_cmd)); - memset((char *)data, 0, sizeof(struct usdhc_data)); - - if (sector + count > priv->card_info.sd_block_count) { - return -EIO; - } - - if (usdhc_poll_card_status_busy(priv, USDHC_WAIT_IDLE_TIMEOUT)) { - return -ETIMEDOUT; - } - - priv->op_context.cmd_only = 0; - cmd->index = SDHC_WRITE_MULTIPLE_BLOCK; - data->block_size = priv->card_info.sd_block_size; - data->block_count = count; - data->tx_data = (const uint32_t *)buf; - data->cmd12 = true; - if (data->block_count == 1U) { - cmd->index = SDHC_WRITE_BLOCK; - } - cmd->argument = sector; - if (!(priv->card_info.card_flags & SDHC_HIGH_CAPACITY_FLAG)) { - cmd->argument *= priv->card_info.sd_block_size; - } - cmd->rsp_type = SDHC_RSP_TYPE_R1; - cmd->rsp_err_flags = SDHC_R1ERR_All_FLAG; - - return usdhc_xfer(priv); -} - -static int usdhc_read_sector(void *bus_data, uint8_t *buf, uint32_t sector, - uint32_t count) -{ - struct usdhc_priv *priv = bus_data; - struct usdhc_cmd *cmd = &priv->op_context.cmd; - struct usdhc_data *data = &priv->op_context.data; - - memset((char *)cmd, 0, sizeof(struct usdhc_cmd)); - memset((char *)data, 0, sizeof(struct usdhc_data)); - - if (sector + count > priv->card_info.sd_block_count) { - return -EIO; - } - - if (usdhc_poll_card_status_busy(priv, USDHC_WAIT_IDLE_TIMEOUT)) { - return -ETIMEDOUT; - } - - priv->op_context.cmd_only = 0; - cmd->index = SDHC_READ_MULTIPLE_BLOCK; - data->block_size = priv->card_info.sd_block_size; - data->block_count = count; - data->rx_data = (uint32_t *)buf; - data->cmd12 = true; - - if (data->block_count == 1U) { - cmd->index = SDHC_READ_SINGLE_BLOCK; - } - - cmd->argument = sector; - if (!(priv->card_info.card_flags & SDHC_HIGH_CAPACITY_FLAG)) { - cmd->argument *= priv->card_info.sd_block_size; - } - - cmd->rsp_type = SDHC_RSP_TYPE_R1; - cmd->rsp_err_flags = SDHC_R1ERR_All_FLAG; - - return usdhc_xfer(priv); -} - -static bool usdhc_set_sd_active(USDHC_Type *base) -{ - uint32_t timeout = 0xffff; - - base->SYS_CTRL |= USDHC_SYS_CTRL_INITA_MASK; - /* Delay some time to wait card become active state. */ - while ((base->SYS_CTRL & USDHC_SYS_CTRL_INITA_MASK) == - USDHC_SYS_CTRL_INITA_MASK) { - if (!timeout) { - break; - } - timeout--; - } - - return ((!timeout) ? false : true); -} - -static void usdhc_get_host_capability(USDHC_Type *base, - struct usdhc_capability *capability) -{ - uint32_t host_cap; - uint32_t max_blk_len; - - host_cap = base->HOST_CTRL_CAP; - - /* Get the capability of USDHC. */ - max_blk_len = ((host_cap & USDHC_HOST_CTRL_CAP_MBL_MASK) >> - USDHC_HOST_CTRL_CAP_MBL_SHIFT); - capability->max_blk_len = (512U << max_blk_len); - /* Other attributes not in HTCAPBLT register. */ - capability->max_blk_cnt = USDHC_MAX_BLOCK_COUNT; - capability->host_flags = (host_cap & (USDHC_SUPPORT_ADMA_FLAG | - USDHC_SUPPORT_HIGHSPEED_FLAG | USDHC_SUPPORT_DMA_FLAG | - USDHC_SUPPORT_SUSPEND_RESUME_FLAG | USDHC_SUPPORT_V330_FLAG)); - capability->host_flags |= (host_cap & USDHC_SUPPORT_V300_FLAG); - capability->host_flags |= (host_cap & USDHC_SUPPORT_V180_FLAG); - capability->host_flags |= - (host_cap & (USDHC_SUPPORT_DDR50_FLAG | - USDHC_SUPPORT_SDR104_FLAG | - USDHC_SUPPORT_SDR50_FLAG)); - /* USDHC support 4/8 bit data bus width. */ - capability->host_flags |= (USDHC_SUPPORT_4BIT_FLAG | - USDHC_SUPPORT_8BIT_FLAG); -} - -static bool usdhc_hw_reset(USDHC_Type *base, uint32_t mask, uint32_t timeout) -{ - base->SYS_CTRL |= (mask & (USDHC_SYS_CTRL_RSTA_MASK | - USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK)); - /* Delay some time to wait reset success. */ - while ((base->SYS_CTRL & mask)) { - if (!timeout) { - break; - } - timeout--; - } - - return ((!timeout) ? false : true); -} - -static void usdhc_host_hw_init(USDHC_Type *base, - const struct usdhc_config *config) -{ - uint32_t proctl, sysctl, wml; - uint32_t int_mask; - - __ASSERT_NO_MSG(config); - __ASSERT_NO_MSG((config->write_watermark >= 1U) && - (config->write_watermark <= 128U)); - __ASSERT_NO_MSG((config->read_watermark >= 1U) && - (config->read_watermark <= 128U)); - __ASSERT_NO_MSG(config->write_burst_len <= 16U); - - /* Reset USDHC. */ - usdhc_hw_reset(base, USDHC_RESET_ALL, 100U); - - proctl = base->PROT_CTRL; - wml = base->WTMK_LVL; - sysctl = base->SYS_CTRL; - - proctl &= ~(USDHC_PROT_CTRL_EMODE_MASK | USDHC_PROT_CTRL_DMASEL_MASK); - /* Endian mode*/ - proctl |= USDHC_PROT_CTRL_EMODE(config->endian); - -#if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) - /* Watermark level */ - wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK); - wml |= (USDHC_WTMK_LVL_RD_WML(config->read_watermark) | - USDHC_WTMK_LVL_WR_WML(config->write_watermark)); -#else - /* Watermark level */ - wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | - USDHC_WTMK_LVL_WR_WML_MASK | - USDHC_WTMK_LVL_RD_BRST_LEN_MASK | - USDHC_WTMK_LVL_WR_BRST_LEN_MASK); - wml |= (USDHC_WTMK_LVL_RD_WML(config->read_watermark) | - USDHC_WTMK_LVL_WR_WML(config->write_watermark) | - USDHC_WTMK_LVL_RD_BRST_LEN(config->read_burst_len) | - USDHC_WTMK_LVL_WR_BRST_LEN(config->write_burst_len)); -#endif - - /* config the data timeout value */ - sysctl &= ~USDHC_SYS_CTRL_DTOCV_MASK; - sysctl |= USDHC_SYS_CTRL_DTOCV(config->data_timeout); - - base->SYS_CTRL = sysctl; - base->WTMK_LVL = wml; - base->PROT_CTRL = proctl; - - /* disable internal DMA and DDR mode */ - base->MIX_CTRL &= ~(USDHC_MIX_CTRL_DMAEN_MASK | - USDHC_MIX_CTRL_DDR_EN_MASK); - - int_mask = (USDHC_INT_CMD_FLAG | USDHC_INT_CARD_DETECT_FLAG | - USDHC_INT_DATA_FLAG | USDHC_INT_SDR104_TUNING_FLAG | - USDHC_INT_BLK_GAP_EVENT_FLAG); - - base->INT_STATUS_EN |= int_mask; - -} - -static void usdhc_cd_gpio_cb(const struct device *dev, - struct gpio_callback *cb, uint32_t pins) -{ - struct usdhc_priv *priv = - CONTAINER_OF(cb, struct usdhc_priv, detect_cb); - const struct usdhc_config *config = priv->config; - - gpio_pin_interrupt_configure(dev, config->detect_pin, GPIO_INT_DISABLE); -} - -static int usdhc_cd_gpio_init(const struct device *detect_gpio, - uint32_t pin, gpio_dt_flags_t flags, - struct gpio_callback *callback) -{ - int ret; - - ret = gpio_pin_configure(detect_gpio, pin, GPIO_INPUT | flags); - if (ret) - return ret; - - gpio_init_callback(callback, usdhc_cd_gpio_cb, BIT(pin)); - - return gpio_add_callback(detect_gpio, callback); -} - -static void usdhc_host_reset(struct usdhc_priv *priv) -{ - USDHC_Type *base = priv->config->base; - - usdhc_select_1_8_vol(base, false); - usdhc_enable_ddr_mode(base, false, 0); - usdhc_tuning(base, SDHC_STANDARD_TUNING_START, SDHC_TUINIG_STEP, false); -#if FSL_FEATURE_USDHC_HAS_HS400_MODE - /* Disable HS400 mode */ - /* Disable DLL */ -#endif -} - -static int usdhc_app_host_cmd(struct usdhc_priv *priv, int retry, - uint32_t arg, uint8_t app_cmd, uint32_t app_arg, enum sdhc_rsp_type rsp_type, - enum sdhc_rsp_type app_rsp_type, bool app_cmd_only) -{ - struct usdhc_cmd *cmd = &priv->op_context.cmd; - int ret; - -APP_CMD_XFER_AGAIN: - priv->op_context.cmd_only = 1; - cmd->index = SDHC_APP_CMD; - cmd->argument = arg; - cmd->rsp_type = rsp_type; - ret = usdhc_xfer(priv); - retry--; - if (ret && retry > 0) { - goto APP_CMD_XFER_AGAIN; - } - - priv->op_context.cmd_only = app_cmd_only; - cmd->index = app_cmd; - cmd->argument = app_arg; - cmd->rsp_type = app_rsp_type; - ret = usdhc_xfer(priv); - if (ret && retry > 0) { - goto APP_CMD_XFER_AGAIN; - } - - return ret; -} - -static int usdhc_sd_init(struct usdhc_priv *priv) -{ - const struct usdhc_config *config = priv->config; - USDHC_Type *base = config->base; - uint32_t app_cmd_41_arg = 0U; - int ret, retry; - struct usdhc_cmd *cmd = &priv->op_context.cmd; - struct usdhc_data *data = &priv->op_context.data; - - if (!priv->host_ready) { - return -ENODEV; - } - - /* reset variables */ - priv->card_info.card_flags = 0U; - /* set DATA bus width 1bit at beginning*/ - usdhc_set_bus_width(base, USDHC_DATA_BUS_WIDTH_1BIT); - /*set card freq to 400KHZ at begging*/ - priv->card_info.busclk_hz = - usdhc_set_sd_clk(base, priv->src_clk_hz, - SDMMC_CLOCK_400KHZ); - /* send card active */ - ret = usdhc_set_sd_active(base); - if (ret == false) { - return -EIO; - } - - /* Get host capability. */ - usdhc_get_host_capability(base, &priv->host_capability); - - /* card go idle */ - usdhc_op_ctx_init(priv, 1, SDHC_GO_IDLE_STATE, 0, SDHC_RSP_TYPE_NONE); - - ret = usdhc_xfer(priv); - if (ret) { - return ret; - } - - if (USDHC_SUPPORT_V330_FLAG != SDMMCHOST_NOT_SUPPORT) { - app_cmd_41_arg |= (SD_OCR_VDD32_33FLAG | SD_OCR_VDD33_34FLAG); - priv->card_info.voltage = SD_VOL_3_3_V; - } else if (USDHC_SUPPORT_V300_FLAG != SDMMCHOST_NOT_SUPPORT) { - app_cmd_41_arg |= SD_OCR_VDD29_30FLAG; - priv->card_info.voltage = SD_VOL_3_3_V; - } - - /* allow user select the work voltage, if not select, - * sdmmc will handle it automatically - */ - if (priv->config->no_1_8_v == false) { - if (USDHC_SUPPORT_V180_FLAG != SDMMCHOST_NOT_SUPPORT) { - app_cmd_41_arg |= SD_OCR_SWITCH_18_REQ_FLAG; - } - } - - /* Check card's supported interface condition. */ - usdhc_op_ctx_init(priv, 1, SDHC_SEND_IF_COND, - SDHC_VHS_3V3 | SDHC_CHECK, SDHC_RSP_TYPE_R7); - - retry = 10; - while (retry) { - ret = usdhc_xfer(priv); - if (!ret) { - if ((cmd->response[0U] & 0xFFU) != SDHC_CHECK) { - ret = -ENOTSUP; - } else { - break; - } - } - retry--; - } - - if (!ret) { - /* SDHC or SDXC card */ - app_cmd_41_arg |= SD_OCR_HOST_CAP_FLAG; - priv->card_info.card_flags |= USDHC_SDHC_FLAG; - } else { - /* SDSC card */ - LOG_ERR("USDHC SDSC not implemented yet!"); - return -ENOTSUP; - } - - /* Set card interface condition according to SDHC capability and - * card's supported interface condition. - */ -APP_SEND_OP_COND_AGAIN: - usdhc_op_ctx_init(priv, 1, 0, 0, SDHC_RSP_TYPE_NONE); - ret = usdhc_app_host_cmd(priv, NXP_SDMMC_MAX_VOLTAGE_RETRIES, 0, - SDHC_APP_SEND_OP_COND, app_cmd_41_arg, - SDHC_RSP_TYPE_R1, SDHC_RSP_TYPE_R3, 1); - if (ret) { - LOG_ERR("APP Condition CMD failed:%d", ret); - return ret; - } - if (cmd->response[0U] & SD_OCR_PWR_BUSY_FLAG) { - /* high capacity check */ - if (cmd->response[0U] & SD_OCR_CARD_CAP_FLAG) { - priv->card_info.card_flags |= SDHC_HIGH_CAPACITY_FLAG; - } - - if (priv->config->no_1_8_v == false) { - /* 1.8V support */ - if (cmd->response[0U] & SD_OCR_SWITCH_18_ACCEPT_FLAG) { - priv->card_info.card_flags |= SDHC_1800MV_FLAG; - } - } - priv->card_info.raw_ocr = cmd->response[0U]; - } else { - goto APP_SEND_OP_COND_AGAIN; - } - - /* check if card support 1.8V */ - if ((priv->card_info.card_flags & USDHC_VOL_1_8V_FLAG)) { - usdhc_op_ctx_init(priv, 1, SDHC_VOL_SWITCH, - 0, SDHC_RSP_TYPE_R1); - - ret = usdhc_xfer(priv); - if (!ret) { - ret = usdhc_vol_switch(priv); - } - if (ret) { - LOG_ERR("Voltage switch failed: %d", ret); - return ret; - } - priv->card_info.voltage = SD_VOL_1_8_V; - } - - /* Initialize card if the card is SD card. */ - usdhc_op_ctx_init(priv, 1, SDHC_ALL_SEND_CID, 0, SDHC_RSP_TYPE_R2); - - ret = usdhc_xfer(priv); - if (!ret) { - memcpy(priv->card_info.raw_cid, cmd->response, - sizeof(priv->card_info.raw_cid)); - sdhc_decode_cid(&priv->card_info.cid, - priv->card_info.raw_cid); - } else { - LOG_ERR("All send CID CMD failed: %d", ret); - return ret; - } - - usdhc_op_ctx_init(priv, 1, SDHC_SEND_RELATIVE_ADDR, - 0, SDHC_RSP_TYPE_R6); - - ret = usdhc_xfer(priv); - if (!ret) { - priv->card_info.relative_addr = (cmd->response[0U] >> 16U); - } else { - LOG_ERR("Send relative address CMD failed: %d", ret); - return ret; - } - - usdhc_op_ctx_init(priv, 1, SDHC_SEND_CSD, - (priv->card_info.relative_addr << 16U), SDHC_RSP_TYPE_R2); - - ret = usdhc_xfer(priv); - if (!ret) { - memcpy(priv->card_info.raw_csd, cmd->response, - sizeof(priv->card_info.raw_csd)); - sdhc_decode_csd(&priv->card_info.csd, priv->card_info.raw_csd, - &priv->card_info.sd_block_count, - &priv->card_info.sd_block_size); - } else { - LOG_ERR("Send CSD CMD failed: %d", ret); - return ret; - } - - usdhc_op_ctx_init(priv, 1, SDHC_SELECT_CARD, - priv->card_info.relative_addr << 16U, - SDHC_RSP_TYPE_R1); - - ret = usdhc_xfer(priv); - if (ret || (cmd->response[0U] & SDHC_R1ERR_All_FLAG)) { - LOG_ERR("Select card CMD failed: %d", ret); - return -EIO; - } - - usdhc_op_ctx_init(priv, 0, 0, 0, SDHC_RSP_TYPE_NONE); - data->block_size = 8; - data->block_count = 1; - data->rx_data = &priv->card_info.raw_scr[0]; - ret = usdhc_app_host_cmd(priv, 1, (priv->card_info.relative_addr << 16), - SDHC_APP_SEND_SCR, 0, - SDHC_RSP_TYPE_R1, SDHC_RSP_TYPE_R1, 0); - - if (ret) { - LOG_ERR("Send SCR following APP CMD failed: %d", ret); - return ret; - } - - switch (config->endian) { - case USDHC_LITTLE_ENDIAN: - priv->card_info.raw_scr[0] = - SWAP_WORD_BYTE_SEQUENCE(priv->card_info.raw_scr[0]); - priv->card_info.raw_scr[1] = - SWAP_WORD_BYTE_SEQUENCE(priv->card_info.raw_scr[1]); - break; - case USDHC_BIG_ENDIAN: - break; - case USDHC_HALF_WORD_BIG_ENDIAN: - priv->card_info.raw_scr[0U] = - SWAP_HALF_WROD_BYTE_SEQUENCE( - priv->card_info.raw_scr[0U]); - priv->card_info.raw_scr[1U] = - SWAP_HALF_WROD_BYTE_SEQUENCE( - priv->card_info.raw_scr[1U]); - break; - default: - return -EINVAL; - } - - sdhc_decode_scr(&priv->card_info.scr, priv->card_info.raw_scr, - &priv->card_info.version); - if (priv->card_info.scr.sd_width & 0x4U) { - priv->card_info.card_flags |= - USDHC_4BIT_WIDTH_FLAG; - } - /* speed class control cmd */ - if (priv->card_info.scr.cmd_support & 0x01U) { - priv->card_info.card_flags |= - USDHC_SPEED_CLASS_CONTROL_CMD_FLAG; - } - /* set block count cmd */ - if (priv->card_info.scr.cmd_support & 0x02U) { - priv->card_info.card_flags |= - USDHC_SET_BLK_CNT_CMD23_FLAG; - } - - /* Set to max frequency in non-high speed mode. */ - priv->card_info.busclk_hz = usdhc_set_sd_clk(base, - priv->src_clk_hz, SD_CLOCK_25MHZ); - - /* Set to 4-bit data bus mode. */ - if ((priv->host_capability.host_flags & USDHC_SUPPORT_4BIT_FLAG) && - (priv->card_info.card_flags & USDHC_4BIT_WIDTH_FLAG)) { - usdhc_op_ctx_init(priv, 1, 0, 0, SDHC_RSP_TYPE_NONE); - - ret = usdhc_app_host_cmd(priv, 1, - (priv->card_info.relative_addr << 16), - SDHC_APP_SET_BUS_WIDTH, 2, - SDHC_RSP_TYPE_R1, SDHC_RSP_TYPE_R1, 1); - - if (ret) { - LOG_ERR("Set bus width failed: %d", ret); - return ret; - } - usdhc_set_bus_width(base, USDHC_DATA_BUS_WIDTH_4BIT); - } - - if (priv->card_info.version >= SD_SPEC_VER3_0) { - /* set sd card driver strength */ - ret = usdhc_select_fun(priv, SD_GRP_DRIVER_STRENGTH_MODE, - priv->card_info.driver_strength); - if (ret) { - LOG_ERR("Set SD driver strength failed: %d", ret); - return ret; - } - - /* set sd card current limit */ - ret = usdhc_select_fun(priv, SD_GRP_CURRENT_LIMIT_MODE, - priv->card_info.max_current); - if (ret) { - LOG_ERR("Set SD current limit failed: %d", ret); - return ret; - } - } - - /* set block size */ - usdhc_op_ctx_init(priv, 1, SDHC_SET_BLOCK_SIZE, - priv->card_info.sd_block_size, SDHC_RSP_TYPE_R1); - - ret = usdhc_xfer(priv); - if (ret || cmd->response[0U] & SDHC_R1ERR_All_FLAG) { - LOG_ERR("Set block size failed: %d", ret); - return -EIO; - } - - if (priv->card_info.version > SD_SPEC_VER1_0) { - /* select bus timing */ - ret = usdhc_select_bus_timing(priv); - if (ret) { - LOG_ERR("Select bus timing failed: %d", ret); - return ret; - } - } - - retry = 10; - ret = -EIO; - while (ret && retry >= 0) { - ret = usdhc_read_sector(priv, (uint8_t *)g_usdhc_rx_dummy, 0, 1); - if (!ret) { - break; - } - retry--; - } - - if (ret) { - LOG_ERR("USDHC bus device initialization failed!"); - } - - return ret; -} - -static K_MUTEX_DEFINE(z_usdhc_init_lock); - - -static int usdhc_dat3_pull(bool pullup, struct usdhc_priv *priv) -{ - int ret = 0U; - -#ifdef CONFIG_PINCTRL - if (pullup) { - /* Default pin configuration pulls dat3 up */ - ret = pinctrl_apply_state(priv->config->pincfg, PINCTRL_STATE_DEFAULT); - if (ret) { - return ret; - } - } else { - /* remove pull on dat3 */ - ret = pinctrl_apply_state(priv->config->pincfg, PINCTRL_STATE_NOPULL); - if (ret) { - LOG_ERR("No floating pinctrl state"); - return ret; - } - } -#else - /* Call board specific function to pull down DAT3 */ - imxrt_usdhc_dat3_pull(pullup); -#endif -#ifdef CONFIG_SDMMC_USDHC_DAT3_PWR_TOGGLE - if (!pullup) { - /* Power off the card to clear DAT3 legacy status */ - if (priv->pwr_gpio) { - ret = gpio_pin_set(priv->pwr_gpio, priv->config->pwr_pin, 0); - if (ret) { - return ret; - } - /* Delay for card power off to complete */ - usdhc_millsec_delay(CONFIG_SDMMC_USDHC_DAT3_PWR_DELAY); - ret = gpio_pin_set(priv->pwr_gpio, priv->config->pwr_pin, 1); - if (ret) { - return ret; - } - } - } -#endif - return ret; -} - -static int usdhc_board_access_init(struct usdhc_priv *priv) -{ - const struct usdhc_config *config = priv->config; - int ret = 0; - uint32_t gpio_level; - USDHC_Type *base = config->base; - - if (config->pwr_name) { - priv->pwr_gpio = device_get_binding(config->pwr_name); - if (!priv->pwr_gpio) { - return -ENODEV; - } - } - - if (config->detect_name) { - priv->detect_type = SD_DETECT_GPIO_CD; - priv->detect_gpio = device_get_binding(config->detect_name); - if (!priv->detect_gpio) { - return -ENODEV; - } - } - - if (config->detect_dat3) { - priv->detect_type = SD_DETECT_HOST_DATA3; - } - - - if (priv->pwr_gpio) { - ret = gpio_pin_configure(priv->pwr_gpio, - config->pwr_pin, - GPIO_OUTPUT_ACTIVE | - config->pwr_flags); - if (ret) { - return ret; - } - - /* 100ms delay to make sure SD card is stable, - * maybe could be shorter - */ - k_busy_wait(100000); - } - - if (!priv->detect_gpio) { - LOG_INF("USDHC detection other than GPIO"); - if (config->detect_dat3) { - LOG_INF("USDHC detection using DAT3 pull"); - base->PROT_CTRL |= USDHC_PROT_CTRL_D3CD_MASK; - /* Pull down DAT3 */ - usdhc_dat3_pull(USDHC_DAT3_PULL_DOWN, priv); - } else { - /* DATA3 does not monitor card insertion */ - base->PROT_CTRL &= ~USDHC_PROT_CTRL_D3CD_MASK; - } - if ((base->PRES_STATE & USDHC_PRES_STATE_CINST_MASK) != 0) { - priv->inserted = true; - if (config->detect_dat3) { - usdhc_dat3_pull(USDHC_DAT3_PULL_UP, priv); - /* Disable DAT3 detect function */ - base->PROT_CTRL &= ~USDHC_PROT_CTRL_D3CD_MASK; - } - } else { - priv->inserted = false; - return -ENODEV; - } - } else { - ret = usdhc_cd_gpio_init(priv->detect_gpio, - config->detect_pin, - config->detect_flags, - &priv->detect_cb); - if (ret) { - return ret; - } - ret = gpio_pin_get(priv->detect_gpio, config->detect_pin); - if (ret < 0) { - return ret; - } - - gpio_level = ret; - - if (gpio_level == 0) { - priv->inserted = false; - LOG_ERR("NO SD inserted!"); - - return -ENODEV; - } - - priv->inserted = true; - LOG_INF("SD inserted!"); - } - return 0; -} - -static int usdhc_access_init(const struct device *dev) -{ - const struct usdhc_config *config = dev->config; - struct usdhc_priv *priv = dev->data; - int ret; - - (void)k_mutex_lock(&z_usdhc_init_lock, K_FOREVER); - - memset((char *)priv, 0, sizeof(struct usdhc_priv)); - priv->config = config; - - if (!config->base) { - k_mutex_unlock(&z_usdhc_init_lock); - - return -ENODEV; - } - - if (clock_control_get_rate(config->clock_dev, - config->clock_subsys, - &priv->src_clk_hz)) { - return -EINVAL; - } - - ret = usdhc_board_access_init(priv); - if (ret) { - k_mutex_unlock(&z_usdhc_init_lock); - - return ret; - } - - priv->op_context.dma_cfg.dma_mode = USDHC_DMA_ADMA2; - priv->op_context.dma_cfg.burst_len = USDHC_INCR_BURST_LEN; - /*No DMA used for this Version*/ - priv->op_context.dma_cfg.adma_table = 0; - priv->op_context.dma_cfg.adma_table_words = USDHC_ADMA_TABLE_WORDS; - usdhc_host_hw_init(config->base, config); - priv->host_ready = 1; - - usdhc_host_reset(priv); - ret = usdhc_sd_init(priv); - k_mutex_unlock(&z_usdhc_init_lock); - - return ret; -} - -static int disk_usdhc_access_status(struct disk_info *disk) -{ - const struct device *dev = disk->dev; - struct usdhc_priv *priv = dev->data; - - return priv->status; -} - -static int disk_usdhc_access_read(struct disk_info *disk, uint8_t *buf, - uint32_t sector, uint32_t count) -{ - const struct device *dev = disk->dev; - struct usdhc_priv *priv = dev->data; - - LOG_DBG("sector=%u count=%u", sector, count); - - return usdhc_read_sector(priv, buf, sector, count); -} - -static int disk_usdhc_access_write(struct disk_info *disk, const uint8_t *buf, - uint32_t sector, uint32_t count) -{ - const struct device *dev = disk->dev; - struct usdhc_priv *priv = dev->data; - - LOG_DBG("sector=%u count=%u", sector, count); - - return usdhc_write_sector(priv, buf, sector, count); -} - -static int disk_usdhc_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buf) -{ - const struct device *dev = disk->dev; - struct usdhc_priv *priv = dev->data; - int err; - - err = sdhc_map_disk_status(priv->status); - if (err != 0) { - return err; - } - - switch (cmd) { - case DISK_IOCTL_CTRL_SYNC: - break; - case DISK_IOCTL_GET_SECTOR_COUNT: - *(uint32_t *)buf = priv->card_info.sd_block_count; - break; - case DISK_IOCTL_GET_SECTOR_SIZE: - *(uint32_t *)buf = priv->card_info.sd_block_size; - break; - case DISK_IOCTL_GET_ERASE_BLOCK_SZ: - *(uint32_t *)buf = priv->card_info.sd_block_size; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int disk_usdhc_access_init(struct disk_info *disk) -{ - const struct device *dev = disk->dev; - struct usdhc_priv *priv = dev->data; - - if (priv->status == DISK_STATUS_OK) { - /* Called twice, don't re-init. */ - return 0; - } - - return usdhc_access_init(dev); -} - -static const struct disk_operations usdhc_disk_ops = { - .init = disk_usdhc_access_init, - .status = disk_usdhc_access_status, - .read = disk_usdhc_access_read, - .write = disk_usdhc_access_write, - .ioctl = disk_usdhc_access_ioctl, -}; - -static struct disk_info usdhc_disk = { - .name = CONFIG_SDMMC_VOLUME_NAME, - .ops = &usdhc_disk_ops, -}; - -static int disk_usdhc_init(const struct device *dev) -{ - struct usdhc_priv *priv = dev->data; -#ifdef CONFIG_PINCTRL - const struct usdhc_config *config = dev->config; - int err; - - err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); - if (err) { - return err; - } -#endif /* CONFIG_PINCTRL */ - - priv->status = DISK_STATUS_UNINIT; - - usdhc_disk.dev = dev; - - return disk_access_register(&usdhc_disk); -} - - -#ifdef CONFIG_PINCTRL -#define PINCTRL_DEFINE(n) PINCTRL_DT_INST_DEFINE(n); -#define PINCTRL_INIT(n) .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), -#else -#define PINCTRL_DEFINE(n) -#define PINCTRL_INIT(n) -#endif /* CONFIG_PINCTRL */ - -#define DISK_ACCESS_USDHC_INIT_NONE(n) - -#define DISK_ACCESS_USDHC_INIT_PWR_PROPS(n) \ - .pwr_name = DT_INST_GPIO_LABEL(n, pwr_gpios), \ - .pwr_pin = DT_INST_GPIO_PIN(n, pwr_gpios), \ - .pwr_flags = DT_INST_GPIO_FLAGS(n, pwr_gpios), - -#define DISK_ACCESS_USDHC_INIT_CD_PROPS(n) \ - .detect_name = DT_INST_GPIO_LABEL(n, cd_gpios), \ - .detect_pin = DT_INST_GPIO_PIN(n, cd_gpios), \ - .detect_flags = DT_INST_GPIO_FLAGS(n, cd_gpios), - -#define DISK_ACCESS_USDHC_INIT_PWR(n) \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(n, pwr_gpios), \ - (DISK_ACCESS_USDHC_INIT_PWR_PROPS(n)), \ - (DISK_ACCESS_USDHC_INIT_NONE(n))) - -#define DISK_ACCESS_USDHC_INIT_CD(n) \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(n, cd_gpios), \ - (DISK_ACCESS_USDHC_INIT_CD_PROPS(n)), \ - (DISK_ACCESS_USDHC_INIT_NONE(n))) - -#define DISK_ACCESS_USDHC_INIT(n) \ - PINCTRL_DEFINE(n) \ - static const struct usdhc_config usdhc_config_##n = { \ - .base = (USDHC_Type *) DT_INST_REG_ADDR(n), \ - .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ - .clock_subsys = \ - (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name), \ - .nusdhc = n, \ - DISK_ACCESS_USDHC_INIT_PWR(n) \ - DISK_ACCESS_USDHC_INIT_CD(n) \ - .no_1_8_v = DT_INST_PROP(n, no_1_8_v), \ - .detect_dat3 = DT_INST_PROP(n, detect_dat3), \ - .data_timeout = USDHC_DATA_TIMEOUT, \ - .endian = USDHC_LITTLE_ENDIAN, \ - .read_watermark = USDHC_READ_WATERMARK_LEVEL, \ - .write_watermark = USDHC_WRITE_WATERMARK_LEVEL, \ - .read_burst_len = USDHC_READ_BURST_LEN, \ - .write_burst_len = USDHC_WRITE_BURST_LEN, \ - PINCTRL_INIT(n) \ - }; \ - \ - static struct usdhc_priv usdhc_priv_##n; \ - \ - DEVICE_DT_INST_DEFINE(n, \ - &disk_usdhc_init, \ - NULL, \ - &usdhc_priv_##n, \ - &usdhc_config_##n, \ - POST_KERNEL, \ - CONFIG_SDMMC_INIT_PRIORITY, \ - NULL); - -DT_INST_FOREACH_STATUS_OKAY(DISK_ACCESS_USDHC_INIT) diff --git a/dts/bindings/mmc/nxp,imx-usdhc.yaml b/dts/bindings/mmc/nxp,imx-usdhc.yaml deleted file mode 100644 index aca07814f2d..00000000000 --- a/dts/bindings/mmc/nxp,imx-usdhc.yaml +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2019, NXP -# SPDX-License-Identifier: Apache-2.0 - -description: NXP i.MXRT USDHC module - -compatible: "nxp,imx-usdhc" - -include: [mmc.yaml, pinctrl-device.yaml] - -properties: - clocks: - required: true - - pwr-gpios: - type: phandle-array - required: false - description: | - Power pin - This pin defaults to active high when consumed by the SD card. The - property value should ensure the flags properly describe the signal - that is presented to the driver. - - cd-gpios: - type: phandle-array - required: false - description: | - Detect pin - This pin defaults to active low when produced by the SD card. The - property value should ensure the flags properly describe the signal - that is presented to the driver. - - no-1-8-v: - type: boolean - required: false - description: | - When the external SD card circuit does not support 1.8V, add this - property to disable 1.8v card voltage of SD card controller. - - detect-dat3: - type: boolean - required: false - description: | - Enable the host to detect an SD card via the DAT3 line of the SD card - connection. Requires the board to define a function to pull DAT3 low or - high using pullup/pulldown resistors. - - label: - required: true diff --git a/tests/drivers/disk/testcase.yaml b/tests/drivers/disk/testcase.yaml index c057f597b55..11aaf4575c4 100644 --- a/tests/drivers/disk/testcase.yaml +++ b/tests/drivers/disk/testcase.yaml @@ -3,7 +3,7 @@ tests: harness: ztest harness_config: fixture: fixture_sdhc - filter: CONFIG_SDMMC_USDHC + filter: CONFIG_SDHC tags: disk mcux integration_platforms: - mimxrt1060_evk