diff --git a/APP_Framework/Applications/app_test/test_adc.c b/APP_Framework/Applications/app_test/test_adc.c index fbbf3ed09..1ff547f9c 100644 --- a/APP_Framework/Applications/app_test/test_adc.c +++ b/APP_Framework/Applications/app_test/test_adc.c @@ -31,7 +31,7 @@ void test_adc() adc_fd = PrivOpen(ADC_DEV_DRIVER, O_RDWR); if (adc_fd < 0) { - KPrintf("open adc fd error %d\n", adc_fd); + printf("open adc fd error %d\n", adc_fd); return; } @@ -39,7 +39,7 @@ void test_adc() ioctl_cfg.ioctl_driver_type = ADC_TYPE; ioctl_cfg.args = &adc_channel; if (0 != PrivIoctl(adc_fd, OPE_CFG, &ioctl_cfg)) { - KPrintf("ioctl adc fd error %d\n", adc_fd); + printf("ioctl adc fd error %d\n", adc_fd); PrivClose(adc_fd); return; } diff --git a/Ubiquitous/XiUOS/board/ok1052-c/board.c b/Ubiquitous/XiUOS/board/ok1052-c/board.c index 02fd1cd76..52d410412 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/board.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/board.c @@ -5,18 +5,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file board.c * @brief relative configure for ok1052-c @@ -25,10 +13,25 @@ * @date 2021.11.11 */ +/************************************************* +File name: board.c +Description: support imxrt1052-board init function +Others: take SDK_2.6.1_MIMXRT1052xxxxB for references +History: +1. Date: 2022-01-25 +Author: AIIT XUOS Lab +Modification: +1. support imxrt1052-board MPU、clock、memory init +2. support imxrt1052-board uart、semc、sdio driver init +*************************************************/ + #include "fsl_common.h" #include "board.h" #include "pin_mux.h" +#ifdef BSP_USING_SDIO +extern int Imrt1052HwSdioInit(void); +#endif #ifdef BSP_USING_SEMC extern status_t BOARD_InitSEMC(void); @@ -640,8 +643,12 @@ void InitBoardHardware() #ifdef BSP_USING_LPUART Imrt1052HwUartInit(); #endif + InstallConsole(KERNEL_CONSOLE_BUS_NAME, KERNEL_CONSOLE_DRV_NAME, KERNEL_CONSOLE_DEVICE_NAME); +#ifdef BSP_USING_SDIO + Imrt1052HwSdioInit(); +#endif } diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig index a0480d689..b43f274f1 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig @@ -13,8 +13,15 @@ menuconfig BSP_USING_LWIP menuconfig BSP_USING_SEMC bool "Using SEMC device" - default y - + default n if BSP_USING_SEMC source "$BSP_DIR/third_party_driver/semc/Kconfig" endif + +menuconfig BSP_USING_SDIO + bool "Using SD card device" + default y + select RESOURCES_SDIO + if BSP_USING_SDIO + source "$BSP_DIR/third_party_driver/sdio/Kconfig" + endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Makefile index b55123bc5..4613b4f05 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Makefile +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Makefile @@ -12,4 +12,8 @@ ifeq ($(CONFIG_BSP_USING_SEMC),y) SRC_DIR += semc endif +ifeq ($(CONFIG_BSP_USING_SDIO),y) + SRC_DIR += sdio +endif + include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/Makefile index e88d02258..7fda1f6bc 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/Makefile +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/Makefile @@ -1,3 +1,7 @@ SRC_FILES := system_MIMXRT1052.c fsl_cache.c fsl_clock.c fsl_common.c pin_mux.c clock_config.c +ifeq ($(CONFIG_BSP_USING_SDIO),y) + SRC_FILES += fsl_usdhc.c +endif + include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/pin_mux.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/pin_mux.c index 8504b75df..b8d4877f8 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/pin_mux.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/pin_mux.c @@ -35,6 +35,7 @@ pin_labels: #include "fsl_common.h" #include "fsl_iomuxc.h" #include "pin_mux.h" +#include "xsconfig.h" /* FUNCTION ************************************************************************************************************ * @@ -46,6 +47,101 @@ void BOARD_InitBootPins(void) { BOARD_InitPins(); } +void SDHCPinmuxConfig(void) +{ + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_14_USDHC1_VSELECT, /* GPIO_B1_14 is configured as USDHC1_VSELECT */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_00_USDHC1_CMD, /* GPIO_SD_B0_00 is configured as USDHC1_CMD */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_01_USDHC1_CLK, /* GPIO_SD_B0_01 is configured as USDHC1_CLK */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_02_USDHC1_DATA0, /* GPIO_SD_B0_02 is configured as USDHC1_DATA0 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_03_USDHC1_DATA1, /* GPIO_SD_B0_03 is configured as USDHC1_DATA1 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_04_USDHC1_DATA2, /* GPIO_SD_B0_04 is configured as USDHC1_DATA2 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B0_05_USDHC1_DATA3, /* GPIO_SD_B0_05 is configured as USDHC1_DATA3 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B1_14_USDHC1_VSELECT, /* GPIO_B1_14 PAD functional properties : */ + 0x0170A1u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/4 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 47K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B0_00_USDHC1_CMD, /* GPIO_SD_B0_00 PAD functional properties : */ + 0x017089u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 47K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B0_01_USDHC1_CLK, /* GPIO_SD_B0_01 PAD functional properties : */ + 0x014089u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Disabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 47K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B0_02_USDHC1_DATA0, /* GPIO_SD_B0_02 PAD functional properties : */ + 0x017089u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 47K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B0_03_USDHC1_DATA1, /* GPIO_SD_B0_03 PAD functional properties : */ + 0x017089u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 47K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B0_04_USDHC1_DATA2, /* GPIO_SD_B0_04 PAD functional properties : */ + 0x017089u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 47K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B0_05_USDHC1_DATA3, /* GPIO_SD_B0_05 PAD functional properties : */ + 0x017089u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0(150 Ohm @ 3.3V, 260 Ohm@1.8V) + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Pull + Pull Up / Down Config. Field: 47K Ohm Pull Up + Hyst. Enable Field: Hysteresis Enabled */ +} + void SemcPinmuxConfig(void) { @@ -630,6 +726,20 @@ BOARD_InitPins: pull_keeper_select: Pull, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0_5, slew_rate: Fast} - {pin_num: G13, peripheral: GPIO1, signal: 'gpio_io, 10', pin_signal: GPIO_AD_B0_10, software_input_on: Disable, hysteresis_enable: Disable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0_5, slew_rate: Fast} + - {pin_num: J3, peripheral: USDHC1, signal: usdhc_clk, pin_signal: GPIO_SD_B0_01, software_input_on: Disable, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_47K_Ohm, + pull_keeper_select: Keeper, pull_keeper_enable: Disable, open_drain: Disable, speed: MHZ_100, drive_strength: R0, slew_rate: Fast} + - {pin_num: J4, peripheral: USDHC1, signal: usdhc_cmd, pin_signal: GPIO_SD_B0_00, software_input_on: Disable, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_47K_Ohm, + pull_keeper_select: Pull, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0, slew_rate: Fast} + - {pin_num: J1, peripheral: USDHC1, signal: 'usdhc_data, 0', pin_signal: GPIO_SD_B0_02, software_input_on: Disable, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_47K_Ohm, + pull_keeper_select: Pull, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0, slew_rate: Fast} + - {pin_num: K1, peripheral: USDHC1, signal: 'usdhc_data, 1', pin_signal: GPIO_SD_B0_03, software_input_on: Disable, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_47K_Ohm, + pull_keeper_select: Pull, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0, slew_rate: Fast} + - {pin_num: H2, peripheral: USDHC1, signal: 'usdhc_data, 2', pin_signal: GPIO_SD_B0_04, software_input_on: Disable, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_47K_Ohm, + pull_keeper_select: Pull, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0, slew_rate: Fast} + - {pin_num: J2, peripheral: USDHC1, signal: 'usdhc_data, 3', pin_signal: GPIO_SD_B0_05, software_input_on: Disable, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_47K_Ohm, + pull_keeper_select: Pull, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0, slew_rate: Fast} + - {pin_num: C14, peripheral: USDHC1, signal: usdhc_vselect, pin_signal: GPIO_B1_14, software_input_on: Disable, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_47K_Ohm, + pull_keeper_select: Pull, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0_4, slew_rate: Fast} * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** */ @@ -661,6 +771,10 @@ void BOARD_InitPins(void) { IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 is configured as LPUART1_RX */ 0U); /* Software Input On Field: Input Path is determined by functionality */ +#ifdef BSP_USING_SDIO + SDHCPinmuxConfig(); +#endif + IOMUXC_SetPinMux( IOMUXC_GPIO_B1_04_ENET_RX_DATA00, /* GPIO_B1_04 is configured as ENET_RX_DATA00 */ 0U); /* Software Input On Field: Input Path is determined by functionality */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_sdio.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_sdio.h new file mode 100644 index 000000000..dcf2c72af --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_sdio.h @@ -0,0 +1,41 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_sdio.h +* @brief define OK1052-board sdio function and struct +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2022-01-24 +*/ + +#ifndef CONNECT_SDIO_H +#define CONNECT_SDIO_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int Imrt1052HwSdioInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_common.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_common.h index 0b0eca9e3..3410e8416 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_common.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_common.h @@ -6,18 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_common.h * @brief common drivers header diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/semc/fsl_semc.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_semc.h similarity index 100% rename from Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/semc/fsl_semc.h rename to Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_semc.h diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/Kconfig b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/Kconfig new file mode 100644 index 000000000..56ebba209 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/Kconfig @@ -0,0 +1,13 @@ +if BSP_USING_SDIO + config SDIO_BUS_NAME + string "sdio bus name" + default "sdio" + + config SDIO_DRIVER_NAME + string "sdio driver name" + default "sdio_drv" + + config SDIO_DEVICE_NAME + string "sdio device name" + default "sdio_dev" +endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/Makefile new file mode 100644 index 000000000..7e451903c --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/Makefile @@ -0,0 +1,5 @@ +SRC_DIR := sdmmc + +SRC_FILES := connect_sdio.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/connect_sdio.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/connect_sdio.c new file mode 100644 index 000000000..f06c0d26e --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/connect_sdio.c @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** +* @file connect_sdio.c +* @brief support sdio function using bus driver framework on OK1052 board +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2022-01-24 +*/ + +/************************************************* +File name: connect_sdio.c +Description: support imxrt1052-board sd card configure and sdio bus register function +Others: take SDK_2.6.1_MIMXRT1052xxxxB/boards/evkbimxrt1050/driver_examples/sdcard/polling/sdcard_polling.c for references +History: +1. Date: 2022-01-24 +Author: AIIT XUOS Lab +Modification: +1. support imxrt1052-board sdio configure, write and read +2. support imxrt1052-board sdio bus device and driver register +*************************************************/ + +#include + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define SDCARD_POWER_CTRL_FUNCTION_EXIST + +/*! @brief Data block count accessed in card */ +#define DATA_BLOCK_COUNT (5U) +/*! @brief Start data block number accessed in card */ +#define DATA_BLOCK_START (2U) +/*! @brief Data buffer size. */ +#define DATA_BUFFER_SIZE (FSL_SDMMC_DEFAULT_BLOCK_SIZE * DATA_BLOCK_COUNT) + +#define BOARD_USDHC_SDCARD_POWER_CONTROL(state) \ + (GPIO_PinWrite(BOARD_SD_POWER_RESET_GPIO, BOARD_SD_POWER_RESET_GPIO_PIN, state)) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static void BoardPowerOffSdCard(void); +static void BoardPowerOnSdCard(void); + +/*! + * @brief printf the card information log. + * + * @param card Card descriptor. + */ +static void CardInformationLog(sd_card_t *card); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* @brief decription about the read/write buffer + * The size of the read/write buffer should be a multiple of 512, since SDHC/SDXC card uses 512-byte fixed + * block length and this driver example is enabled with a SDHC/SDXC card.If you are using a SDSC card, you + * can define the block length by yourself if the card supports partial access. + * The address of the read/write buffer should align to the specific DMA data buffer address align value if + * DMA transfer is used, otherwise the buffer address is not important. + * At the same time buffer address/size should be aligned to the cache line size if cache is supported. + */ +/*! @brief Data written to the card */ +SDK_ALIGN(uint8_t g_data_write[SDK_SIZEALIGN(DATA_BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)], + MAX(SDMMC_DATA_BUFFER_ALIGN_CACHE, SDMMCHOST_DMA_BUFFER_ADDR_ALIGN)); +/*! @brief Data read from the card */ +SDK_ALIGN(uint8_t g_data_read[SDK_SIZEALIGN(DATA_BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)], + MAX(SDMMC_DATA_BUFFER_ALIGN_CACHE, SDMMCHOST_DMA_BUFFER_ADDR_ALIGN)); + +/*! @brief SDMMC host detect card configuration */ +static const sdmmchost_detect_card_t s_sdcard_detect = { +#ifndef BOARD_SD_DETECT_TYPE + .cdType = kSDMMCHOST_DetectCardByGpioCD, +#else + .cdType = BOARD_SD_DETECT_TYPE, +#endif + .cdTimeOut_ms = (~0U), +}; + +/*! @brief SDMMC card power control configuration */ +#if defined SDCARD_POWER_CTRL_FUNCTION_EXIST +static const sdmmchost_pwr_card_t s_sdcard_pwr_ctrl = { + .powerOn = BoardPowerOnSdCard, + .powerOnDelay_ms = 0U, + .powerOff = BoardPowerOffSdCard, + .powerOffDelay_ms = 0U, +}; +#endif + +/*! @brief SDMMC card power control configuration */ +#if defined SDCARD_SWITCH_VOLTAGE_FUNCTION_EXIST +static const sdmmchost_card_switch_voltage_func_t s_sdcard_voltage_switch = { + .cardSignalLine1V8 = BOARD_USDHC_Switch_VoltageTo1V8, + .cardSignalLine3V3 = BOARD_USDHC_Switch_VoltageTo3V3, +}; +#endif + +/*! @brief SD card detect flag */ +static volatile bool s_card_inserted = false; + +/*! @brief Card descriptor. */ +static sd_card_t g_sd; +static int sd_lock = -1; + +static void BoardUSDHCClockConfiguration(void) +{ + CLOCK_InitSysPll(&sysPllConfig_BOARD_BootClockRUN); + /*configure system pll PFD0 fractional divider to 24, output clock is 528MHZ * 18 / 24 = 396 MHZ*/ + CLOCK_InitSysPfd(kCLOCK_Pfd0, 24U); + /* Configure USDHC clock source and divider */ + CLOCK_SetDiv(kCLOCK_Usdhc1Div, 0U); + CLOCK_SetMux(kCLOCK_Usdhc1Mux, 1U); +} + +static void BoardPowerOffSdCard(void) +{ + /* + Do nothing here. + + SD card will not be detected correctly if the card VDD is power off, + the reason is caused by card VDD supply to the card detect circuit, this issue is exist on EVK board rev A1 and + A2. + + If power off function is not implemented after soft reset and prior to SD Host initialization without + remove/insert card, + a UHS-I card may not reach its highest speed mode during the second card initialization. + Application can avoid this issue by toggling the SD_VDD (GPIO) before the SD host initialization. + */ +} + +static void BoardPowerOnSdCard(void) +{ + BOARD_USDHC_SDCARD_POWER_CONTROL(1); +} + +static void SdcardDetectCallBack(bool is_inserted, void *user_data) +{ + s_card_inserted = is_inserted; +} + +static void CardInformationLog(sd_card_t *card) +{ + NULL_PARAM_CHECK(card); + + KPrintf("\r\nCard size %d * %d bytes\r\n", card->blockCount, card->blockSize); + KPrintf("\r\nWorking condition:\r\n"); + if (card->operationVoltage == kCARD_OperationVoltage330V) { + KPrintf("\r\n Voltage : 3.3V\r\n"); + } else if (card->operationVoltage == kCARD_OperationVoltage180V) { + KPrintf("\r\n Voltage : 1.8V\r\n"); + } + + if (card->currentTiming == kSD_TimingSDR12DefaultMode) { + if (card->operationVoltage == kCARD_OperationVoltage330V) { + KPrintf("\r\n Timing mode: Default mode\r\n"); + } else if (card->operationVoltage == kCARD_OperationVoltage180V) { + KPrintf("\r\n Timing mode: SDR12 mode\r\n"); + } + } else if (card->currentTiming == kSD_TimingSDR25HighSpeedMode) { + if (card->operationVoltage == kCARD_OperationVoltage180V) { + KPrintf("\r\n Timing mode: SDR25\r\n"); + } else { + KPrintf("\r\n Timing mode: High Speed\r\n"); + } + } else if (card->currentTiming == kSD_TimingSDR50Mode) { + KPrintf("\r\n Timing mode: SDR50\r\n"); + } else if (card->currentTiming == kSD_TimingSDR104Mode) { + KPrintf("\r\n Timing mode: SDR104\r\n"); + } else if (card->currentTiming == kSD_TimingDDR50Mode) { + KPrintf("\r\n Timing mode: DDR50\r\n"); + } + + KPrintf("\r\n Freq : %d HZ\r\n", card->busClock_Hz); +} + +static uint32 SdioConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(configure_info); + + if (configure_info->configure_cmd == OPER_BLK_GETGEOME) { + // NULL_PARAM_CHECK(configure_info->private_data); + // struct DeviceBlockArrange *args = (struct DeviceBlockArrange *)configure_info->private_data; + // //SD_GetCardInfo(&SDCardInfo); + + // // args->size_perbank = SDCardInfo.CardBlockSize; + // // args->block_size = SDCardInfo.CardBlockSize; + // // if(SDCardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD) + // // args->bank_num = (SDCardInfo.SD_csd.DeviceSize + 1) * 1024; + // // else + // // args->bank_num = SDCardInfo.CardCapacity; + } + + return EOK; +} + +static uint32 SdioOpen(void *dev) +{ + NULL_PARAM_CHECK(dev); + + if(sd_lock >= 0) { + KSemaphoreDelete(sd_lock); + } + sd_lock = KSemaphoreCreate(1); + if (sd_lock < 0){ + return ERROR; + } + + return EOK; +} + +static uint32 SdioClose(void *dev) +{ + NULL_PARAM_CHECK(dev); + + KSemaphoreDelete(sd_lock); + + return EOK; +} + +static uint32 SdioRead(void *dev, struct BusBlockReadParam *read_param) +{ + uint8 ret = EOK; + + KSemaphoreObtain(sd_lock, WAITING_FOREVER); + + // if (((uint32)read_param->buffer & 0x03) != 0) { + // uint64_t sector; + // uint8_t* temp; + + // sector = (uint64_t)read_param->pos * SDCARD_SECTOR_SIZE; + // temp = (uint8_t*)read_param->buffer; + + // for (uint8 i = 0; i < read_param->size; i++) { + // ret = SD_ReadBlock((uint8_t *)SDBuffer, sector, 1); + // if(ret != SD_OK) { + // KPrintf("read failed: %d, buffer 0x%08x\n", ret, temp); + // return 0; + // } + + // memcpy(temp, SDBuffer, SDCARD_SECTOR_SIZE); + + // sector += SDCARD_SECTOR_SIZE; + // temp += SDCARD_SECTOR_SIZE; + // } + // } else { + // ret = SD_ReadBlock((uint8_t *)read_param->buffer, (uint64_t)read_param->pos * SDCARD_SECTOR_SIZE, read_param->size); + // if (ret != SD_OK) { + // KPrintf("read failed: %d, buffer 0x%08x\n", ret, (uint8_t *)read_param->buffer); + // return 0; + // } + // } + + // KSemaphoreAbandon(sd_lock); + + return read_param->size; +} + +static uint32 SdioWrite(void *dev, struct BusBlockWriteParam *write_param) +{ + uint8 ret = EOK; + + // KSemaphoreObtain(sd_lock, WAITING_FOREVER); + + // if (((uint32)write_param->buffer & 0x03) != 0) { + // uint64_t sector; + // uint8_t* temp; + + // sector = (uint64_t)write_param->pos * SDCARD_SECTOR_SIZE; + // temp = (uint8_t*)write_param->buffer; + + // for (uint8 i = 0; i < write_param->size; i++) { + // memcpy(SDBuffer, temp, SDCARD_SECTOR_SIZE); + + // ret = SD_WriteBlock((uint8_t *)SDBuffer, sector, 1); + // if(ret != SD_OK) { + // KPrintf("write failed: %d, buffer 0x%08x\n", ret, temp); + // return 0; + // } + + // sector += SDCARD_SECTOR_SIZE; + // temp += SDCARD_SECTOR_SIZE; + // } + // } else { + // ret = SD_WriteBlock((uint8_t *)write_param->buffer, (uint64_t)write_param->pos * SDCARD_SECTOR_SIZE, write_param->size); + // if (ret != SD_OK) { + // KPrintf("write failed: %d, buffer 0x%08x\n", ret, (uint8_t *)write_param->buffer); + // return 0; + // } + // } + + KSemaphoreAbandon(sd_lock); + + return write_param->size; +} + +static struct SdioDevDone dev_done = +{ + SdioOpen, + SdioClose, + SdioWrite, + SdioRead, +}; + +int Imrt1052HwSdioInit(void) +{ + x_err_t ret = EOK; + bool is_read_only; + + static struct SdioBus sdio_bus; + static struct SdioDriver sdio_drv; + static struct SdioHardwareDevice sdio_dev; + static sd_card_t *card = &g_sd; + + memset(&sdio_bus, 0, sizeof(struct SdioBus)); + memset(&sdio_drv, 0, sizeof(struct SdioDriver)); + memset(&sdio_dev, 0, sizeof(struct SdioHardwareDevice)); + + BoardUSDHCClockConfiguration(); + + card->host.base = SD_HOST_BASEADDR; + card->host.sourceClock_Hz = SD_HOST_CLK_FREQ; + + /* card detect type */ + card->usrParam.cd = &s_sdcard_detect; + +#if defined SDCARD_POWER_CTRL_FUNCTION_EXIST + card->usrParam.pwr = &s_sdcard_pwr_ctrl; +#endif + +#if defined DEMO_SDCARD_SWITCH_VOLTAGE_FUNCTION_EXIST + card->usrParam.cardVoltage = &s_sdcard_voltage_switch; +#endif + + /* SD host init function */ + if (SD_HostInit(card) != kStatus_Success) { + KPrintf("\r\nSD host init fail\r\n"); + return ERROR; + } + + KPrintf("\r\nPlease insert a card into board.\r\n"); + + /* power off card */ + SD_PowerOffCard(card->host.base, card->usrParam.pwr); + + if (SD_WaitCardDetectStatus(SD_HOST_BASEADDR, &s_sdcard_detect, true) == kStatus_Success) { + KPrintf("\r\nCard inserted.\r\n"); + /* reset host once card re-plug in */ + SD_HostReset(&(card->host)); + /* power on the card */ + SD_PowerOnCard(card->host.base, card->usrParam.pwr); + KPrintf("power on done\n"); + } else { + KPrintf("\r\nCard detect fail.\r\n"); + return ERROR; + } + + /* Init card. */ + if (SD_CardInit(card)) { + KPrintf("\r\nSD card init failed.\r\n"); + return ERROR; + } + + /* card information log */ + CardInformationLog(card); + + /* Check if card is readonly. */ + is_read_only = SD_CheckReadOnly(card); + + ret = SdioBusInit(&sdio_bus, SDIO_BUS_NAME); + if (ret != EOK) { + KPrintf("Sdio bus init error %d\n", ret); + return ERROR; + } + + ret = SdioDriverInit(&sdio_drv, SDIO_DRIVER_NAME); + if (ret != EOK) { + KPrintf("Sdio driver init error %d\n", ret); + return ERROR; + } + ret = SdioDriverAttachToBus(SDIO_DRIVER_NAME, SDIO_BUS_NAME); + if (ret != EOK) { + KPrintf("Sdio driver attach error %d\n", ret); + return ERROR; + } + + sdio_dev.dev_done = &dev_done; + ret = SdioDeviceRegister(&sdio_dev, SDIO_DEVICE_NAME); + if (ret != EOK) { + KPrintf("Sdio device register error %d\n", ret); + return ERROR; + } + ret = SdioDeviceAttachToBus(SDIO_DEVICE_NAME, SDIO_BUS_NAME); + if (ret != EOK) { + KPrintf("Sdio device register error %d\n", ret); + return ERROR; + } + + return ret; +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/Makefile new file mode 100644 index 000000000..ecf9e5433 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/Makefile @@ -0,0 +1,3 @@ +SRC_DIR += port src + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_mmc.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_mmc.h new file mode 100644 index 000000000..6f280b72f --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_mmc.h @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_MMC_H_ +#define _FSL_MMC_H_ + +#include "fsl_sdmmc_common.h" + +/*! + * @addtogroup MMCCARD + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief MMC card flags */ +enum _mmc_card_flag +{ + kMMC_SupportHighSpeed26MHZFlag = (1U << 0U), /*!< Support high speed 26MHZ */ + kMMC_SupportHighSpeed52MHZFlag = (1U << 1U), /*!< Support high speed 52MHZ */ + kMMC_SupportHighSpeedDDR52MHZ180V300VFlag = (1 << 2U), /*!< ddr 52MHZ 1.8V or 3.0V */ + kMMC_SupportHighSpeedDDR52MHZ120VFlag = (1 << 3U), /*!< DDR 52MHZ 1.2V */ + kMMC_SupportHS200200MHZ180VFlag = (1 << 4U), /*!< HS200 ,200MHZ,1.8V */ + kMMC_SupportHS200200MHZ120VFlag = (1 << 5U), /*!< HS200, 200MHZ, 1.2V */ + kMMC_SupportHS400DDR200MHZ180VFlag = (1 << 6U), /*!< HS400, DDR, 200MHZ,1.8V */ + kMMC_SupportHS400DDR200MHZ120VFlag = (1 << 7U), /*!< HS400, DDR, 200MHZ,1.2V */ + kMMC_SupportHighCapacityFlag = (1U << 8U), /*!< Support high capacity */ + kMMC_SupportAlternateBootFlag = (1U << 9U), /*!< Support alternate boot */ + kMMC_SupportDDRBootFlag = (1U << 10U), /*!< support DDR boot flag*/ + kMMC_SupportHighSpeedBootFlag = (1U << 11U), /*!< support high speed boot flag*/ +}; + +/*! + * @brief mmc card state + * + * Define the card structure including the necessary fields to identify and describe the card. + */ +typedef struct _mmc_card +{ + SDMMCHOST_CONFIG host; /*!< Host information */ + mmccard_usr_param_t usrParam; /*!< user parameter */ + + bool isHostReady; /*!< Use this flag to indicate if need host re-init or not*/ + bool noInteralAlign; /*!< use this flag to disable sdmmc align. If disable, sdmmc will not make sure the + data buffer address is word align, otherwise all the transfer are align to low level driver */ + uint32_t busClock_Hz; /*!< MMC bus clock united in Hz */ + uint32_t relativeAddress; /*!< Relative address of the card */ + bool enablePreDefinedBlockCount; /*!< Enable PRE-DEFINED block count when read/write */ + uint32_t flags; /*!< Capability flag in _mmc_card_flag */ + uint32_t rawCid[4U]; /*!< Raw CID content */ + uint32_t rawCsd[4U]; /*!< Raw CSD content */ + uint32_t rawExtendedCsd[MMC_EXTENDED_CSD_BYTES / 4U]; /*!< Raw MMC Extended CSD content */ + uint32_t ocr; /*!< Raw OCR content */ + mmc_cid_t cid; /*!< CID */ + mmc_csd_t csd; /*!< CSD */ + mmc_extended_csd_t extendedCsd; /*!< Extended CSD */ + uint32_t blockSize; /*!< Card block size */ + uint32_t userPartitionBlocks; /*!< Card total block number in user partition */ + uint32_t bootPartitionBlocks; /*!< Boot partition size united as block size */ + uint32_t eraseGroupBlocks; /*!< Erase group size united as block size */ + mmc_access_partition_t currentPartition; /*!< Current access partition */ + mmc_voltage_window_t hostVoltageWindowVCCQ; /*!< Host IO voltage window */ + mmc_voltage_window_t hostVoltageWindowVCC; /*!< application must set this value according to board specific */ + mmc_high_speed_timing_t busTiming; /*!< indicate the current work timing mode*/ + mmc_data_bus_width_t busWidth; /*!< indicate the current work bus width */ +} mmc_card_t; + +/************************************************************************************************* + * API + ************************************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name MMCCARD Function + * @{ + */ + +/*! + * @brief Initializes the MMC card and host. + * + * @param card Card descriptor. + * + * @retval kStatus_SDMMC_HostNotReady host is not ready. + * @retval kStatus_SDMMC_GoIdleFailed Go idle failed. + * @retval kStatus_SDMMC_SendOperationConditionFailed Send operation condition failed. + * @retval kStatus_SDMMC_AllSendCidFailed Send CID failed. + * @retval kStatus_SDMMC_SetRelativeAddressFailed Set relative address failed. + * @retval kStatus_SDMMC_SendCsdFailed Send CSD failed. + * @retval kStatus_SDMMC_CardNotSupport Card not support. + * @retval kStatus_SDMMC_SelectCardFailed Send SELECT_CARD command failed. + * @retval kStatus_SDMMC_SendExtendedCsdFailed Send EXT_CSD failed. + * @retval kStatus_SDMMC_SetBusWidthFailed Set bus width failed. + * @retval kStatus_SDMMC_SwitchHighSpeedFailed Switch high speed failed. + * @retval kStatus_SDMMC_SetCardBlockSizeFailed Set card block size failed. + * @retval kStatus_Success Operate successfully. + */ +status_t MMC_Init(mmc_card_t *card); + +/*! + * @brief Deinitializes the card and host. + * + * @param card Card descriptor. + */ +void MMC_Deinit(mmc_card_t *card); + +/*! + * @brief intialize the card. + * + * @param card Card descriptor. + * + * @retval kStatus_SDMMC_HostNotReady host is not ready. + * @retval kStatus_SDMMC_GoIdleFailed Go idle failed. + * @retval kStatus_SDMMC_SendOperationConditionFailed Send operation condition failed. + * @retval kStatus_SDMMC_AllSendCidFailed Send CID failed. + * @retval kStatus_SDMMC_SetRelativeAddressFailed Set relative address failed. + * @retval kStatus_SDMMC_SendCsdFailed Send CSD failed. + * @retval kStatus_SDMMC_CardNotSupport Card not support. + * @retval kStatus_SDMMC_SelectCardFailed Send SELECT_CARD command failed. + * @retval kStatus_SDMMC_SendExtendedCsdFailed Send EXT_CSD failed. + * @retval kStatus_SDMMC_SetBusWidthFailed Set bus width failed. + * @retval kStatus_SDMMC_SwitchHighSpeedFailed Switch high speed failed. + * @retval kStatus_SDMMC_SetCardBlockSizeFailed Set card block size failed. + * @retval kStatus_Success Operate successfully. + */ +status_t MMC_CardInit(mmc_card_t *card); + +/*! + * @brief Deinitializes the card. + * + * @param card Card descriptor. + */ +void MMC_CardDeinit(mmc_card_t *card); + +/*! + * @brief initialize the host. + * + * This function deinitializes the specific host. + * + * @param card Card descriptor. + */ +status_t MMC_HostInit(mmc_card_t *card); + +/*! + * @brief Deinitializes the host. + * + * This function deinitializes the host. + * + * @param card Card descriptor. + */ +void MMC_HostDeinit(mmc_card_t *card); + +/*! + * @brief reset the host. + * + * This function reset the specific host. + * + * @param host host descriptor. + */ +void MMC_HostReset(SDMMCHOST_CONFIG *host); + +/*! + * @brief power on card. + * + * The power on operation depend on host or the user define power on function. + * @param base host base address. + * @param pwr user define power control configuration + */ +void MMC_PowerOnCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr); + +/*! + * @brief power off card. + * + * The power off operation depend on host or the user define power on function. + * @param base host base address. + * @param pwr user define power control configuration + */ +void MMC_PowerOffCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr); + +/*! + * @brief Checks if the card is read-only. + * + * @param card Card descriptor. + * @retval true Card is read only. + * @retval false Card isn't read only. + */ +bool MMC_CheckReadOnly(mmc_card_t *card); + +/*! + * @brief Reads data blocks from the card. + * + * @param card Card descriptor. + * @param buffer The buffer to save data. + * @param startBlock The start block index. + * @param blockCount The number of blocks to read. + * @retval kStatus_InvalidArgument Invalid argument. + * @retval kStatus_SDMMC_CardNotSupport Card not support. + * @retval kStatus_SDMMC_SetBlockCountFailed Set block count failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_StopTransmissionFailed Stop transmission failed. + * @retval kStatus_Success Operate successfully. + */ +status_t MMC_ReadBlocks(mmc_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockCount); + +/*! + * @brief Writes data blocks to the card. + * + * @param card Card descriptor. + * @param buffer The buffer to save data blocks. + * @param startBlock Start block number to write. + * @param blockCount Block count. + * @retval kStatus_InvalidArgument Invalid argument. + * @retval kStatus_SDMMC_NotSupportYet Not support now. + * @retval kStatus_SDMMC_SetBlockCountFailed Set block count failed. + * @retval kStatus_SDMMC_WaitWriteCompleteFailed Send status failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_StopTransmissionFailed Stop transmission failed. + * @retval kStatus_Success Operate successfully. + */ +status_t MMC_WriteBlocks(mmc_card_t *card, const uint8_t *buffer, uint32_t startBlock, uint32_t blockCount); + +/*! + * @brief Erases groups of the card. + * + * Erase group is the smallest erase unit in MMC card. The erase range is [startGroup, endGroup]. + * + * @param card Card descriptor. + * @param startGroup Start group number. + * @param endGroup End group number. + * @retval kStatus_InvalidArgument Invalid argument. + * @retval kStatus_SDMMC_WaitWriteCompleteFailed Send status failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t MMC_EraseGroups(mmc_card_t *card, uint32_t startGroup, uint32_t endGroup); + +/*! + * @brief Selects the partition to access. + * + * @param card Card descriptor. + * @param partitionNumber The partition number. + * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure EXT_CSD failed. + * @retval kStatus_Success Operate successfully. + */ +status_t MMC_SelectPartition(mmc_card_t *card, mmc_access_partition_t partitionNumber); + +/*! + * @brief Configures the boot activity of the card. + * + * @param card Card descriptor. + * @param config Boot configuration structure. + * @retval kStatus_SDMMC_NotSupportYet Not support now. + * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure EXT_CSD failed. + * @retval kStatus_SDMMC_ConfigureBootFailed Configure boot failed. + * @retval kStatus_Success Operate successfully. + */ +status_t MMC_SetBootConfig(mmc_card_t *card, const mmc_boot_config_t *config); + +/*! + * @brief MMC card start boot. + * + * @param card Card descriptor. + * @param mmcConfig mmc Boot configuration structure. + * @param buffer address to recieve data. + * @param hostConfig host boot configurations. + * @retval kStatus_Fail fail. + * @retval kStatus_SDMMC_TransferFailed transfer fail. + * @retval kStatus_SDMMC_GoIdleFailed reset card fail. + * @retval kStatus_Success Operate successfully. + */ +status_t MMC_StartBoot(mmc_card_t *card, + const mmc_boot_config_t *mmcConfig, + uint8_t *buffer, + SDMMCHOST_BOOT_CONFIG *hostConfig); + +/*! + * @brief MMC card set boot configuration write protect. + * + * @param card Card descriptor. + * @param wp write protect value. + */ +status_t MMC_SetBootConfigWP(mmc_card_t *card, uint8_t wp); + +/*! + * @brief MMC card continous read boot data. + * + * @param card Card descriptor. + * @param buffer buffer address. + * @param hostConfig host boot configurations. + */ +status_t MMC_ReadBootData(mmc_card_t *card, uint8_t *buffer, SDMMCHOST_BOOT_CONFIG *hostConfig); + +/*! + * @brief MMC card stop boot mode. + * + * @param card Card descriptor. + * @param bootMode boot mode. + */ +status_t MMC_StopBoot(mmc_card_t *card, uint32_t bootMode); + +/*! + * @brief MMC card set boot partition write protect. + * + * @param card Card descriptor. + * @param bootPartitionWP boot partition write protect value. + */ +status_t MMC_SetBootPartitionWP(mmc_card_t *card, mmc_boot_partition_wp_t bootPartitionWP); + +/* @} */ +#if defined(__cplusplus) +} +#endif +/*! @} */ +#endif /* _FSL_MMC_H_*/ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sd.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sd.h new file mode 100644 index 000000000..ae19da5e2 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sd.h @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_SD_H_ +#define _FSL_SD_H_ + +#include "fsl_sdmmc_common.h" +/*! + * @addtogroup SDCARD + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief SD card flags */ +enum _sd_card_flag +{ + kSD_SupportHighCapacityFlag = (1U << 1U), /*!< Support high capacity */ + kSD_Support4BitWidthFlag = (1U << 2U), /*!< Support 4-bit data width */ + kSD_SupportSdhcFlag = (1U << 3U), /*!< Card is SDHC */ + kSD_SupportSdxcFlag = (1U << 4U), /*!< Card is SDXC */ + kSD_SupportVoltage180v = (1U << 5U), /*!< card support 1.8v voltage*/ + kSD_SupportSetBlockCountCmd = (1U << 6U), /*!< card support cmd23 flag*/ + kSD_SupportSpeedClassControlCmd = (1U << 7U), /*!< card support speed class control flag */ +}; + +/*! + * @brief SD card state + * + * Define the card structure including the necessary fields to identify and describe the card. + */ +typedef struct _sd_card +{ + SDMMCHOST_CONFIG host; /*!< Host information */ + + sdcard_usr_param_t usrParam; /*!< user parameter */ + bool isHostReady; /*!< use this flag to indicate if need host re-init or not*/ + bool noInteralAlign; /*!< use this flag to disable sdmmc align. If disable, sdmmc will not make sure the + data buffer address is word align, otherwise all the transfer are align to low level driver */ + uint32_t busClock_Hz; /*!< SD bus clock frequency united in Hz */ + uint32_t relativeAddress; /*!< Relative address of the card */ + uint32_t version; /*!< Card version */ + uint32_t flags; /*!< Flags in _sd_card_flag */ + uint32_t rawCid[4U]; /*!< Raw CID content */ + uint32_t rawCsd[4U]; /*!< Raw CSD content */ + uint32_t rawScr[2U]; /*!< Raw CSD content */ + uint32_t ocr; /*!< Raw OCR content */ + sd_cid_t cid; /*!< CID */ + sd_csd_t csd; /*!< CSD */ + sd_scr_t scr; /*!< SCR */ + sd_status_t stat; /*!< sd 512 bit status */ + uint32_t blockCount; /*!< Card total block number */ + uint32_t blockSize; /*!< Card block size */ + sd_timing_mode_t currentTiming; /*!< current timing mode */ + sd_driver_strength_t driverStrength; /*!< driver strength */ + sd_max_current_t maxCurrent; /*!< card current limit */ + sdmmc_operation_voltage_t operationVoltage; /*!< card operation voltage */ +} sd_card_t; + +/************************************************************************************************* + * API + ************************************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name SDCARD Function + * @{ + */ + +/*! + * @brief Initializes the card on a specific host controller. + * @deprecated Do not use this function. It has been superceded by @ref SD_HostInit,SD_CardInit. + + * This function initializes the card on a specific host controller, it is consist of + * host init, card detect, card init function, however user can ignore this high level function, + * instead of use the low level function, such as SD_CardInit, SD_HostInit, SD_CardDetect. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_HostNotReady host is not ready. + * @retval kStatus_SDMMC_GoIdleFailed Go idle failed. + * @retval kStatus_SDMMC_NotSupportYet Card not support. + * @retval kStatus_SDMMC_SendOperationConditionFailed Send operation condition failed. + * @retval kStatus_SDMMC_AllSendCidFailed Send CID failed. + * @retval kStatus_SDMMC_SendRelativeAddressFailed Send relative address failed. + * @retval kStatus_SDMMC_SendCsdFailed Send CSD failed. + * @retval kStatus_SDMMC_SelectCardFailed Send SELECT_CARD command failed. + * @retval kStatus_SDMMC_SendScrFailed Send SCR failed. + * @retval kStatus_SDMMC_SetBusWidthFailed Set bus width failed. + * @retval kStatus_SDMMC_SwitchHighSpeedFailed Switch high speed failed. + * @retval kStatus_SDMMC_SetCardBlockSizeFailed Set card block size failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SD_Init(sd_card_t *card); + +/*! + * @brief Deinitializes the card. + * @deprecated Do not use this function. It has been superceded by @ref SD_HostDeinit,SD_CardDeinit. + * This function deinitializes the specific card and host. + * + * @param card Card descriptor. + */ +void SD_Deinit(sd_card_t *card); + +/*! + * @brief Initializes the card. + * + * This function initializes the card only, make sure the host is ready when call this function, + * otherwise it will return kStatus_SDMMC_HostNotReady. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_HostNotReady host is not ready. + * @retval kStatus_SDMMC_GoIdleFailed Go idle failed. + * @retval kStatus_SDMMC_NotSupportYet Card not support. + * @retval kStatus_SDMMC_SendOperationConditionFailed Send operation condition failed. + * @retval kStatus_SDMMC_AllSendCidFailed Send CID failed. + * @retval kStatus_SDMMC_SendRelativeAddressFailed Send relative address failed. + * @retval kStatus_SDMMC_SendCsdFailed Send CSD failed. + * @retval kStatus_SDMMC_SelectCardFailed Send SELECT_CARD command failed. + * @retval kStatus_SDMMC_SendScrFailed Send SCR failed. + * @retval kStatus_SDMMC_SetBusWidthFailed Set bus width failed. + * @retval kStatus_SDMMC_SwitchHighSpeedFailed Switch high speed failed. + * @retval kStatus_SDMMC_SetCardBlockSizeFailed Set card block size failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SD_CardInit(sd_card_t *card); + +/*! + * @brief Deinitializes the card. + * + * This function deinitializes the specific card. + * + * @param card Card descriptor. + */ +void SD_CardDeinit(sd_card_t *card); + +/*! + * @brief initialize the host. + * + * This function deinitializes the specific host. + * + * @param card Card descriptor. + */ +status_t SD_HostInit(sd_card_t *card); + +/*! + * @brief Deinitializes the host. + * + * This function deinitializes the host. + * + * @param card Card descriptor. + */ +void SD_HostDeinit(sd_card_t *card); + +/*! + * @brief reset the host. + * + * This function reset the specific host. + * + * @param host host descriptor. + */ +void SD_HostReset(SDMMCHOST_CONFIG *host); + +/*! + * @brief power on card. + * + * The power on operation depend on host or the user define power on function. + * @param base host base address. + * @param pwr user define power control configuration + */ +void SD_PowerOnCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr); + +/*! + * @brief power off card. + * + * The power off operation depend on host or the user define power on function. + * @param base host base address. + * @param pwr user define power control configuration + */ +void SD_PowerOffCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr); + +/*! + * @brief sd wait card detect function. + * + * Detect card through GPIO, CD, DATA3. + * + * @param card card descriptor. + * @param card detect configuration + * @param waitCardStatus wait card detect status + */ +status_t SD_WaitCardDetectStatus(SDMMCHOST_TYPE *hostBase, const sdmmchost_detect_card_t *cd, bool waitCardStatus); + +/*! + * @brief sd card present check function. + * + * @param card card descriptor. + */ +bool SD_IsCardPresent(sd_card_t *card); + +/*! + * @brief Checks whether the card is write-protected. + * + * This function checks if the card is write-protected via the CSD register. + * + * @param card The specific card. + * @retval true Card is read only. + * @retval false Card isn't read only. + */ +bool SD_CheckReadOnly(sd_card_t *card); + +/*! + * @brief Send SELECT_CARD command to set the card to be transfer state or not. + * + * @param card Card descriptor. + * @param isSelected True to set the card into transfer state, false to disselect. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SD_SelectCard(sd_card_t *card, bool isSelected); + +/*! + * @brief Send ACMD13 to get the card current status. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_SendApplicationCommandFailed send application command failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SD_ReadStatus(sd_card_t *card); + +/*! + * @brief Reads blocks from the specific card. + * + * This function reads blocks from the specific card with default block size defined by the + * SDHC_CARD_DEFAULT_BLOCK_SIZE. + * + * @param card Card descriptor. + * @param buffer The buffer to save the data read from card. + * @param startBlock The start block index. + * @param blockCount The number of blocks to read. + * @retval kStatus_InvalidArgument Invalid argument. + * @retval kStatus_SDMMC_CardNotSupport Card not support. + * @retval kStatus_SDMMC_NotSupportYet Not support now. + * @retval kStatus_SDMMC_WaitWriteCompleteFailed Send status failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_StopTransmissionFailed Stop transmission failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SD_ReadBlocks(sd_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockCount); + +/*! + * @brief Writes blocks of data to the specific card. + * + * This function writes blocks to the specific card with default block size 512 bytes. + * + * @param card Card descriptor. + * @param buffer The buffer holding the data to be written to the card. + * @param startBlock The start block index. + * @param blockCount The number of blocks to write. + * @retval kStatus_InvalidArgument Invalid argument. + * @retval kStatus_SDMMC_NotSupportYet Not support now. + * @retval kStatus_SDMMC_CardNotSupport Card not support. + * @retval kStatus_SDMMC_WaitWriteCompleteFailed Send status failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_StopTransmissionFailed Stop transmission failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SD_WriteBlocks(sd_card_t *card, const uint8_t *buffer, uint32_t startBlock, uint32_t blockCount); + +/*! + * @brief Erases blocks of the specific card. + * + * This function erases blocks of the specific card with default block size 512 bytes. + * + * @param card Card descriptor. + * @param startBlock The start block index. + * @param blockCount The number of blocks to erase. + * @retval kStatus_InvalidArgument Invalid argument. + * @retval kStatus_SDMMC_WaitWriteCompleteFailed Send status failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_WaitWriteCompleteFailed Send status failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SD_EraseBlocks(sd_card_t *card, uint32_t startBlock, uint32_t blockCount); + +/*! + * @brief select card driver strength + * select card driver strength + * @param card Card descriptor. + * @param driverStrength Driver strength + */ +status_t SD_SetDriverStrength(sd_card_t *card, sd_driver_strength_t driverStrength); + +/*! + * @brief select max current + * select max operation current + * @param card Card descriptor. + * @param maxCurrent Max current + */ +status_t SD_SetMaxCurrent(sd_card_t *card, sd_max_current_t maxCurrent); + +/* @} */ + +#if defined(__cplusplus) +} +#endif +/*! @} */ +#endif /* _FSL_SD_H_*/ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdio.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdio.h new file mode 100644 index 000000000..2998fa7a2 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdio.h @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_SDIO_H_ +#define _FSL_SDIO_H_ + +#include "fsl_sdmmc_common.h" + +/*! + * @addtogroup SDIOCARD + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief Middleware version. */ +#define FSL_SDIO_DRIVER_VERSION (MAKE_VERSION(2U, 2U, 11U)) /*2.2.11*/ + +/*!@brief sdio device support maximum IO number */ +#ifndef FSL_SDIO_MAX_IO_NUMS +#define FSL_SDIO_MAX_IO_NUMS (7U) +#endif +/*!@brief sdio card descriptor */ +typedef struct _sdio_card sdio_card_t; +/*!@brief sdio io handler */ +typedef void (*sdio_io_irq_handler_t)(sdio_card_t *card, uint32_t func); +/*! @brief sdio io read/write direction */ +typedef enum _sdio_io_direction +{ + kSDIO_IORead = 0U, /*!< io read */ + kSDIO_IOWrite = 1U, /*!< io write */ +} sdio_io_direction_t; + +/*! + * @brief SDIO card state + * + * Define the card structure including the necessary fields to identify and describe the card. + */ +struct _sdio_card +{ + SDMMCHOST_CONFIG host; /*!< Host information */ + sdiocard_usr_param_t usrParam; /*!< user parameter */ + bool noInternalAlign; /*!< use this flag to disable sdmmc align. If disable, sdmmc will not make sure the + data buffer address is word align, otherwise all the transfer are align to low level driver */ + bool isHostReady; /*!< use this flag to indicate if need host re-init or not*/ + bool memPresentFlag; /*!< indicate if memory present */ + + uint32_t busClock_Hz; /*!< SD bus clock frequency united in Hz */ + uint32_t relativeAddress; /*!< Relative address of the card */ + uint8_t sdVersion; /*!< SD version */ + sd_timing_mode_t currentTiming; /*!< current timing mode */ + sd_driver_strength_t driverStrength; /*!< driver strength */ + sd_max_current_t maxCurrent; /*!< card current limit */ + sdmmc_operation_voltage_t operationVoltage; /*!< card operation voltage */ + + uint8_t sdioVersion; /*!< SDIO version */ + uint8_t cccrVersioin; /*!< CCCR version */ + uint8_t ioTotalNumber; /*!< total number of IO function */ + uint32_t cccrflags; /*!< Flags in _sd_card_flag */ + uint32_t io0blockSize; /*!< record the io0 block size*/ + uint32_t ocr; /*!< Raw OCR content, only 24bit avalible for SDIO card */ + uint32_t commonCISPointer; /*!< point to common CIS */ + sdio_common_cis_t commonCIS; /*!< CIS table */ + + /* io registers/IRQ handler */ + sdio_fbr_t ioFBR[FSL_SDIO_MAX_IO_NUMS]; /*!< FBR table */ + sdio_func_cis_t funcCIS[FSL_SDIO_MAX_IO_NUMS]; /*!< function CIS table*/ + sdio_io_irq_handler_t ioIRQHandler[FSL_SDIO_MAX_IO_NUMS]; /*!< io IRQ handler */ + uint8_t ioIntIndex; /*!< used to record current enabled io interrupt index */ + uint8_t ioIntNums; /*!< used to record total enabled io interrupt numbers */ +}; + +/************************************************************************************************* + * API + ************************************************************************************************/ +#if defined(__cplusplus) +extern "C" +{ +#endif +/*! + * @name Initialization and deinitialization + * @{ + */ + +/*! + * @brief SDIO card init function + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_GoIdleFailed + * @retval kStatus_SDMMC_HandShakeOperationConditionFailed + * @retval kStatus_SDMMC_SDIO_InvalidCard + * @retval kStatus_SDMMC_SDIO_InvalidVoltage + * @retval kStatus_SDMMC_SendRelativeAddressFailed + * @retval kStatus_SDMMC_SelectCardFailed + * @retval kStatus_SDMMC_SDIO_SwitchHighSpeedFail + * @retval kStatus_SDMMC_SDIO_ReadCISFail + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_Init(sdio_card_t *card); + +/*! + * @brief SDIO card deinit, include card and host deinit. + * + * @param card Card descriptor. + */ +void SDIO_Deinit(sdio_card_t *card); + +/*! + * @brief Initializes the card. + * + * This function initializes the card only, make sure the host is ready when call this function, + * otherwise it will return kStatus_SDMMC_HostNotReady. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_HostNotReady host is not ready. + * @retval kStatus_SDMMC_GoIdleFailed Go idle failed. + * @retval kStatus_SDMMC_NotSupportYet Card not support. + * @retval kStatus_SDMMC_SendOperationConditionFailed Send operation condition failed. + * @retval kStatus_SDMMC_AllSendCidFailed Send CID failed. + * @retval kStatus_SDMMC_SendRelativeAddressFailed Send relative address failed. + * @retval kStatus_SDMMC_SendCsdFailed Send CSD failed. + * @retval kStatus_SDMMC_SelectCardFailed Send SELECT_CARD command failed. + * @retval kStatus_SDMMC_SendScrFailed Send SCR failed. + * @retval kStatus_SDMMC_SetBusWidthFailed Set bus width failed. + * @retval kStatus_SDMMC_SwitchHighSpeedFailed Switch high speed failed. + * @retval kStatus_SDMMC_SetCardBlockSizeFailed Set card block size failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SDIO_CardInit(sdio_card_t *card); + +/*! + * @brief Deinitializes the card. + * + * This function deinitializes the specific card. + * + * @param card Card descriptor. + */ +void SDIO_CardDeinit(sdio_card_t *card); + +/*! + * @brief initialize the host. + * + * This function deinitializes the specific host. + * + * @param card Card descriptor. + */ +status_t SDIO_HostInit(sdio_card_t *card); + +/*! + * @brief Deinitializes the host. + * + * This function deinitializes the host. + * + * @param card Card descriptor. + */ +void SDIO_HostDeinit(sdio_card_t *card); + +/*! + * @brief reset the host. + * + * This function reset the specific host. + * + * @param host host descriptor. + */ +void SDIO_HostReset(SDMMCHOST_CONFIG *host); + +/*! + * @brief power on card. + * + * The power on operation depend on host or the user define power on function. + * @param base host base address. + * @param pwr user define power control configuration + */ +void SDIO_PowerOnCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr); + +/*! + * @brief power on card. + * + * The power off operation depend on host or the user define power on function. + * @param base host base address. + * @param pwr user define power control configuration + */ +void SDIO_PowerOffCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr); + +/*! + * @brief set SDIO card to inactive state + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_CardInActive(sdio_card_t *card); + +/*! + * @brief get SDIO card capability + * + * @param card Card descriptor. + * @param function IO number + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_GetCardCapability(sdio_card_t *card, sdio_func_num_t func); + +/*! + * @brief set SDIO card block size + * + * @param card Card descriptor. + * @param function io number + * @param block size + * @retval kStatus_SDMMC_SetCardBlockSizeFailed + * @retval kStatus_SDMMC_SDIO_InvalidArgument + * @retval kStatus_Success + */ +status_t SDIO_SetBlockSize(sdio_card_t *card, sdio_func_num_t func, uint32_t blockSize); + +/*! + * @brief set SDIO card reset + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_CardReset(sdio_card_t *card); + +/*! + * @brief set SDIO card data bus width + * + * @param card Card descriptor. + * @param data bus width + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_SetDataBusWidth(sdio_card_t *card, sdio_bus_width_t busWidth); + +/*! + * @brief switch the card to high speed + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_SDMMC_SDIO_SwitchHighSpeedFail + * @retval kStatus_Success + */ +status_t SDIO_SwitchToHighSpeed(sdio_card_t *card); + +/*! + * @brief read SDIO card CIS for each function + * + * @param card Card descriptor. + * @param function io number + * @param tuple code list + * @param tuple code number + * @retval kStatus_SDMMC_SDIO_ReadCISFail + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_ReadCIS(sdio_card_t *card, sdio_func_num_t func, const uint32_t *tupleList, uint32_t tupleNum); + +/*! + * @brief sdio wait card detect function. + * + * Detect card through GPIO, CD, DATA3. + * + * @param card card descriptor. + * @param card detect configuration + * @param waitCardStatus wait card detect status + */ +status_t SDIO_WaitCardDetectStatus(SDMMCHOST_TYPE *hostBase, + const sdmmchost_detect_card_t *cd, + bool waitCardStatus); + +/*! + * @brief sdio card present check function. + * + * @param card card descriptor. + */ +bool SDIO_IsCardPresent(sdio_card_t *card); + +/* @} */ + +/*! + * @name IO operations + * @{ + */ + +/*! + * @brief IO direct write transfer function + * + * @param card Card descriptor. + * @param function IO numner + * @param register address + * @param the data pinter to write + * @param raw flag, indicate read after write or write only + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_IO_Write_Direct(sdio_card_t *card, sdio_func_num_t func, uint32_t regAddr, uint8_t *data, bool raw); + +/*! + * @brief IO direct read transfer function + * + * @param card Card descriptor. + * @param function IO number + * @param register address + * @param data pointer to read + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_IO_Read_Direct(sdio_card_t *card, sdio_func_num_t func, uint32_t regAddr, uint8_t *data); + +/*! + * @brief IO direct read/write transfer function + * + * @param card Card descriptor. + * @param direction io access direction, please reference sdio_io_direction_t. + * @param function IO number + * @param register address + * @param dataIn data to write + * @param dataOut data pointer for readback data, support both for read and write, when application want readback + * the data after write command, dataOut should not be NULL. + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ + +status_t SDIO_IO_RW_Direct(sdio_card_t *card, + sdio_io_direction_t direction, + sdio_func_num_t func, + uint32_t regAddr, + uint8_t dataIn, + uint8_t *dataOut); + +/*! + * @brief IO extended write transfer function + * + * @param card Card descriptor. + * @param function IO number + * @param register address + * @param data buffer to write + * @param data count + * @param write flags + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_SDMMC_SDIO_InvalidArgument + * @retval kStatus_Success + */ +status_t SDIO_IO_Write_Extended( + sdio_card_t *card, sdio_func_num_t func, uint32_t regAddr, uint8_t *buffer, uint32_t count, uint32_t flags); +/*! + * @brief IO extended read transfer function + * + * @param card Card descriptor. + * @param function IO number + * @param register address + * @param data buffer to read + * @param data count + * @param write flags + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_SDMMC_SDIO_InvalidArgument + * @retval kStatus_Success + */ +status_t SDIO_IO_Read_Extended( + sdio_card_t *card, sdio_func_num_t func, uint32_t regAddr, uint8_t *buffer, uint32_t count, uint32_t flags); +/*! + * @brief enable IO interrupt + * + * @param card Card descriptor. + * @param function IO number + * @param enable/disable flag + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_EnableIOInterrupt(sdio_card_t *card, sdio_func_num_t func, bool enable); + +/*! + * @brief enable IO and wait IO ready + * + * @param card Card descriptor. + * @param function IO number + * @param enable/disable flag + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_EnableIO(sdio_card_t *card, sdio_func_num_t func, bool enable); + +/*! + * @brief select IO + * + * @param card Card descriptor. + * @param function IO number + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_SelectIO(sdio_card_t *card, sdio_func_num_t func); + +/*! + * @brief Abort IO transfer + * + * @param card Card descriptor. + * @param function IO number + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_AbortIO(sdio_card_t *card, sdio_func_num_t func); + +/*! + * @brief Set driver strength. + * + * @param card Card descriptor. + * @param driverStrength target driver strength. + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_SetDriverStrength(sdio_card_t *card, sd_driver_strength_t driverStrength); + +/*! + * @brief Enable/Disable Async interrupt. + * + * @param card Card descriptor. + * @param func function io number. + * @param enable true is enable, false is disable. + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_EnableAsyncInterrupt(sdio_card_t *card, bool enable); + +/*! + * @brief Get pending interrupt. + * + * @param card Card descriptor. + * @param pendingInt pointer store pending interrupt + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_GetPendingInterrupt(sdio_card_t *card, uint8_t *pendingInt); + +/*! + * @brief sdio card io transfer function. + * This function can be used for trnansfer direct/extend command. + * Please pay attention to the non-align data buffer address transfer, + * if data buffer address can not meet host controller internal DMA requirement, sdio driver will try to use + internal align buffer if data size is not bigger than internal buffer size, + * Align address transfer always can get a better performance, so if application want sdio driver make sure buffer + address align, + * please redefine the SDMMC_GLOBAL_BUFFER_SIZE macro to a value which is big enough for your application. + * + * @param card card descriptor. + * @param cmd command to transfer + * @param argument argument to transfer + * @param blockSize used for block mode. + * @param txData tx buffer pointer or NULL + * @param rxData rx buffer pointer or NULL + * @param dataSize transfer data size + * @param response reponse pointer, if application want read response back, please set it to a NON-NULL pointer. + + */ +status_t SDIO_IO_Transfer(sdio_card_t *card, + sdio_command_t cmd, + uint32_t argument, + uint32_t blockSize, + uint8_t *txData, + uint8_t *rxData, + uint16_t dataSize, + uint32_t *response); + +/*! + * @brief sdio set io IRQ handler. + * + * @param card card descriptor. + * @param func function io number. + * @param handler, io IRQ handler. + */ +void SDIO_SetIOIRQHandler(sdio_card_t *card, sdio_func_num_t func, sdio_io_irq_handler_t handler); + +/*! + * @brief sdio card io pending interrupt handle function. + * This function is used to handle the pending io interrupt. + * To reigster a IO IRQ handler, + * @code + * //initialization + * SDIO_EnableIOInterrupt(card, 0, true); + * SDIO_SetIOIRQHandler(card, 0, func0_handler); + * //call it in interrupt callback + * SDIO_HandlePendingIOInterrupt(card); + * @code + * To releae a IO IRQ handler, + * @code + * SDIO_EnableIOInterrupt(card, 0, false); + * SDIO_SetIOIRQHandler(card, 0, NULL); + * @code + * @param card card descriptor. + * + * @retval kStatus_SDMMC_TransferFailed + * @retval kStatus_Success + */ +status_t SDIO_HandlePendingIOInterrupt(sdio_card_t *card); + +/* @} */ + +#if defined(__cplusplus) +} +#endif +/*! @} */ +#endif /* _FSL_SDIO_H_*/ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdmmc_common.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdmmc_common.h new file mode 100644 index 000000000..a8e52e0bf --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdmmc_common.h @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_SDMMC_COMMON_H_ +#define _FSL_SDMMC_COMMON_H_ + +#include "fsl_common.h" +#include "fsl_sdmmc_host.h" +#include "fsl_sdmmc_spec.h" +#include "stdlib.h" + +/*! + * @addtogroup CARD + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief Middleware version. */ +#define FSL_SDMMC_DRIVER_VERSION (MAKE_VERSION(2U, 2U, 11U)) /*2.2.11*/ + +/*! @brief Reverse byte sequence in uint32_t */ +#define SWAP_WORD_BYTE_SEQUENCE(x) (__REV(x)) +/*! @brief Reverse byte sequence for each half word in uint32_t */ +#define SWAP_HALF_WROD_BYTE_SEQUENCE(x) (__REV16(x)) +/*! @brief Maximum loop count to check the card operation voltage range */ +#define FSL_SDMMC_MAX_VOLTAGE_RETRIES (1000U) +/*! @brief Maximum loop count to send the cmd */ +#define FSL_SDMMC_MAX_CMD_RETRIES (10U) +/*! @brief Default block size */ +#define FSL_SDMMC_DEFAULT_BLOCK_SIZE (512U) +#ifndef SDMMC_GLOBAL_BUFFER_SIZE +/*! @brief SDMMC global data buffer size, word unit*/ +#define SDMMC_GLOBAL_BUFFER_SIZE (128U) +#endif +/*! @brief SDMMC enable software tuning */ +#define SDMMC_ENABLE_SOFTWARE_TUNING (0U) +/* Common definition for cache line size align */ +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL +#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) +#if defined(FSL_FEATURE_L2DCACHE_LINESIZE_BYTE) +#define SDMMC_DATA_BUFFER_ALIGN_CACHE MAX(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE, FSL_FEATURE_L2DCACHE_LINESIZE_BYTE) +#else +#define SDMMC_DATA_BUFFER_ALIGN_CACHE FSL_FEATURE_L1DCACHE_LINESIZE_BYTE +#endif +#else +#define SDMMC_DATA_BUFFER_ALIGN_CACHE 1 +#endif +#else +#define SDMMC_DATA_BUFFER_ALIGN_CACHE 1 +#endif + +/*! @brief SD/MMC error log. */ +#if defined SDMMC_ENABLE_LOG_PRINT +#include "fsl_debug_console.h" +#define SDMMC_LOG(...) PRINTF(__VA_ARGS__) +#else +#define SDMMC_LOG(format, ...) +#endif + +/*! @brief SD/MMC card API's running status. */ +enum _sdmmc_status +{ + kStatus_SDMMC_NotSupportYet = MAKE_STATUS(kStatusGroup_SDMMC, 0U), /*!< Haven't supported */ + kStatus_SDMMC_TransferFailed = MAKE_STATUS(kStatusGroup_SDMMC, 1U), /*!< Send command failed */ + kStatus_SDMMC_SetCardBlockSizeFailed = MAKE_STATUS(kStatusGroup_SDMMC, 2U), /*!< Set block size failed */ + kStatus_SDMMC_HostNotSupport = MAKE_STATUS(kStatusGroup_SDMMC, 3U), /*!< Host doesn't support */ + kStatus_SDMMC_CardNotSupport = MAKE_STATUS(kStatusGroup_SDMMC, 4U), /*!< Card doesn't support */ + kStatus_SDMMC_AllSendCidFailed = MAKE_STATUS(kStatusGroup_SDMMC, 5U), /*!< Send CID failed */ + kStatus_SDMMC_SendRelativeAddressFailed = MAKE_STATUS(kStatusGroup_SDMMC, 6U), /*!< Send relative address failed */ + kStatus_SDMMC_SendCsdFailed = MAKE_STATUS(kStatusGroup_SDMMC, 7U), /*!< Send CSD failed */ + kStatus_SDMMC_SelectCardFailed = MAKE_STATUS(kStatusGroup_SDMMC, 8U), /*!< Select card failed */ + kStatus_SDMMC_SendScrFailed = MAKE_STATUS(kStatusGroup_SDMMC, 9U), /*!< Send SCR failed */ + kStatus_SDMMC_SetDataBusWidthFailed = MAKE_STATUS(kStatusGroup_SDMMC, 10U), /*!< Set bus width failed */ + kStatus_SDMMC_GoIdleFailed = MAKE_STATUS(kStatusGroup_SDMMC, 11U), /*!< Go idle failed */ + kStatus_SDMMC_HandShakeOperationConditionFailed = + MAKE_STATUS(kStatusGroup_SDMMC, 12U), /*!< Send Operation Condition failed */ + kStatus_SDMMC_SendApplicationCommandFailed = + MAKE_STATUS(kStatusGroup_SDMMC, 13U), /*!< Send application command failed */ + kStatus_SDMMC_SwitchFailed = MAKE_STATUS(kStatusGroup_SDMMC, 14U), /*!< Switch command failed */ + kStatus_SDMMC_StopTransmissionFailed = MAKE_STATUS(kStatusGroup_SDMMC, 15U), /*!< Stop transmission failed */ + kStatus_SDMMC_WaitWriteCompleteFailed = MAKE_STATUS(kStatusGroup_SDMMC, 16U), /*!< Wait write complete failed */ + kStatus_SDMMC_SetBlockCountFailed = MAKE_STATUS(kStatusGroup_SDMMC, 17U), /*!< Set block count failed */ + kStatus_SDMMC_SetRelativeAddressFailed = MAKE_STATUS(kStatusGroup_SDMMC, 18U), /*!< Set relative address failed */ + kStatus_SDMMC_SwitchBusTimingFailed = MAKE_STATUS(kStatusGroup_SDMMC, 19U), /*!< Switch high speed failed */ + kStatus_SDMMC_SendExtendedCsdFailed = MAKE_STATUS(kStatusGroup_SDMMC, 20U), /*!< Send EXT_CSD failed */ + kStatus_SDMMC_ConfigureBootFailed = MAKE_STATUS(kStatusGroup_SDMMC, 21U), /*!< Configure boot failed */ + kStatus_SDMMC_ConfigureExtendedCsdFailed = MAKE_STATUS(kStatusGroup_SDMMC, 22U), /*!< Configure EXT_CSD failed */ + kStatus_SDMMC_EnableHighCapacityEraseFailed = + MAKE_STATUS(kStatusGroup_SDMMC, 23U), /*!< Enable high capacity erase failed */ + kStatus_SDMMC_SendTestPatternFailed = MAKE_STATUS(kStatusGroup_SDMMC, 24U), /*!< Send test pattern failed */ + kStatus_SDMMC_ReceiveTestPatternFailed = MAKE_STATUS(kStatusGroup_SDMMC, 25U), /*!< Receive test pattern failed */ + kStatus_SDMMC_SDIO_ResponseError = MAKE_STATUS(kStatusGroup_SDMMC, 26U), /*!< sdio response error */ + kStatus_SDMMC_SDIO_InvalidArgument = + MAKE_STATUS(kStatusGroup_SDMMC, 27U), /*!< sdio invalid argument response error */ + kStatus_SDMMC_SDIO_SendOperationConditionFail = + MAKE_STATUS(kStatusGroup_SDMMC, 28U), /*!< sdio send operation condition fail */ + kStatus_SDMMC_InvalidVoltage = MAKE_STATUS(kStatusGroup_SDMMC, 29U), /*!< invaild voltage */ + kStatus_SDMMC_SDIO_SwitchHighSpeedFail = MAKE_STATUS(kStatusGroup_SDMMC, 30U), /*!< switch to high speed fail */ + kStatus_SDMMC_SDIO_ReadCISFail = MAKE_STATUS(kStatusGroup_SDMMC, 31U), /*!< read CIS fail */ + kStatus_SDMMC_SDIO_InvalidCard = MAKE_STATUS(kStatusGroup_SDMMC, 32U), /*!< invaild SDIO card */ + kStatus_SDMMC_TuningFail = MAKE_STATUS(kStatusGroup_SDMMC, 33U), /*!< tuning fail */ + + kStatus_SDMMC_SwitchVoltageFail = MAKE_STATUS(kStatusGroup_SDMMC, 34U), /*!< switch voltage fail*/ + kStatus_SDMMC_SwitchVoltage18VFail33VSuccess = MAKE_STATUS(kStatusGroup_SDMMC, 35U), /*!< switch voltage fail*/ + + kStatus_SDMMC_ReTuningRequest = MAKE_STATUS(kStatusGroup_SDMMC, 36U), /*!< retuning request */ + kStatus_SDMMC_SetDriverStrengthFail = MAKE_STATUS(kStatusGroup_SDMMC, 37U), /*!< set driver strength fail */ + kStatus_SDMMC_SetPowerClassFail = MAKE_STATUS(kStatusGroup_SDMMC, 38U), /*!< set power class fail */ + kStatus_SDMMC_HostNotReady = MAKE_STATUS(kStatusGroup_SDMMC, 39U), /*!< host controller not ready */ + kStatus_SDMMC_CardDetectFailed = MAKE_STATUS(kStatusGroup_SDMMC, 40U), /*!< card detect failed */ + kStatus_SDMMC_AuSizeNotSetProperly = MAKE_STATUS(kStatusGroup_SDMMC, 41U), /*!< AU size not set properly */ + +}; + +/*! @brief card operation voltage */ +typedef enum _sdmmc_operation_voltage +{ + kCARD_OperationVoltageNone = 0U, /*!< indicate current voltage setting is not setting by suser*/ + kCARD_OperationVoltage330V = 1U, /*!< card operation voltage around 3.3v */ + kCARD_OperationVoltage300V = 2U, /*!< card operation voltage around 3.0v */ + kCARD_OperationVoltage180V = 3U, /*!< card operation voltage around 1.8v */ +} sdmmc_operation_voltage_t; + +/************************************************************************************************* + * API + ************************************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif +/*! + * @name common function + * @{ + */ + +/*! + * @brief Selects the card to put it into transfer state. + * + * @param base SDMMCHOST peripheral base address. + * @param transfer SDMMCHOST transfer function. + * @param relativeAddress Relative address. + * @param isSelected True to put card into transfer state. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_SelectCard(SDMMCHOST_TYPE *base, + SDMMCHOST_TRANSFER_FUNCTION transfer, + uint32_t relativeAddress, + bool isSelected); + +/*! + * @brief Sends an application command. + * + * @param base SDMMCHOST peripheral base address. + * @param transfer SDMMCHOST transfer function. + * @param relativeAddress Card relative address. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_CardNotSupport Card doesn't support. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_SendApplicationCommand(SDMMCHOST_TYPE *base, + SDMMCHOST_TRANSFER_FUNCTION transfer, + uint32_t relativeAddress); + +/*! + * @brief Sets the block count. + * + * @param base SDMMCHOST peripheral base address. + * @param transfer SDMMCHOST transfer function. + * @param blockCount Block count. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_SetBlockCount(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer, uint32_t blockCount); + +/*! + * @brief Sets the card to be idle state. + * + * @param base SDMMCHOST peripheral base address. + * @param transfer SDMMCHOST transfer function. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_GoIdle(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer); + +/*! + * @brief Sets data block size. + * + * @param base SDMMCHOST peripheral base address. + * @param transfer SDMMCHOST transfer function. + * @param blockSize Block size. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_SetBlockSize(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer, uint32_t blockSize); + +/*! + * @brief Sets card to inactive status + * + * @param base SDMMCHOST peripheral base address. + * @param transfer SDMMCHOST transfer function. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +status_t SDMMC_SetCardInactive(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer); + +/*! + * @brief provide a simple delay function for sdmmc + * + * @param num Delay num*10000. + */ +void SDMMC_Delay(uint32_t num); + +/*! + * @brief provide a voltage switch function for SD/SDIO card + * @deprecated Do not use this function, it has been superceded by SDMMC_SwitchToVoltage. + * @param base SDMMCHOST peripheral base address. + * @param transfer SDMMCHOST transfer function. + */ +status_t SDMMC_SwitchVoltage(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer); + +/*! + * @brief provide a voltage switch function for SD/SDIO card + * + * @param base SDMMCHOST peripheral base address. + * @param transfer SDMMCHOST transfer function. + * @param switchVoltageFunc voltage switch function. + * @return error code. + */ + +status_t SDMMC_SwitchToVoltage(SDMMCHOST_TYPE *base, + SDMMCHOST_TRANSFER_FUNCTION transfer, + sdmmchost_card_switch_voltage_t switchVoltageFunc); +/*! + * @brief excute tuning + * + * @param base SDMMCHOST peripheral base address. + * @param transfer Host transfer function + * @param tuningCmd Tuning cmd + * @param blockSize Tuning block size + */ +status_t SDMMC_ExecuteTuning(SDMMCHOST_TYPE *base, + SDMMCHOST_TRANSFER_FUNCTION transfer, + uint32_t tuningCmd, + uint32_t blockSize); +/* @} */ + +#if defined(__cplusplus) +} +#endif +/* @} */ +#endif /* _FSL_SDMMC_COMMON_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdmmc_host.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdmmc_host.h new file mode 100644 index 000000000..0fca080d1 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdmmc_host.h @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_SDMMC_HOST_H +#define _FSL_SDMMC_HOST_H + +#include "fsl_common.h" +#include "board.h" +#if defined(FSL_FEATURE_SOC_SDHC_COUNT) && FSL_FEATURE_SOC_SDHC_COUNT > 0U +#include "fsl_sdhc.h" +#elif defined(FSL_FEATURE_SOC_SDIF_COUNT) && FSL_FEATURE_SOC_SDIF_COUNT > 0U +#include "fsl_sdif.h" +#elif defined(FSL_FEATURE_SOC_USDHC_COUNT) && FSL_FEATURE_SOC_USDHC_COUNT > 0U +#include "fsl_usdhc.h" +#endif + +/*! + * @addtogroup SDMMCHOST + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Common definition for support and not support macro */ +#define SDMMCHOST_NOT_SUPPORT 0U /*!< use this define to indicate the host not support feature*/ +#define SDMMCHOST_SUPPORT 1U /*!< use this define to indicate the host support feature*/ + +/* Common definition for board support SDR104/HS200/HS400 frequency */ +/* SDR104 mode freq */ +#if defined BOARD_SD_HOST_SUPPORT_SDR104_FREQ +#define SDMMCHOST_SUPPORT_SDR104_FREQ BOARD_SD_HOST_SUPPORT_SDR104_FREQ +#else +#define SDMMCHOST_SUPPORT_SDR104_FREQ SD_CLOCK_208MHZ +#endif +/* HS200 mode freq */ +#if defined BOARD_SD_HOST_SUPPORT_HS200_FREQ +#define SDMMCHOST_SUPPORT_HS200_FREQ BOARD_SD_HOST_SUPPORT_HS200_FREQ +#else +#define SDMMCHOST_SUPPORT_HS200_FREQ MMC_CLOCK_HS200 +#endif +/* HS400 mode freq */ +#if defined BOARD_SD_HOST_SUPPORT_HS400_FREQ +#define SDMMCHOST_SUPPORT_HS400_FREQ BOARD_SD_HOST_SUPPORT_HS400_FREQ +#else +#define SDMMCHOST_SUPPORT_HS400_FREQ MMC_CLOCK_HS400 +#endif + +/* Common definition for SDMMCHOST transfer complete timeout */ +#define SDMMCHOST_TRANSFER_COMPLETE_TIMEOUT (500U) +/* Common definition for card detect timeout */ +#define SDMMCHOST_CARD_DETECT_TIMEOUT (~0U) + +/* Common definition for IRQ */ +#if defined(__CORTEX_M) +#define SDMMCHOST_SET_IRQ_PRIORITY(id, priority) (NVIC_SetPriority(id, priority)) +#else +#define SDMMCHOST_SET_IRQ_PRIORITY(id, priority) (GIC_SetPriority(id, priority)) +#endif + +#define SDMMCHOST_ENABLE_IRQ(id) (EnableIRQ(id)) + +/*********************************************************SDHC**********************************************************/ +#if (defined(FSL_FEATURE_SOC_SDHC_COUNT) && (FSL_FEATURE_SOC_SDHC_COUNT > 0U)) + +/*define host baseaddr ,clk freq, IRQ number*/ +#define MMC_HOST_BASEADDR BOARD_SDHC_BASEADDR +#define MMC_HOST_CLK_FREQ BOARD_SDHC_CLK_FREQ +#define MMC_HOST_IRQ BOARD_SDHC_IRQ +#define SD_HOST_BASEADDR BOARD_SDHC_BASEADDR +#define SD_HOST_CLK_FREQ BOARD_SDHC_CLK_FREQ +#define SD_HOST_IRQ BOARD_SDHC_IRQ + +/* define for card bus speed/strength cnofig */ +#define CARD_BUS_FREQ_50MHZ (0U) +#define CARD_BUS_FREQ_100MHZ0 (0U) +#define CARD_BUS_FREQ_100MHZ1 (0U) +#define CARD_BUS_FREQ_200MHZ (0U) + +#define CARD_BUS_STRENGTH_0 (0U) +#define CARD_BUS_STRENGTH_1 (0U) +#define CARD_BUS_STRENGTH_2 (0U) +#define CARD_BUS_STRENGTH_3 (0U) +#define CARD_BUS_STRENGTH_4 (0U) +#define CARD_BUS_STRENGTH_5 (0U) +#define CARD_BUS_STRENGTH_6 (0U) +#define CARD_BUS_STRENGTH_7 (0U) + +#define SDMMCHOST_TYPE SDHC_Type +#define SDMMCHOST_CONFIG sdhc_host_t +#define SDMMCHOST_TRANSFER sdhc_transfer_t +#define SDMMCHOST_COMMAND sdhc_command_t +#define SDMMCHOST_DATA sdhc_data_t +#define SDMMCHOST_BUS_WIDTH_TYPE sdhc_data_bus_width_t +#define SDMMCHOST_CAPABILITY sdhc_capability_t +#define SDMMCHOST_BOOT_CONFIG sdhc_boot_config_t + +#define CARD_DATA0_STATUS_MASK (kSDHC_Data0LineLevelFlag) +#define CARD_DATA0_NOT_BUSY (kSDHC_Data0LineLevelFlag) +#define CARD_DATA1_STATUS_MASK (kSDHC_Data1LineLevelFlag) +#define CARD_DATA2_STATUS_MASK (kSDHC_Data2LineLevelFlag) +#define CARD_DATA3_STATUS_MASK (kSDHC_Data3LineLevelFlag) + +#define kSDMMCHOST_DATABUSWIDTH1BIT kSDHC_DataBusWidth1Bit /*!< 1-bit mode */ +#define kSDMMCHOST_DATABUSWIDTH4BIT kSDHC_DataBusWidth4Bit /*!< 4-bit mode */ +#define kSDMMCHOST_DATABUSWIDTH8BIT kSDHC_DataBusWidth8Bit /*!< 8-bit mode */ + +#define SDMMCHOST_STANDARD_TUNING_START (0U) /*!< standard tuning start point */ +#define SDMMCHOST_TUINIG_STEP (1U) /*!< standard tuning step */ +#define SDMMCHOST_RETUNING_TIMER_COUNT (4U) /*!< Re-tuning timer */ +#define SDMMCHOST_TUNING_DELAY_MAX (0x7FU) +#define SDMMCHOST_RETUNING_REQUEST (1U) +#define SDMMCHOST_TUNING_ERROR (2U) + +/* function pointer define */ +#define SDMMCHOST_TRANSFER_FUNCTION sdhc_transfer_function_t +#define GET_SDMMCHOST_CAPABILITY(base, capability) (SDHC_GetCapability(base, capability)) +#define GET_SDMMCHOST_STATUS(base) (SDHC_GetPresentStatusFlags(base)) +#define SDMMCHOST_SET_CARD_CLOCK(base, sourceClock_HZ, busClock_HZ) (SDHC_SetSdClock(base, sourceClock_HZ, busClock_HZ)) +#define SDMMCHOST_SET_CARD_BUS_WIDTH(base, busWidth) (SDHC_SetDataBusWidth(base, busWidth)) +#define SDMMCHOST_SEND_CARD_ACTIVE(base, timeout) (SDHC_SetCardActive(base, timeout)) +#define SDMMCHOST_SWITCH_VOLTAGE180V(base, enable18v) +#define SDMMCHOST_SWITCH_VOLTAGE120V(base, enable12v) +#define SDMMCHOST_CONFIG_IO_STRENGTH(speed, strength) +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, flag) +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_STATUS(base) (0U) +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_RESULT(base) (1U) +#define SDMMCHOST_CONFIG_SD_IO(speed, strength) +#define SDMMCHOST_CONFIG_MMC_IO(speed, strength) +#define SDMMCHOST_ENABLE_DDR_MODE(base, flag, nibblePos) +#define SDMMCHOST_FORCE_SDCLOCK_ON(base, enable) +#define SDMMCHOST_EXECUTE_MANUAL_TUNING_ENABLE(base, flag) +#define SDMMCHOST_ADJUST_MANUAL_TUNING_DELAY(base, delay) +#define SDMMCHOST_AUTO_MANUAL_TUNING_ENABLE(base, flag) +#define SDMMCHOST_ENABLE_CARD_CLOCK(base, enable) (SDHC_EnableSdClock(base, enable)) +#define SDMMCHOST_RESET_TUNING(base, timeout) +#define SDMMCHOST_CHECK_TUNING_ERROR(base) (0U) +#define SDMMCHOST_ADJUST_TUNING_DELAY(base, delay) +#define SDMMCHOST_AUTO_STANDARD_RETUNING_TIMER(base) +#define SDMMCHOST_TRANSFER_DATA_ERROR kStatus_SDHC_TransferDataFailed +#define SDMMCHOST_TRANSFER_CMD_ERROR kStatus_SDHC_SendCommandFailed +#define SDMMCHOST_ENABLE_HS400_MODE(base, flag) +#define SDMMCHOST_RESET_STROBE_DLL(base) +#define SDMMCHOST_ENABLE_STROBE_DLL(base, flag) +#define SDMMCHOST_CONFIG_STROBE_DLL(base, delay, updateInterval) +#define SDMMCHOST_GET_STROBE_DLL_STATUS(base) +/* sd card power */ +#define SDMMCHOST_INIT_SD_POWER() +#define SDMMCHOST_ENABLE_SD_POWER(enable) +#define SDMMCHOST_SWITCH_VCC_TO_180V() +#define SDMMCHOST_SWITCH_VCC_TO_330V() +/* mmc card power */ +#define SDMMCHOST_INIT_MMC_POWER() +#define SDMMCHOST_ENABLE_MMC_POWER(enable) +#define SDMMCHOST_ENABLE_TUNING_FLAG(data) +#define SDMMCHOST_ENABLE_BOOT_FLAG(data) +#define SDMMCHOST_ENABLE_BOOT_CONTINOUS_FLAG(data) +#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_SIZE(config) (0U) +#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_COUNT(config) (0U) +#define SDMMCHOST_GET_HOST_CONFIG_BOOT_MODE(config) (0U) +#define SDMMCHOST_EMPTY_CMD_FLAG(command) +#define SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_HANDLER BOARD_SDHC_CD_PORT_IRQ_HANDLER +#define SDMMCHOST_CARD_DETECT_IRQ BOARD_SDHC_CD_PORT_IRQ +/* sd card detect through host CD */ +#define SDMMCHOST_CARD_DETECT_INSERT_ENABLE(base) (SDHC_EnableInterruptStatus(base, kSDHC_CardInsertionFlag)) +#define SDMMCHOST_CARD_DETECT_REMOVE_ENABLE(base) (SDHC_EnableInterruptStatus(base, kSDHC_CardRemovalFlag)) +#define SDMMCHOST_CARD_DETECT_INSERT_STATUS(base) (SDHC_GetInterruptStatusFlags(base) & kSDHC_CardInsertionFlag) +#define SDMMCHOST_CARD_DETECT_REMOVE_STATUS(base) (SDHC_GetInterruptStatusFlags(base, kSDHC_CardRemovalFlag)) +#define SDMMCHOST_CARD_DETECT_INSERT_INTERRUPT_ENABLE(base) (SDHC_EnableInterruptSignal(base, kSDHC_CardInsertionFlag)) +#define SDMMCHOST_CARD_DETECT_INSERT_INTERRUPT_DISABLE(base) \ + (SDHC_DisableInterruptSignal(base, kSDHC_CardInsertionFlag)) +#define SDMMCHOST_CARD_DETECT_REMOVE_INTERRUPT_ENABLE(base) (SDHC_EnableInterruptSignal(base, kSDHC_CardRemovalFlag)) +#define SDMMCHOST_CARD_DETECT_DATA3_ENABLE(base, flag) (SDHC_CardDetectByData3(base, flag)) +#define SDMMCHOST_ENABLE_MMC_BOOT(base, flag) +#define SDMMCHOST_SETMMCBOOTCONFIG(base, config) (SDHC_SetMmcBootConfig(base, config)) +/* define card detect pin voltage level when card inserted */ +#if defined BOARD_SDHC_CARD_INSERT_CD_LEVEL +#define SDMMCHOST_CARD_INSERT_CD_LEVEL BOARD_SDHC_CARD_INSERT_CD_LEVEL +#else +#define SDMMCHOST_CARD_INSERT_CD_LEVEL (0U) +#endif +#define SDMMCHOST_AUTO_TUNING_ENABLE(base, flag) +#define SDMMCHOST_ENABLE_SDIO_INT(base) \ + SDHC_EnableInterruptStatus(base, kSDHC_CardInterruptFlag); \ + SDHC_EnableInterruptSignal(base, kSDHC_CardInterruptFlag) +#define SDMMCHOST_DISABLE_SDIO_INT(base) \ + SDHC_DisableInterruptStatus(base, kSDHC_CardInterruptFlag); \ + SDHC_DisableInterruptSignal(base, kSDHC_CardInterruptFlag) + +/*! @brief SDHC host capability*/ +enum _host_capability +{ + kSDMMCHOST_SupportAdma = kSDHC_SupportAdmaFlag, + kSDMMCHOST_SupportHighSpeed = kSDHC_SupportHighSpeedFlag, + kSDMMCHOST_SupportDma = kSDHC_SupportDmaFlag, + kSDMMCHOST_SupportSuspendResume = kSDHC_SupportSuspendResumeFlag, + kSDMMCHOST_SupportV330 = kSDHC_SupportV330Flag, + kSDMMCHOST_SupportV300 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportV180 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportV120 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_Support4BitBusWidth = kSDHC_Support4BitFlag, + kSDMMCHOST_Support8BitBusWidth = kSDHC_Support8BitFlag, + kSDMMCHOST_SupportDDR50 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportSDR104 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportSDR50 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportHS200 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportHS400 = SDMMCHOST_NOT_SUPPORT, +}; + +/* Endian mode. */ +#define SDHC_ENDIAN_MODE kSDHC_EndianModeLittle + +/* DMA mode */ +#define SDHC_DMA_MODE kSDHC_DmaModeAdma2 +/* address align */ +#define SDMMCHOST_DMA_BUFFER_ADDR_ALIGN (SDHC_ADMA2_ADDRESS_ALIGN) + +/* Read/write watermark level. The bigger value indicates DMA has higher read/write performance. */ +#define SDHC_READ_WATERMARK_LEVEL (0x80U) +#define SDHC_WRITE_WATERMARK_LEVEL (0x80U) + +/* ADMA table length united as word. + * + * SD card driver can't support ADMA1 transfer mode currently. + * One ADMA2 table item occupy two words which can transfer maximum 0xFFFFU bytes one time. + * The more data to be transferred in one time, the bigger value of SDHC_ADMA_TABLE_WORDS need to be set. + */ +#define SDHC_ADMA_TABLE_WORDS (8U) + +/*********************************************************SDIF**********************************************************/ +#elif (defined(FSL_FEATURE_SOC_SDIF_COUNT) && (FSL_FEATURE_SOC_SDIF_COUNT > 0U)) + +/*define host baseaddr ,clk freq, IRQ number*/ +#define MMC_HOST_BASEADDR BOARD_SDIF_BASEADDR +#define MMC_HOST_CLK_FREQ BOARD_SDIF_CLK_FREQ +#define MMC_HOST_IRQ BOARD_SDIF_IRQ +#define SD_HOST_BASEADDR BOARD_SDIF_BASEADDR +#define SD_HOST_CLK_FREQ BOARD_SDIF_CLK_FREQ +#define SD_HOST_IRQ BOARD_SDIF_IRQ + +/* define for card bus speed/strength cnofig */ +#define CARD_BUS_FREQ_50MHZ (0U) +#define CARD_BUS_FREQ_100MHZ0 (0U) +#define CARD_BUS_FREQ_100MHZ1 (0U) +#define CARD_BUS_FREQ_200MHZ (0U) + +#define CARD_BUS_STRENGTH_0 (0U) +#define CARD_BUS_STRENGTH_1 (0U) +#define CARD_BUS_STRENGTH_2 (0U) +#define CARD_BUS_STRENGTH_3 (0U) +#define CARD_BUS_STRENGTH_4 (0U) +#define CARD_BUS_STRENGTH_5 (0U) +#define CARD_BUS_STRENGTH_6 (0U) +#define CARD_BUS_STRENGTH_7 (0U) + +#define SDMMCHOST_TYPE SDIF_Type +#define SDMMCHOST_CONFIG sdif_host_t +#define SDMMCHOST_TRANSFER sdif_transfer_t +#define SDMMCHOST_COMMAND sdif_command_t +#define SDMMCHOST_DATA sdif_data_t +#define SDMMCHOST_BUS_WIDTH_TYPE sdif_bus_width_t +#define SDMMCHOST_CAPABILITY sdif_capability_t +#define SDMMCHOST_BOOT_CONFIG void + +#define CARD_DATA0_STATUS_MASK SDIF_STATUS_DATA_BUSY_MASK +#define CARD_DATA0_NOT_BUSY 0U + +#define CARD_DATA1_STATUS_MASK (0U) +#define CARD_DATA2_STATUS_MASK (0U) +#define CARD_DATA3_STATUS_MASK (0U) + +#define kSDMMCHOST_DATABUSWIDTH1BIT kSDIF_Bus1BitWidth /*!< 1-bit mode */ +#define kSDMMCHOST_DATABUSWIDTH4BIT kSDIF_Bus4BitWidth /*!< 4-bit mode */ +#define kSDMMCHOST_DATABUSWIDTH8BIT kSDIF_Bus8BitWidth /*!< 8-bit mode */ + +#define SDMMCHOST_STANDARD_TUNING_START (0U) /*!< standard tuning start point */ +#define SDMMCHOST_TUINIG_STEP (1U) /*!< standard tuning step */ +#define SDMMCHOST_RETUNING_TIMER_COUNT (4U) /*!< Re-tuning timer */ +#define SDMMCHOST_TUNING_DELAY_MAX (0x7FU) +#define SDMMCHOST_RETUNING_REQUEST (1U) +#define SDMMCHOST_TUNING_ERROR (2U) +/* function pointer define */ +#define SDMMCHOST_TRANSFER_FUNCTION sdif_transfer_function_t +#define GET_SDMMCHOST_CAPABILITY(base, capability) (SDIF_GetCapability(base, capability)) +#define GET_SDMMCHOST_STATUS(base) (SDIF_GetControllerStatus(base)) +#define SDMMCHOST_SET_CARD_CLOCK(base, sourceClock_HZ, busClock_HZ) \ + (SDIF_SetCardClock(base, sourceClock_HZ, busClock_HZ)) +#define SDMMCHOST_SET_CARD_BUS_WIDTH(base, busWidth) (SDIF_SetCardBusWidth(base, busWidth)) +#define SDMMCHOST_SEND_CARD_ACTIVE(base, timeout) (SDIF_SendCardActive(base, timeout)) +#define SDMMCHOST_SWITCH_VOLTAGE180V(base, enable18v) +#define SDMMCHOST_SWITCH_VOLTAGE120V(base, enable12v) +#define SDMMCHOST_CONFIG_IO_STRENGTH(speed, strength) +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, flag) +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_STATUS(base) (0U) +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_RESULT(base) (1U) +#define SDMMCHOST_CONFIG_SD_IO(speed, strength) +#define SDMMCHOST_CONFIG_MMC_IO(speed, strength) +#define SDMMCHOST_ENABLE_DDR_MODE(base, flag, nibblePos) +#define SDMMCHOST_FORCE_SDCLOCK_ON(base, enable) +#define SDMMCHOST_EXECUTE_MANUAL_TUNING_ENABLE(base, flag) +#define SDMMCHOST_ADJUST_MANUAL_TUNING_DELAY(base, delay) +#define SDMMCHOST_AUTO_MANUAL_TUNING_ENABLE(base, flag) +#define SDMMCHOST_ENABLE_CARD_CLOCK(base, enable) (SDIF_EnableCardClock(base, enable)) +#define SDMMCHOST_RESET_TUNING(base, timeout) +#define SDMMCHOST_CHECK_TUNING_ERROR(base) (0U) +#define SDMMCHOST_ADJUST_TUNING_DELAY(base, delay) +#define SDMMCHOST_AUTO_STANDARD_RETUNING_TIMER(base) + +#define SDMMCHOST_ENABLE_HS400_MODE(base, flag) +#define SDMMCHOST_RESET_STROBE_DLL(base) +#define SDMMCHOST_ENABLE_STROBE_DLL(base, flag) +#define SDMMCHOST_CONFIG_STROBE_DLL(base, delay, updateInterval) +#define SDMMCHOST_GET_STROBE_DLL_STATUS(base) +/* sd card power */ +#define SDMMCHOST_INIT_SD_POWER() +#define SDMMCHOST_ENABLE_SD_POWER(enable) +#define SDMMCHOST_SWITCH_VCC_TO_180V() +#define SDMMCHOST_SWITCH_VCC_TO_330V() +/* mmc card power */ +#define SDMMCHOST_INIT_MMC_POWER() +#define SDMMCHOST_ENABLE_MMC_POWER(enable) +#define SDMMCHOST_ENABLE_TUNING_FLAG(data) +#define SDMMCHOST_ENABLE_MMC_BOOT(base, flag) +#define SDMMCHOST_SETMMCBOOTCONFIG(base, config) +#define SDMMCHOST_ENABLE_BOOT_FLAG(data) +#define SDMMCHOST_ENABLE_BOOT_CONTINOUS_FLAG(data) +#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_SIZE(config) (0U) +#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_COUNT(config) (0U) +#define SDMMCHOST_GET_HOST_CONFIG_BOOT_MODE(config) (0U) +#define SDMMCHOST_EMPTY_CMD_FLAG(command) +#define SDMMCHOST_CARD_DETECT_STATUS() BOARD_SDIF_CD_STATUS() +#define SDMMCHOST_CARD_DETECT_INIT() BOARD_SDIF_CD_GPIO_INIT() +#define SDMMCHOST_CARD_DETECT_INTERRUPT_STATUS() BOARD_SDIF_CD_INTERRUPT_STATUS() +#define SDMMCHOST_CARD_DETECT_INTERRUPT_CLEAR(flag) BOARD_SDIF_CD_CLEAR_INTERRUPT(flag) +#define SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_HANDLER BOARD_SDIF_CD_PORT_IRQ_HANDLER +#define SDMMCHOST_CARD_DETECT_IRQ BOARD_SDIF_CD_PORT_IRQ +#define SDMMCHOST_TRANSFER_DATA_ERROR kStatus_SDIF_DataTransferFail +#define SDMMCHOST_TRANSFER_CMD_ERROR kStatus_SDIF_SendCmdFail +/* define card detect pin voltage level when card inserted */ +#if defined BOARD_SDIF_CARD_INSERT_CD_LEVEL +#define SDMMCHOST_CARD_INSERT_CD_LEVEL BOARD_SDIF_CARD_INSERT_CD_LEVEL +#else +#define SDMMCHOST_CARD_INSERT_CD_LEVEL (0U) +#endif +#define SDMMCHOST_AUTO_TUNING_ENABLE(base, flag) +/* sd card detect through host CD */ +#define SDMMCHOST_CARD_DETECT_INSERT_ENABLE(base) (SDIF_EnableInterrupt(base, kSDIF_CardDetect)) +#define SDMMCHOST_CARD_DETECT_INSERT_STATUS(base, data3) (SDIF_DetectCardInsert(base, data3)) +#define SDMMCHOST_ENABLE_SDIO_INT(base) +#define SDMMCHOST_DISABLE_SDIO_INT(base) +/*! @brief SDIF host capability*/ +enum _host_capability +{ + kSDMMCHOST_SupportHighSpeed = kSDIF_SupportHighSpeedFlag, + kSDMMCHOST_SupportDma = kSDIF_SupportDmaFlag, + kSDMMCHOST_SupportSuspendResume = kSDIF_SupportSuspendResumeFlag, + kSDMMCHOST_SupportV330 = kSDIF_SupportV330Flag, + kSDMMCHOST_SupportV300 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportV180 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportV120 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_Support4BitBusWidth = kSDIF_Support4BitFlag, + kSDMMCHOST_Support8BitBusWidth = + SDMMCHOST_NOT_SUPPORT, /* mask the 8 bit here,user can change depend on your board */ + kSDMMCHOST_SupportDDR50 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportSDR104 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportSDR50 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportHS200 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_SupportHS400 = SDMMCHOST_NOT_SUPPORT, + +}; + +/*! @brief DMA table length united as word + * One dma table item occupy four words which can transfer maximum 2*8188 bytes in dual DMA mode + * and 8188 bytes in chain mode + * The more data to be transferred in one time, the bigger value of SDHC_ADMA_TABLE_WORDS need to be set. + * user need check the DMA descriptor table lenght if bigger enough. + */ +#define SDIF_DMA_TABLE_WORDS (0x40U) +/* address align */ +#define SDMMCHOST_DMA_BUFFER_ADDR_ALIGN (4U) + +/*********************************************************USDHC**********************************************************/ +#elif (defined(FSL_FEATURE_SOC_USDHC_COUNT) && (FSL_FEATURE_SOC_USDHC_COUNT > 0U)) + +/*define host baseaddr ,clk freq, IRQ number*/ +#define MMC_HOST_BASEADDR BOARD_MMC_HOST_BASEADDR +#define MMC_HOST_CLK_FREQ BOARD_MMC_HOST_CLK_FREQ +#define MMC_HOST_IRQ BOARD_MMC_HOST_IRQ +#define SD_HOST_BASEADDR BOARD_SD_HOST_BASEADDR +#define SD_HOST_CLK_FREQ BOARD_SD_HOST_CLK_FREQ +#define SD_HOST_IRQ BOARD_SD_HOST_IRQ + +#define SDMMCHOST_TYPE USDHC_Type +#define SDMMCHOST_CONFIG usdhc_host_t +#define SDMMCHOST_TRANSFER usdhc_transfer_t +#define SDMMCHOST_COMMAND usdhc_command_t +#define SDMMCHOST_DATA usdhc_data_t +#define SDMMCHOST_BOOT_CONFIG usdhc_boot_config_t +#define CARD_DATA0_STATUS_MASK (kUSDHC_Data0LineLevelFlag) +#define CARD_DATA1_STATUS_MASK (kUSDHC_Data1LineLevelFlag) +#define CARD_DATA2_STATUS_MASK (kUSDHC_Data2LineLevelFlag) +#define CARD_DATA3_STATUS_MASK (kUSDHC_Data3LineLevelFlag) +#define CARD_DATA0_NOT_BUSY (kUSDHC_Data0LineLevelFlag) + +#define SDMMCHOST_BUS_WIDTH_TYPE usdhc_data_bus_width_t +#define SDMMCHOST_CAPABILITY usdhc_capability_t + +#define kSDMMCHOST_DATABUSWIDTH1BIT kUSDHC_DataBusWidth1Bit /*!< 1-bit mode */ +#define kSDMMCHOST_DATABUSWIDTH4BIT kUSDHC_DataBusWidth4Bit /*!< 4-bit mode */ +#define kSDMMCHOST_DATABUSWIDTH8BIT kUSDHC_DataBusWidth8Bit /*!< 8-bit mode */ + +#define SDMMCHOST_STANDARD_TUNING_START (10U) /*!< standard tuning start point */ +#define SDMMCHOST_TUINIG_STEP (2U) /*!< standard tuning step */ +#define SDMMCHOST_RETUNING_TIMER_COUNT (0U) /*!< Re-tuning timer */ +#define SDMMCHOST_TUNING_DELAY_MAX (0x7FU) +#define SDMMCHOST_RETUNING_REQUEST kStatus_USDHC_ReTuningRequest +#define SDMMCHOST_TUNING_ERROR kStatus_USDHC_TuningError +#define SDMMCHOST_TRANSFER_DATA_ERROR kStatus_USDHC_TransferDataFailed +#define SDMMCHOST_TRANSFER_CMD_ERROR kStatus_USDHC_SendCommandFailed +/* define for card bus speed/strength cnofig */ +#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 SDMMCHOST_STROBE_DLL_DELAY_TARGET (7U) +#define SDMMCHOST_STROBE_DLL_DELAY_UPDATE_INTERVAL (4U) + +/* function pointer define */ +#define SDMMCHOST_TRANSFER_FUNCTION usdhc_transfer_function_t +#define GET_SDMMCHOST_CAPABILITY(base, capability) (USDHC_GetCapability(base, capability)) +#define GET_SDMMCHOST_STATUS(base) (USDHC_GetPresentStatusFlags(base)) +#define SDMMCHOST_SET_CARD_CLOCK(base, sourceClock_HZ, busClock_HZ) \ + (USDHC_SetSdClock(base, sourceClock_HZ, busClock_HZ)) +#define SDMMCHOST_ENABLE_CARD_CLOCK(base, enable) +#define SDMMCHOST_FORCE_SDCLOCK_ON(base, enable) (USDHC_ForceClockOn(base, enable)) +#define SDMMCHOST_SET_CARD_BUS_WIDTH(base, busWidth) (USDHC_SetDataBusWidth(base, busWidth)) +#define SDMMCHOST_SEND_CARD_ACTIVE(base, timeout) (USDHC_SetCardActive(base, timeout)) +#define SDMMCHOST_SWITCH_VOLTAGE180V(base, enable18v) (UDSHC_SelectVoltage(base, enable18v)) +#define SDMMCHOST_SWITCH_VOLTAGE120V(base, enable12v) +#define SDMMCHOST_CONFIG_SD_IO(speed, strength) BOARD_SD_Pin_Config(speed, strength) +#define SDMMCHOST_CONFIG_MMC_IO(speed, strength) BOARD_MMC_Pin_Config(speed, strength) +#define SDMMCHOST_SWITCH_VCC_TO_180V() +#define SDMMCHOST_SWITCH_VCC_TO_330V() + +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_STATUS(base) (0U) +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_RESULT(base) (1U) +#define SDMMCHOST_AUTO_STANDARD_RETUNING_TIMER(base) +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, flag) +#define SDMMCHOST_CHECK_TUNING_ERROR(base) (0U) +#define SDMMCHOST_ADJUST_TUNING_DELAY(base, delay) +#else +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, flag) \ + (USDHC_EnableStandardTuning(base, SDMMCHOST_STANDARD_TUNING_START, SDMMCHOST_TUINIG_STEP, flag)) +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_STATUS(base) (USDHC_GetExecuteStdTuningStatus(base)) +#define SDMMCHOST_EXECUTE_STANDARD_TUNING_RESULT(base) (USDHC_CheckStdTuningResult(base)) +#define SDMMCHOST_AUTO_STANDARD_RETUNING_TIMER(base) (USDHC_SetRetuningTimer(base, SDMMCHOST_RETUNING_TIMER_COUNT)) +#define SDMMCHOST_EXECUTE_MANUAL_TUNING_ENABLE(base, flag) (USDHC_EnableManualTuning(base, flag)) +#define SDMMCHOST_ADJUST_TUNING_DELAY(base, delay) (USDHC_AdjustDelayForManualTuning(base, delay)) +#define SDMMCHOST_AUTO_TUNING_ENABLE(base, flag) (USDHC_EnableAutoTuning(base, flag)) +#define SDMMCHOST_CHECK_TUNING_ERROR(base) (USDHC_CheckTuningError(base)) +#endif + +#define SDMMCHOST_AUTO_TUNING_CONFIG(base) (USDHC_EnableAutoTuningForCmdAndData(base)) +#define SDMMCHOST_RESET_TUNING(base, timeout) \ + { \ + (USDHC_Reset(base, kUSDHC_ResetTuning | kUSDHC_ResetData | kUSDHC_ResetCommand, timeout)); \ + } + +#define SDMMCHOST_ENABLE_DDR_MODE(base, flag, nibblePos) (USDHC_EnableDDRMode(base, flag, nibblePos)) + +#if FSL_FEATURE_USDHC_HAS_HS400_MODE +#define SDMMCHOST_ENABLE_HS400_MODE(base, flag) (USDHC_EnableHS400Mode(base, flag)) +#define SDMMCHOST_RESET_STROBE_DLL(base) (USDHC_ResetStrobeDLL(base)) +#define SDMMCHOST_ENABLE_STROBE_DLL(base, flag) (USDHC_EnableStrobeDLL(base, flag)) +#define SDMMCHOST_CONFIG_STROBE_DLL(base, delay, updateInterval) (USDHC_ConfigStrobeDLL(base, delay, updateInterval)) +#define SDMMCHOST_GET_STROBE_DLL_STATUS (base)(USDHC_GetStrobeDLLStatus(base)) +#else +#define SDMMCHOST_ENABLE_HS400_MODE(base, flag) +#define SDMMCHOST_RESET_STROBE_DLL(base) +#define SDMMCHOST_ENABLE_STROBE_DLL(base, flag) +#define SDMMCHOST_CONFIG_STROBE_DLL(base, delay, updateInterval) +#define SDMMCHOST_GET_STROBE_DLL_STATUS(base) +#endif + +#define SDMMCHOST_ENABLE_MMC_BOOT(base, flag) (USDHC_EnableMmcBoot(base, flag)) +#define SDMMCHOST_SETMMCBOOTCONFIG(base, config) (USDHC_SetMmcBootConfig(base, config)) +/* sd card power */ +#define SDMMCHOST_INIT_SD_POWER() BOARD_USDHC_SDCARD_POWER_CONTROL_INIT() +#define SDMMCHOST_ENABLE_SD_POWER(enable) BOARD_USDHC_SDCARD_POWER_CONTROL(enable) +/* mmc card power */ +#define SDMMCHOST_INIT_MMC_POWER() BOARD_USDHC_MMCCARD_POWER_CONTROL_INIT() +#define SDMMCHOST_ENABLE_MMC_POWER(enable) BOARD_USDHC_MMCCARD_POWER_CONTROL(enable) +/* sd card detect through gpio */ +#define SDMMCHOST_CARD_DETECT_GPIO_STATUS() BOARD_USDHC_CD_STATUS() +#define SDMMCHOST_CARD_DETECT_GPIO_INIT() BOARD_USDHC_CD_GPIO_INIT() +#define SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_STATUS() BOARD_USDHC_CD_INTERRUPT_STATUS() +#define SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_STATUS_CLEAR(flag) BOARD_USDHC_CD_CLEAR_INTERRUPT(flag) +#define SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_HANDLER BOARD_USDHC_CD_PORT_IRQ_HANDLER +#define SDMMCHOST_CARD_DETECT_GPIO_IRQ BOARD_USDHC_CD_PORT_IRQ +/* sd card detect through host CD */ +#define SDMMCHOST_CARD_DETECT_INSERT_ENABLE(base) (USDHC_EnableInterruptStatus(base, kUSDHC_CardInsertionFlag)) +#define SDMMCHOST_CARD_DETECT_REMOVE_ENABLE(base) (USDHC_EnableInterruptStatus(base, kUSDHC_CardRemovalFlag)) +#define SDMMCHOST_CARD_DETECT_INSERT_STATUS(base) (USDHC_DetectCardInsert(base)) +#define SDMMCHOST_CARD_DETECT_REMOVE_STATUS(base) (USDHC_GetInterruptStatusFlags(base, kUSDHC_CardRemovalFlag)) +#define SDMMCHOST_CARD_DETECT_INSERT_INTERRUPT_ENABLE(base) \ + (USDHC_EnableInterruptSignal(base, kUSDHC_CardInsertionFlag)) +#define SDMMCHOST_CARD_DETECT_REMOVE_INTERRUPT_ENABLE(base) (USDHC_EnableInterruptSignal(base, kUSDHC_CardRemovalFlag)) +#define SDMMCHOST_CARD_DETECT_DATA3_ENABLE(base, flag) (USDHC_CardDetectByData3(base, flag)) + +/* define card detect pin voltage level when card inserted */ +#if defined BOARD_USDHC_CARD_INSERT_CD_LEVEL +#define SDMMCHOST_CARD_INSERT_CD_LEVEL BOARD_USDHC_CARD_INSERT_CD_LEVEL +#else +#define SDMMCHOST_CARD_INSERT_CD_LEVEL (0U) +#endif +#define SDMMCHOST_ENABLE_TUNING_FLAG(data) (data.dataType = kUSDHC_TransferDataTuning) +#define SDMMCHOST_ENABLE_BOOT_FLAG(data) (data.dataType = kUSDHC_TransferDataBoot) +#define SDMMCHOST_ENABLE_BOOT_CONTINOUS_FLAG(data) (data.dataType = kUSDHC_TransferDataBootcontinous) +#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_SIZE(config) (config->blockSize) +#define SDMMCHOST_GET_HOST_CONFIG_BLOCK_COUNT(config) (config->blockCount) +#define SDMMCHOST_GET_HOST_CONFIG_BOOT_MODE(config) (config->bootMode) +#define SDMMCHOST_EMPTY_CMD_FLAG(command) (command.type = kCARD_CommandTypeEmpty) +#define SDMMCHOST_ENABLE_SDIO_INT(base) \ + USDHC_EnableInterruptStatus(base, kUSDHC_CardInterruptFlag); \ + USDHC_EnableInterruptSignal(base, kUSDHC_CardInterruptFlag) +#define SDMMCHOST_DISABLE_SDIO_INT(base) \ + USDHC_DisableInterruptStatus(base, kUSDHC_CardInterruptFlag); \ + USDHC_DisableInterruptSignal(base, kUSDHC_CardInterruptFlag) +/*! @brief USDHC host capability*/ +enum _host_capability +{ + kSDMMCHOST_SupportAdma = kUSDHC_SupportAdmaFlag, + kSDMMCHOST_SupportHighSpeed = kUSDHC_SupportHighSpeedFlag, + kSDMMCHOST_SupportDma = kUSDHC_SupportDmaFlag, + kSDMMCHOST_SupportSuspendResume = kUSDHC_SupportSuspendResumeFlag, + kSDMMCHOST_SupportV330 = kUSDHC_SupportV330Flag, /* this define should depend on your board config */ + kSDMMCHOST_SupportV300 = kUSDHC_SupportV300Flag, /* this define should depend on your board config */ +#if defined(BOARD_SD_SUPPORT_180V) && !BOARD_SD_SUPPORT_180V + kSDMMCHOST_SupportV180 = SDMMCHOST_NOT_SUPPORT, /* this define should depend on you board config */ +#else + kSDMMCHOST_SupportV180 = kUSDHC_SupportV180Flag, /* this define should depend on you board config */ +#endif + kSDMMCHOST_SupportV120 = SDMMCHOST_NOT_SUPPORT, + kSDMMCHOST_Support4BitBusWidth = kUSDHC_Support4BitFlag, +#if defined(BOARD_MMC_SUPPORT_8BIT_BUS) +#if BOARD_MMC_SUPPORT_8BIT_BUS + kSDMMCHOST_Support8BitBusWidth = kUSDHC_Support8BitFlag, +#else + kSDMMCHOST_Support8BitBusWidth = SDMMCHOST_NOT_SUPPORT, +#endif +#else + kSDMMCHOST_Support8BitBusWidth = kUSDHC_Support8BitFlag, +#endif + kSDMMCHOST_SupportDDR50 = kUSDHC_SupportDDR50Flag, + kSDMMCHOST_SupportSDR104 = kUSDHC_SupportSDR104Flag, + kSDMMCHOST_SupportSDR50 = kUSDHC_SupportSDR50Flag, + kSDMMCHOST_SupportHS200 = kUSDHC_SupportSDR104Flag, +#if FSL_FEATURE_USDHC_HAS_HS400_MODE + kSDMMCHOST_SupportHS400 = SDMMCHOST_SUPPORT +#else + kSDMMCHOST_SupportHS400 = SDMMCHOST_NOT_SUPPORT, +#endif +}; + +/* Endian mode. */ +#define USDHC_ENDIAN_MODE kUSDHC_EndianModeLittle + +/* DMA mode */ +#define USDHC_DMA_MODE kUSDHC_DmaModeAdma2 +/* address align */ +#define SDMMCHOST_DMA_BUFFER_ADDR_ALIGN (USDHC_ADMA2_ADDRESS_ALIGN) + +/* Read/write watermark level. The bigger value indicates DMA has higher read/write performance. */ +#define USDHC_READ_WATERMARK_LEVEL (0x80U) +#define USDHC_WRITE_WATERMARK_LEVEL (0x80U) + +/* ADMA table length united as word. + * + * One ADMA2 table item occupy two words which can transfer maximum 0xFFFFU bytes one time. + * The more data to be transferred in one time, the bigger value of SDHC_ADMA_TABLE_WORDS need to be set. + */ +#define USDHC_ADMA_TABLE_WORDS (8U) /* define the ADMA descriptor table length */ +#define USDHC_ADMA2_ADDR_ALIGN (4U) /* define the ADMA2 descriptor table addr align size */ +#define USDHC_READ_BURST_LEN (8U) /*!< number of words USDHC read in a single burst */ +#define USDHC_WRITE_BURST_LEN (8U) /*!< number of words USDHC write in a single burst */ +#define USDHC_DATA_TIMEOUT (0xFU) /*!< data timeout counter value */ + +#endif /* (defined(FSL_FEATURE_SOC_SDHC_COUNT) && (FSL_FEATURE_SOC_SDHC_COUNT > 0U)) */ + +/*! @brief card detect callback definition */ +typedef void (*sdmmchost_cd_callback_t)(bool isInserted, void *userData); + +/*! @brief host Endian mode + * corresponding to driver define + */ +enum _sdmmchost_endian_mode +{ + kSDMMCHOST_EndianModeBig = 0U, /*!< Big endian mode */ + kSDMMCHOST_EndianModeHalfWordBig = 1U, /*!< Half word big endian mode */ + kSDMMCHOST_EndianModeLittle = 2U, /*!< Little endian mode */ +}; + +/*! @brief sd card detect type */ +typedef enum _sdmmchost_detect_card_type +{ + kSDMMCHOST_DetectCardByGpioCD, /*!< sd card detect by CD pin through GPIO */ + kSDMMCHOST_DetectCardByHostCD, /*!< sd card detect by CD pin through host */ + kSDMMCHOST_DetectCardByHostDATA3, /*!< sd card detect by DAT3 pin through host */ +} sdmmchost_detect_card_type_t; + +/*! @brief sd card detect */ +typedef struct _sdmmchost_detect_card +{ + sdmmchost_detect_card_type_t cdType; /*!< card detect type */ + uint32_t cdTimeOut_ms; /*!< card detect timeout which allow 0 - 0xFFFFFFF, value 0 will return immediately, value + 0xFFFFFFFF will block until card is insert */ + + sdmmchost_cd_callback_t cardInserted; /*!< card inserted callback which is meaningful for interrupt case */ + sdmmchost_cd_callback_t cardRemoved; /*!< card removed callback which is meaningful for interrupt case */ + + void *userData; /*!< user data */ +} sdmmchost_detect_card_t; + +/*! @brief card power control function pointer */ +typedef void (*sdmmchost_pwr_t)(void); + +/*! @brief card power control */ +typedef struct _sdmmchost_pwr_card +{ + sdmmchost_pwr_t powerOn; /*!< power on function pointer */ + uint32_t powerOnDelay_ms; /*!< power on delay */ + + sdmmchost_pwr_t powerOff; /*!< power off function pointer */ + uint32_t powerOffDelay_ms; /*!< power off delay */ +} sdmmchost_pwr_card_t; + +/*! @brief card interrupt function pointer */ +typedef void (*sdmmchost_card_int_callback_t)(void *userData); +/*! @brief card interrupt application callback */ +typedef struct _sdmmchost_card_int +{ + void *userData; /*!< user data */ + sdmmchost_card_int_callback_t cardInterrupt; /*!< card int call back */ +} sdmmchost_card_int_t; + +/*! @brief card switch voltage function pointer */ +typedef void (*sdmmchost_card_switch_voltage_t)(void); +/*! @brief card switch voltage function collection */ +typedef struct _sdmmchost_card_switch_voltage_func +{ + sdmmchost_card_switch_voltage_t cardSignalLine1V8; /*!< switch to 1.8v function pointer */ + sdmmchost_card_switch_voltage_t cardSignalLine3V3; /*! + +/*! + * @addtogroup CARD + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief SD/MMC card initialization clock frequency */ +#define SDMMC_CLOCK_400KHZ (400000U) +/*! @brief SD card bus frequency 1 in high-speed mode */ +#define SD_CLOCK_25MHZ (25000000U) +/*! @brief SD card bus frequency 2 in high-speed mode */ +#define SD_CLOCK_50MHZ (50000000U) +/*! @brief SD card bus frequency in SDR50 mode */ +#define SD_CLOCK_100MHZ (100000000U) +/*! @brief SD card bus frequency in SDR104 mode */ +#define SD_CLOCK_208MHZ (208000000U) +/*! @brief MMC card bus frequency 1 in high-speed mode */ +#define MMC_CLOCK_26MHZ (26000000U) +/*! @brief MMC card bus frequency 2 in high-speed mode */ +#define MMC_CLOCK_52MHZ (52000000U) +/*! @brief MMC card bus frequency in high-speed DDR52 mode */ +#define MMC_CLOCK_DDR52 (52000000U) +/*! @brief MMC card bus frequency in high-speed HS200 mode */ +#define MMC_CLOCK_HS200 (200000000U) +/*! @brief MMC card bus frequency in high-speed HS400 mode */ +#define MMC_CLOCK_HS400 (400000000U) + +/*!@brief mask convert */ +#define SDMMC_MASK(bit) (1U << (bit)) + +/*! @brief Card status bit in R1 */ +enum _sdmmc_r1_card_status_flag +{ + kSDMMC_R1OutOfRangeFlag = 31, /*!< Out of range status bit */ + kSDMMC_R1AddressErrorFlag = 30, /*!< Address error status bit */ + kSDMMC_R1BlockLengthErrorFlag = 29, /*!< Block length error status bit */ + kSDMMC_R1EraseSequenceErrorFlag = 28, /*!< Erase sequence error status bit */ + kSDMMC_R1EraseParameterErrorFlag = 27, /*!< Erase parameter error status bit */ + kSDMMC_R1WriteProtectViolationFlag = 26, /*!< Write protection violation status bit */ + kSDMMC_R1CardIsLockedFlag = 25, /*!< Card locked status bit */ + kSDMMC_R1LockUnlockFailedFlag = 24, /*!< lock/unlock error status bit */ + kSDMMC_R1CommandCrcErrorFlag = 23, /*!< CRC error status bit */ + kSDMMC_R1IllegalCommandFlag = 22, /*!< Illegal command status bit */ + kSDMMC_R1CardEccFailedFlag = 21, /*!< Card ecc error status bit */ + kSDMMC_R1CardControllerErrorFlag = 20, /*!< Internal card controller error status bit */ + kSDMMC_R1ErrorFlag = 19, /*!< A general or an unknown error status bit */ + kSDMMC_R1CidCsdOverwriteFlag = 16, /*!< Cid/csd overwrite status bit */ + kSDMMC_R1WriteProtectEraseSkipFlag = 15, /*!< Write protection erase skip status bit */ + kSDMMC_R1CardEccDisabledFlag = 14, /*!< Card ecc disabled status bit */ + kSDMMC_R1EraseResetFlag = 13, /*!< Erase reset status bit */ + kSDMMC_R1ReadyForDataFlag = 8, /*!< Ready for data status bit */ + kSDMMC_R1SwitchErrorFlag = 7, /*!< Switch error status bit */ + kSDMMC_R1ApplicationCommandFlag = 5, /*!< Application command enabled status bit */ + kSDMMC_R1AuthenticationSequenceErrorFlag = 3, /*!< error in the sequence of authentication process */ +}; + +/*! @brief R1 all the error flag */ +#define SDMMC_R1_ALL_ERROR_FLAG \ + (SDMMC_MASK(kSDMMC_R1OutOfRangeFlag) | SDMMC_MASK(kSDMMC_R1AddressErrorFlag) | \ + SDMMC_MASK(kSDMMC_R1BlockLengthErrorFlag) | SDMMC_MASK(kSDMMC_R1EraseSequenceErrorFlag) | \ + SDMMC_MASK(kSDMMC_R1EraseParameterErrorFlag) | SDMMC_MASK(kSDMMC_R1WriteProtectViolationFlag) | \ + SDMMC_MASK(kSDMMC_R1CardIsLockedFlag) | SDMMC_MASK(kSDMMC_R1LockUnlockFailedFlag) | \ + SDMMC_MASK(kSDMMC_R1CommandCrcErrorFlag) | SDMMC_MASK(kSDMMC_R1IllegalCommandFlag) | \ + SDMMC_MASK(kSDMMC_R1CardEccFailedFlag) | SDMMC_MASK(kSDMMC_R1CardControllerErrorFlag) | \ + SDMMC_MASK(kSDMMC_R1ErrorFlag) | SDMMC_MASK(kSDMMC_R1CidCsdOverwriteFlag) | \ + SDMMC_MASK(kSDMMC_R1AuthenticationSequenceErrorFlag)) + +/*! @brief R1: current state */ +#define SDMMC_R1_CURRENT_STATE(x) (((x)&0x00001E00U) >> 9U) + +/*! @brief CURRENT_STATE filed in R1 */ +typedef enum _sdmmc_r1_current_state +{ + kSDMMC_R1StateIdle = 0U, /*!< R1: current state: idle */ + kSDMMC_R1StateReady = 1U, /*!< R1: current state: ready */ + kSDMMC_R1StateIdentify = 2U, /*!< R1: current state: identification */ + kSDMMC_R1StateStandby = 3U, /*!< R1: current state: standby */ + kSDMMC_R1StateTransfer = 4U, /*!< R1: current state: transfer */ + kSDMMC_R1StateSendData = 5U, /*!< R1: current state: sending data */ + kSDMMC_R1StateReceiveData = 6U, /*!< R1: current state: receiving data */ + kSDMMC_R1StateProgram = 7U, /*!< R1: current state: programming */ + kSDMMC_R1StateDisconnect = 8U, /*!< R1: current state: disconnect */ +} sdmmc_r1_current_state_t; + +/*! @brief Error bit in SPI mode R1 */ +enum _sdspi_r1_error_status_flag +{ + kSDSPI_R1InIdleStateFlag = (1U << 0U), /*!< In idle state */ + kSDSPI_R1EraseResetFlag = (1U << 1U), /*!< Erase reset */ + kSDSPI_R1IllegalCommandFlag = (1U << 2U), /*!< Illegal command */ + kSDSPI_R1CommandCrcErrorFlag = (1U << 3U), /*!< Com crc error */ + kSDSPI_R1EraseSequenceErrorFlag = (1U << 4U), /*!< Erase sequence error */ + kSDSPI_R1AddressErrorFlag = (1U << 5U), /*!< Address error */ + kSDSPI_R1ParameterErrorFlag = (1U << 6U), /*!< Parameter error */ +}; + +/*! @brief Error bit in SPI mode R2 */ +enum _sdspi_r2_error_status_flag +{ + kSDSPI_R2CardLockedFlag = (1U << 0U), /*!< Card is locked */ + kSDSPI_R2WriteProtectEraseSkip = (1U << 1U), /*!< Write protect erase skip */ + kSDSPI_R2LockUnlockFailed = (1U << 1U), /*!< Lock/unlock command failed */ + kSDSPI_R2ErrorFlag = (1U << 2U), /*!< Unknown error */ + kSDSPI_R2CardControllerErrorFlag = (1U << 3U), /*!< Card controller error */ + kSDSPI_R2CardEccFailedFlag = (1U << 4U), /*!< Card ecc failed */ + kSDSPI_R2WriteProtectViolationFlag = (1U << 5U), /*!< Write protect violation */ + kSDSPI_R2EraseParameterErrorFlag = (1U << 6U), /*!< Erase parameter error */ + kSDSPI_R2OutOfRangeFlag = (1U << 7U), /*!< Out of range */ + kSDSPI_R2CsdOverwriteFlag = (1U << 7U), /*!< CSD overwrite */ +}; + +/*! @brief The bit mask for COMMAND VERSION field in R7 */ +#define SDSPI_R7_VERSION_SHIFT (28U) +/*! @brief The bit mask for COMMAND VERSION field in R7 */ +#define SDSPI_R7_VERSION_MASK (0xFU) +/*! @brief The bit shift for VOLTAGE ACCEPTED field in R7 */ +#define SDSPI_R7_VOLTAGE_SHIFT (8U) +/*! @brief The bit mask for VOLTAGE ACCEPTED field in R7 */ +#define SDSPI_R7_VOLTAGE_MASK (0xFU) +/*! @brief The bit mask for VOLTAGE 2.7V to 3.6V field in R7 */ +#define SDSPI_R7_VOLTAGE_27_36_MASK (0x1U << SDSPI_R7_VOLTAGE_SHIFT) +/*! @brief The bit shift for ECHO field in R7 */ +#define SDSPI_R7_ECHO_SHIFT (0U) +/*! @brief The bit mask for ECHO field in R7 */ +#define SDSPI_R7_ECHO_MASK (0xFFU) + +/*! @brief Data error token mask */ +#define SDSPI_DATA_ERROR_TOKEN_MASK (0xFU) +/*! @brief Data Error Token mask bit */ +enum _sdspi_data_error_token +{ + kSDSPI_DataErrorTokenError = (1U << 0U), /*!< Data error */ + kSDSPI_DataErrorTokenCardControllerError = (1U << 1U), /*!< Card controller error */ + kSDSPI_DataErrorTokenCardEccFailed = (1U << 2U), /*!< Card ecc error */ + kSDSPI_DataErrorTokenOutOfRange = (1U << 3U), /*!< Out of range */ +}; + +/*! @brief Data Token */ +typedef enum _sdspi_data_token +{ + kSDSPI_DataTokenBlockRead = 0xFEU, /*!< Single block read, multiple block read */ + kSDSPI_DataTokenSingleBlockWrite = 0xFEU, /*!< Single block write */ + kSDSPI_DataTokenMultipleBlockWrite = 0xFCU, /*!< Multiple block write */ + kSDSPI_DataTokenStopTransfer = 0xFDU, /*!< Stop transmission */ +} sdspi_data_token_t; + +/* Data Response Token mask */ +#define SDSPI_DATA_RESPONSE_TOKEN_MASK (0x1FU) /*!< Mask for data response bits */ +/*! @brief Data Response Token */ +typedef enum _sdspi_data_response_token +{ + kSDSPI_DataResponseTokenAccepted = 0x05U, /*!< Data accepted */ + kSDSPI_DataResponseTokenCrcError = 0x0BU, /*!< Data rejected due to CRC error */ + kSDSPI_DataResponseTokenWriteError = 0x0DU, /*!< Data rejected due to write error */ +} sdspi_data_response_token_t; + +/*! @brief SD card individual commands */ +typedef enum _sd_command +{ + kSD_SendRelativeAddress = 3U, /*!< Send Relative Address */ + kSD_Switch = 6U, /*!< Switch Function */ + kSD_SendInterfaceCondition = 8U, /*!< Send Interface Condition */ + kSD_VoltageSwitch = 11U, /*!< Voltage Switch */ + kSD_SpeedClassControl = 20U, /*!< Speed Class control */ + kSD_EraseWriteBlockStart = 32U, /*!< Write Block Start */ + kSD_EraseWriteBlockEnd = 33U, /*!< Write Block End */ + kSD_SendTuningBlock = 19U, /*!< Send Tuning Block */ +} sd_command_t; + +/*! @brief SDSPI individual commands */ +typedef enum _sdspi_command +{ + kSDSPI_CommandCrc = 59U, /*!< Command crc protection on/off */ +} sdspi_command_t; + +/*! @brief SD card individual application commands */ +typedef enum _sd_application_command +{ + kSD_ApplicationSetBusWdith = 6U, /*!< Set Bus Width */ + kSD_ApplicationStatus = 13U, /*!< Send SD status */ + kSD_ApplicationSendNumberWriteBlocks = 22U, /*!< Send Number Of Written Blocks */ + kSD_ApplicationSetWriteBlockEraseCount = 23U, /*!< Set Write Block Erase Count */ + kSD_ApplicationSendOperationCondition = 41U, /*!< Send Operation Condition */ + kSD_ApplicationSetClearCardDetect = 42U, /*!< Set Connnect/Disconnect pull up on detect pin */ + kSD_ApplicationSendScr = 51U, /*!< Send Scr */ +} sd_application_command_t; + +/*! @brief SD card command class */ +enum _sdmmc_command_class +{ + kSDMMC_CommandClassBasic = (1U << 0U), /*!< Card command class 0 */ + kSDMMC_CommandClassBlockRead = (1U << 2U), /*!< Card command class 2 */ + kSDMMC_CommandClassBlockWrite = (1U << 4U), /*!< Card command class 4 */ + kSDMMC_CommandClassErase = (1U << 5U), /*!< Card command class 5 */ + kSDMMC_CommandClassWriteProtect = (1U << 6U), /*!< Card command class 6 */ + kSDMMC_CommandClassLockCard = (1U << 7U), /*!< Card command class 7 */ + kSDMMC_CommandClassApplicationSpecific = (1U << 8U), /*!< Card command class 8 */ + kSDMMC_CommandClassInputOutputMode = (1U << 9U), /*!< Card command class 9 */ + kSDMMC_CommandClassSwitch = (1U << 10U), /*!< Card command class 10 */ +}; + +/*! @brief OCR register in SD card */ +enum _sd_ocr_flag +{ + kSD_OcrPowerUpBusyFlag = 31, /*!< Power up busy status */ + kSD_OcrHostCapacitySupportFlag = 30, /*!< Card capacity status */ + kSD_OcrCardCapacitySupportFlag = kSD_OcrHostCapacitySupportFlag, /*!< Card capacity status */ + kSD_OcrSwitch18RequestFlag = 24, /*!< Switch to 1.8V request */ + kSD_OcrSwitch18AcceptFlag = kSD_OcrSwitch18RequestFlag, /*!< Switch to 1.8V accepted */ + kSD_OcrVdd27_28Flag = 15, /*!< VDD 2.7-2.8 */ + kSD_OcrVdd28_29Flag = 16, /*!< VDD 2.8-2.9 */ + kSD_OcrVdd29_30Flag = 17, /*!< VDD 2.9-3.0 */ + kSD_OcrVdd30_31Flag = 18, /*!< VDD 2.9-3.0 */ + kSD_OcrVdd31_32Flag = 19, /*!< VDD 3.0-3.1 */ + kSD_OcrVdd32_33Flag = 20, /*!< VDD 3.1-3.2 */ + kSD_OcrVdd33_34Flag = 21, /*!< VDD 3.2-3.3 */ + kSD_OcrVdd34_35Flag = 22, /*!< VDD 3.3-3.4 */ + kSD_OcrVdd35_36Flag = 23, /*!< VDD 3.4-3.5 */ +}; + +/*! @brief SD card specification version number */ +enum _sd_specification_version +{ + kSD_SpecificationVersion1_0 = (1U << 0U), /*!< SD card version 1.0-1.01 */ + kSD_SpecificationVersion1_1 = (1U << 1U), /*!< SD card version 1.10 */ + kSD_SpecificationVersion2_0 = (1U << 2U), /*!< SD card version 2.00 */ + kSD_SpecificationVersion3_0 = (1U << 3U), /*!< SD card version 3.0 */ +}; + +/*! @brief SD card bus width */ +typedef enum _sd_data_bus_width +{ + kSD_DataBusWidth1Bit = 0U, /*!< SD data bus width 1-bit mode */ + kSD_DataBusWidth4Bit = 1U, /*!< SD data bus width 4-bit mode */ +} sd_data_bus_width_t; + +/*! @brief SD card switch mode */ +typedef enum _sd_switch_mode +{ + kSD_SwitchCheck = 0U, /*!< SD switch mode 0: check function */ + kSD_SwitchSet = 1U, /*!< SD switch mode 1: set function */ +} sd_switch_mode_t; + +/*! @brief SD card CSD register flags */ +enum _sd_csd_flag +{ + kSD_CsdReadBlockPartialFlag = (1U << 0U), /*!< Partial blocks for read allowed [79:79] */ + kSD_CsdWriteBlockMisalignFlag = (1U << 1U), /*!< Write block misalignment [78:78] */ + kSD_CsdReadBlockMisalignFlag = (1U << 2U), /*!< Read block misalignment [77:77] */ + kSD_CsdDsrImplementedFlag = (1U << 3U), /*!< DSR implemented [76:76] */ + kSD_CsdEraseBlockEnabledFlag = (1U << 4U), /*!< Erase single block enabled [46:46] */ + kSD_CsdWriteProtectGroupEnabledFlag = (1U << 5U), /*!< Write protect group enabled [31:31] */ + kSD_CsdWriteBlockPartialFlag = (1U << 6U), /*!< Partial blocks for write allowed [21:21] */ + kSD_CsdFileFormatGroupFlag = (1U << 7U), /*!< File format group [15:15] */ + kSD_CsdCopyFlag = (1U << 8U), /*!< Copy flag [14:14] */ + kSD_CsdPermanentWriteProtectFlag = (1U << 9U), /*!< Permanent write protection [13:13] */ + kSD_CsdTemporaryWriteProtectFlag = (1U << 10U), /*!< Temporary write protection [12:12] */ +}; + +/*! @brief SD card SCR register flags */ +enum _sd_scr_flag +{ + kSD_ScrDataStatusAfterErase = (1U << 0U), /*!< Data status after erases [55:55] */ + kSD_ScrSdSpecification3 = (1U << 1U), /*!< Specification version 3.00 or higher [47:47]*/ +}; + +/*! @brief SD timing function number */ +enum _sd_timing_function +{ + kSD_FunctionSDR12Deafult = 0U, /*!< SDR12 mode & default*/ + kSD_FunctionSDR25HighSpeed = 1U, /*!< SDR25 & high speed*/ + kSD_FunctionSDR50 = 2U, /*!< SDR50 mode*/ + kSD_FunctionSDR104 = 3U, /*!< SDR104 mode*/ + kSD_FunctionDDR50 = 4U, /*!< DDR50 mode*/ +}; + +/*! @brief SD group number */ +enum _sd_group_num +{ + kSD_GroupTimingMode = 0U, /*!< acess mode group*/ + kSD_GroupCommandSystem = 1U, /*!< command system group*/ + kSD_GroupDriverStrength = 2U, /*!< driver strength group*/ + kSD_GroupCurrentLimit = 3U, /*!< current limit group*/ +}; + +/*! @brief SD card timing mode flags */ +typedef enum _sd_timing_mode +{ + kSD_TimingSDR12DefaultMode = 0U, /*!< Identification mode & SDR12 */ + kSD_TimingSDR25HighSpeedMode = 1U, /*!< High speed mode & SDR25 */ + kSD_TimingSDR50Mode = 2U, /*!< SDR50 mode*/ + kSD_TimingSDR104Mode = 3U, /*!< SDR104 mode */ + kSD_TimingDDR50Mode = 4U, /*!< DDR50 mode */ +} sd_timing_mode_t; + +/*! @brief SD card driver strength */ +typedef enum _sd_driver_strength +{ + kSD_DriverStrengthTypeB = 0U, /*!< default driver strength*/ + kSD_DriverStrengthTypeA = 1U, /*!< driver strength TYPE A */ + kSD_DriverStrengthTypeC = 2U, /*!< driver strength TYPE C */ + kSD_DriverStrengthTypeD = 3U, /*!< driver strength TYPE D */ +} sd_driver_strength_t; + +/*! @brief SD card current limit */ +typedef enum _sd_max_current +{ + kSD_CurrentLimit200MA = 0U, /*!< default current limit */ + kSD_CurrentLimit400MA = 1U, /*!< current limit to 400MA */ + kSD_CurrentLimit600MA = 2U, /*!< current limit to 600MA */ + kSD_CurrentLimit800MA = 3U, /*!< current limit to 800MA */ +} sd_max_current_t; + +/*! @brief SD/MMC card common commands */ +typedef enum _sdmmc_command +{ + kSDMMC_GoIdleState = 0U, /*!< Go Idle State */ + kSDMMC_AllSendCid = 2U, /*!< All Send CID */ + kSDMMC_SetDsr = 4U, /*!< Set DSR */ + kSDMMC_SelectCard = 7U, /*!< Select Card */ + kSDMMC_SendCsd = 9U, /*!< Send CSD */ + kSDMMC_SendCid = 10U, /*!< Send CID */ + kSDMMC_StopTransmission = 12U, /*!< Stop Transmission */ + kSDMMC_SendStatus = 13U, /*!< Send Status */ + kSDMMC_GoInactiveState = 15U, /*!< Go Inactive State */ + kSDMMC_SetBlockLength = 16U, /*!< Set Block Length */ + kSDMMC_ReadSingleBlock = 17U, /*!< Read Single Block */ + kSDMMC_ReadMultipleBlock = 18U, /*!< Read Multiple Block */ + kSDMMC_SetBlockCount = 23U, /*!< Set Block Count */ + kSDMMC_WriteSingleBlock = 24U, /*!< Write Single Block */ + kSDMMC_WriteMultipleBlock = 25U, /*!< Write Multiple Block */ + kSDMMC_ProgramCsd = 27U, /*!< Program CSD */ + kSDMMC_SetWriteProtect = 28U, /*!< Set Write Protect */ + kSDMMC_ClearWriteProtect = 29U, /*!< Clear Write Protect */ + kSDMMC_SendWriteProtect = 30U, /*!< Send Write Protect */ + kSDMMC_Erase = 38U, /*!< Erase */ + kSDMMC_LockUnlock = 42U, /*!< Lock Unlock */ + kSDMMC_ApplicationCommand = 55U, /*!< Send Application Command */ + kSDMMC_GeneralCommand = 56U, /*!< General Purpose Command */ + kSDMMC_ReadOcr = 58U, /*!< Read OCR */ +} sdmmc_command_t; + +/*! @brief sdio card cccr register number */ +#define SDIO_CCCR_REG_NUMBER (0x16U) +/*! @brief sdio IO ready timeout steps */ +#ifndef SDIO_IO_READY_TIMEOUT_UNIT +#define SDIO_IO_READY_TIMEOUT_UNIT (10U) +#endif +/*! @brief sdio card cccr register addr */ +enum _sdio_cccr_reg +{ + kSDIO_RegCCCRSdioVer = 0x00U, /*!< CCCR & SDIO version*/ + kSDIO_RegSDVersion = 0x01U, /*!< SD version */ + kSDIO_RegIOEnable = 0x02U, /*!< io enable register */ + kSDIO_RegIOReady = 0x03U, /*!< io ready register */ + kSDIO_RegIOIntEnable = 0x04U, /*!< io interrupt enable register */ + kSDIO_RegIOIntPending = 0x05U, /*!< io interrupt pending register */ + kSDIO_RegIOAbort = 0x06U, /*!< io abort register */ + kSDIO_RegBusInterface = 0x07U, /*!< bus interface register */ + kSDIO_RegCardCapability = 0x08U, /*!< card capability register */ + kSDIO_RegCommonCISPointer = 0x09U, /*!< common CIS pointer register */ + kSDIO_RegBusSuspend = 0x0C, /*!< bus suspend register */ + kSDIO_RegFunctionSelect = 0x0DU, /*!< function select register */ + kSDIO_RegExecutionFlag = 0x0EU, /*!< execution flag register */ + kSDIO_RegReadyFlag = 0x0FU, /*!< ready flag register */ + kSDIO_RegFN0BlockSizeLow = 0x10U, /*!< FN0 block size register */ + kSDIO_RegFN0BlockSizeHigh = 0x11U, /*!< FN0 block size register */ + kSDIO_RegPowerControl = 0x12U, /*!< power control register */ + kSDIO_RegBusSpeed = 0x13U, /*!< bus speed register */ + kSDIO_RegUHSITimingSupport = 0x14U, /*!< UHS-I timing support register */ + kSDIO_RegDriverStrength = 0x15U, /*!< Driver strength register */ + kSDIO_RegInterruptExtension = 0x16U, /*!< Interrupt extension register */ +}; + +/*! @brief sdio card individual commands */ +typedef enum _sdio_command +{ + kSDIO_SendRelativeAddress = 3U, /*!< send relative address */ + kSDIO_SendOperationCondition = 5U, /*!< send operation condition */ + kSDIO_SendInterfaceCondition = 8U, /*!< send interface condition */ + kSDIO_RWIODirect = 52U, /*!< read/write IO direct command */ + kSDIO_RWIOExtended = 53U, /*!< read/write IO extended command */ +} sdio_command_t; + +/*! @brief sdio card individual commands */ +typedef enum _sdio_func_num +{ + kSDIO_FunctionNum0, /*!< sdio function0*/ + kSDIO_FunctionNum1, /*!< sdio function1*/ + kSDIO_FunctionNum2, /*!< sdio function2*/ + kSDIO_FunctionNum3, /*!< sdio function3*/ + kSDIO_FunctionNum4, /*!< sdio function4*/ + kSDIO_FunctionNum5, /*!< sdio function5*/ + kSDIO_FunctionNum6, /*!< sdio function6*/ + kSDIO_FunctionNum7, /*!< sdio function7*/ + kSDIO_FunctionMemory, /*!< for combo card*/ +} sdio_func_num_t; + +#define SDIO_CMD_ARGUMENT_RW_POS (31U) /*!< read/write flag position */ +#define SDIO_CMD_ARGUMENT_FUNC_NUM_POS (28U) /*!< function number position */ +#define SDIO_DIRECT_CMD_ARGUMENT_RAW_POS (27U) /*!< direct raw flag position */ +#define SDIO_CMD_ARGUMENT_REG_ADDR_POS (9U) /*!< direct reg addr position */ +#define SDIO_CMD_ARGUMENT_REG_ADDR_MASK (0x1FFFFU) /*!< direct reg addr mask */ +#define SDIO_DIRECT_CMD_DATA_MASK (0xFFU) /*!< data mask */ + +#define SDIO_EXTEND_CMD_ARGUMENT_BLOCK_MODE_POS (27U) /*!< extended command argument block mode bit position */ +#define SDIO_EXTEND_CMD_ARGUMENT_OP_CODE_POS (26U) /*!< extended command argument OP Code bit position */ +#define SDIO_EXTEND_CMD_BLOCK_MODE_MASK (0x08000000U) /*!< block mode mask */ +#define SDIO_EXTEND_CMD_OP_CODE_MASK (0x04000000U) /*!< op code mask */ +#define SDIO_EXTEND_CMD_COUNT_MASK (0x1FFU) /*!< byte/block count mask */ +#define SDIO_MAX_BLOCK_SIZE (2048U) /*!< max block size */ +#define SDIO_FBR_BASE(x) (x * 0x100U) /*!< function basic register */ +#define SDIO_TPL_CODE_END (0xFFU) /*!< tuple end */ +#define SDIO_TPL_CODE_MANIFID (0x20U) /*!< manufacturer ID */ +#define SDIO_TPL_CODE_FUNCID (0x21U) /*!< function ID */ +#define SDIO_TPL_CODE_FUNCE (0x22U) /*!< function extension tuple*/ +/*! @brief sdio command response flag */ +enum _sdio_status_flag +{ + kSDIO_StatusCmdCRCError = 0x8000U, /*!< the CRC check of the previous cmd fail*/ + kSDIO_StatusIllegalCmd = 0x4000U, /*!< cmd illegal for the card state */ + kSDIO_StatusR6Error = 0x2000U, /*!< special for R6 error status */ + kSDIO_StatusError = 0x0800U, /*!< A general or an unknown error occurred */ + kSDIO_StatusFunctionNumError = 0x0200U, /*!< invail function error */ + kSDIO_StatusOutofRange = 0x0100U, /*!< cmd argument was out of the allowed range*/ +}; + +/*! @brief sdio operation condition flag */ +enum _sdio_ocr_flag +{ + kSDIO_OcrPowerUpBusyFlag = 31, /*!< Power up busy status */ + kSDIO_OcrIONumber = 28, /*!< number of IO function */ + kSDIO_OcrMemPresent = 27, /*!< memory present flag */ + + kSDIO_OcrVdd20_21Flag = 8, /*!< VDD 2.0-2.1 */ + kSDIO_OcrVdd21_22Flag = 9, /*!< VDD 2.1-2.2 */ + kSDIO_OcrVdd22_23Flag = 10, /*!< VDD 2.2-2.3 */ + kSDIO_OcrVdd23_24Flag = 11, /*!< VDD 2.3-2.4 */ + kSDIO_OcrVdd24_25Flag = 12, /*!< VDD 2.4-2.5 */ + kSDIO_OcrVdd25_26Flag = 13, /*!< VDD 2.5-2.6 */ + kSDIO_OcrVdd26_27Flag = 14, /*!< VDD 2.6-2.7 */ + kSDIO_OcrVdd27_28Flag = 15, /*!< VDD 2.7-2.8 */ + kSDIO_OcrVdd28_29Flag = 16, /*!< VDD 2.8-2.9 */ + kSDIO_OcrVdd29_30Flag = 17, /*!< VDD 2.9-3.0 */ + kSDIO_OcrVdd30_31Flag = 18, /*!< VDD 2.9-3.0 */ + kSDIO_OcrVdd31_32Flag = 19, /*!< VDD 3.0-3.1 */ + kSDIO_OcrVdd32_33Flag = 20, /*!< VDD 3.1-3.2 */ + kSDIO_OcrVdd33_34Flag = 21, /*!< VDD 3.2-3.3 */ + kSDIO_OcrVdd34_35Flag = 22, /*!< VDD 3.3-3.4 */ + kSDIO_OcrVdd35_36Flag = 23, /*!< VDD 3.4-3.5 */ +}; +/*! @brief sdio ocr voltage window mask */ +#define SDIO_OCR_VOLTAGE_WINDOW_MASK (0xFFFFU << 8U) + +/*! @brief sdio ocr reigster IO NUMBER mask */ +#define SDIO_OCR_IO_NUM_MASK (7U << kSDIO_OcrIONumber) + +/*! @brief sdio capability flag */ +enum _sdio_capability_flag +{ + kSDIO_CCCRSupportDirectCmdDuringDataTrans = (1U << 0U), /*!< support direct cmd during data transfer */ + kSDIO_CCCRSupportMultiBlock = (1U << 1U), /*!< support multi block mode */ + kSDIO_CCCRSupportReadWait = (1U << 2U), /*!< support read wait */ + kSDIO_CCCRSupportSuspendResume = (1U << 3U), /*!< support suspend resume */ + kSDIO_CCCRSupportIntDuring4BitDataTrans = (1U << 4U), /*!< support interrupt during 4-bit data transfer */ + kSDIO_CCCRSupportLowSpeed1Bit = (1U << 6U), /*!< support low speed 1bit mode */ + kSDIO_CCCRSupportLowSpeed4Bit = (1U << 7U), /*!< support low speed 4bit mode */ + kSDIO_CCCRSupportMasterPowerControl = (1U << 8U), /*!< support master power control */ + kSDIO_CCCRSupportHighSpeed = (1U << 9U), /*!< support high speed */ + kSDIO_CCCRSupportContinuousSPIInt = (1U << 10U), /*!< support continuous SPI interrupt */ +}; +/*! @brief UHS timing mode flag */ +#define SDIO_CCCR_SUPPORT_HIGHSPEED (1u << 9U) +#define SDIO_CCCR_SUPPORT_SDR50 (1U << 11U) +#define SDIO_CCCR_SUPPORT_SDR104 (1U << 12U) +#define SDIO_CCCR_SUPPORT_DDR50 (1U << 13U) +#define SDIO_CCCR_SUPPORT_DRIVER_TYPE_A (1U << 14U) +#define SDIO_CCCR_SUPPORT_DRIVER_TYPE_C (1U << 15U) +#define SDIO_CCCR_SUPPORT_DRIVER_TYPE_D (1U << 16U) +#define SDIO_CCCR_SUPPORT_ASYNC_INT (1U << 17U) + +#define SDIO_CCCR_BUS_SPEED_MASK (7U << 1U) +#define SDIO_CCCR_ENABLE_HIGHSPEED_MODE (1U << 1U) +#define SDIO_CCCR_ENABLE_SDR50_MODE (2U << 1U) +#define SDIO_CCCR_ENABLE_SDR104_MODE (3U << 1U) +#define SDIO_CCCR_ENABLE_DDR50_MODE (4U << 1U) + +/*! @brief Driver type flag */ +#define SDIO_CCCR_DRIVER_TYPE_MASK (3U << 4U) +#define SDIO_CCCR_ENABLE_DRIVER_TYPE_B (0U << 4U) +#define SDIO_CCCR_ENABLE_DRIVER_TYPE_A (1U << 4U) +#define SDIO_CCCR_ENABLE_DRIVER_TYPE_C (2U << 4U) +#define SDIO_CCCR_ENABLE_DRIVER_TYPE_D (3U << 4U) + +/*! @brief aync interrupt flag*/ +#define SDIO_CCCR_ASYNC_INT_MASK (1U) +#define SDIO_CCCR_ENABLE_AYNC_INT (1U << 1U) + +/*! @brief 8 bit data bus flag*/ +#define SDIO_CCCR_SUPPORT_8BIT_BUS (1U << 18U) +#define SDIO_CCCR_SUPPORT_LOW_SPEED_4BIT_BUS (1U << 7U) +/*! @brief sdio fbr flag */ +enum _sdio_fbr_flag +{ + kSDIO_FBRSupportCSA = (1U << 0U), /*!< function support CSA */ + kSDIO_FBRSupportPowerSelection = (1U << 1U), /*!< function support power selection */ +}; + +/*! @brief sdio bus width */ +typedef enum _sdio_bus_width +{ + kSDIO_DataBus1Bit = 0x00U, /*!< 1 bit bus mode */ + kSDIO_DataBus4Bit = 0X02U, /*!< 4 bit bus mode*/ + kSDIO_DataBus8Bit = 0X03U, /*!< 8 bit bus mode*/ +} sdio_bus_width_t; + +/*! @brief MMC card individual commands */ +typedef enum _mmc_command +{ + kMMC_SendOperationCondition = 1U, /*!< Send Operation Condition */ + kMMC_SetRelativeAddress = 3U, /*!< Set Relative Address */ + kMMC_SleepAwake = 5U, /*!< Sleep Awake */ + kMMC_Switch = 6U, /*!< Switch */ + kMMC_SendExtendedCsd = 8U, /*!< Send EXT_CSD */ + kMMC_ReadDataUntilStop = 11U, /*!< Read Data Until Stop */ + kMMC_BusTestRead = 14U, /*!< Test Read */ + kMMC_SendingBusTest = 19U, /*!< test bus width cmd*/ + kMMC_WriteDataUntilStop = 20U, /*!< Write Data Until Stop */ + kMMC_SendTuningBlock = 21U, /*!< MMC sending tuning block */ + kMMC_ProgramCid = 26U, /*!< Program CID */ + kMMC_EraseGroupStart = 35U, /*!< Erase Group Start */ + kMMC_EraseGroupEnd = 36U, /*!< Erase Group End */ + kMMC_FastInputOutput = 39U, /*!< Fast IO */ + kMMC_GoInterruptState = 40U, /*!< Go interrupt State */ +} mmc_command_t; + +/*! @brief MMC card classified as voltage range */ +typedef enum _mmc_classified_voltage +{ + kMMC_ClassifiedVoltageHigh = 0U, /*!< High-voltage MMC card */ + kMMC_ClassifiedVoltageDual = 1U, /*!< Dual-voltage MMC card */ +} mmc_classified_voltage_t; + +/*! @brief MMC card classified as density level */ +typedef enum _mmc_classified_density +{ + kMMC_ClassifiedDensityWithin2GB = 0U, /*!< Density byte is less than or equal 2GB */ + kMMC_ClassifiedDensityHigher2GB = 1U, /* Density byte is higher than 2GB */ +} mmc_classified_density_t; + +/*! @brief The bit mask for VOLTAGE WINDOW 1.70V to 1.95V field in OCR */ +#define MMC_OCR_V170TO195_SHIFT (7U) +/*! @brief The bit mask for VOLTAGE WINDOW 1.70V to 1.95V field in OCR */ +#define MMC_OCR_V170TO195_MASK (0x00000080U) +/*! @brief The bit shift for VOLTAGE WINDOW 2.00V to 2.60V field in OCR */ +#define MMC_OCR_V200TO260_SHIFT (8U) +/*! @brief The bit mask for VOLTAGE WINDOW 2.00V to 2.60V field in OCR */ +#define MMC_OCR_V200TO260_MASK (0x00007F00U) +/*! @brief The bit shift for VOLTAGE WINDOW 2.70V to 3.60V field in OCR */ +#define MMC_OCR_V270TO360_SHIFT (15U) +/*! @brief The bit mask for VOLTAGE WINDOW 2.70V to 3.60V field in OCR */ +#define MMC_OCR_V270TO360_MASK (0x00FF8000U) +/*! @brief The bit shift for ACCESS MODE field in OCR */ +#define MMC_OCR_ACCESS_MODE_SHIFT (29U) +/*! @brief The bit mask for ACCESS MODE field in OCR */ +#define MMC_OCR_ACCESS_MODE_MASK (0x60000000U) +/*! @brief The bit shift for BUSY field in OCR */ +#define MMC_OCR_BUSY_SHIFT (31U) +/*! @brief The bit mask for BUSY field in OCR */ +#define MMC_OCR_BUSY_MASK (1U << MMC_OCR_BUSY_SHIFT) + +/*! @brief MMC card access mode(Access mode in OCR). */ +typedef enum _mmc_access_mode +{ + kMMC_AccessModeByte = 0U, /*!< The card should be accessed as byte */ + kMMC_AccessModeSector = 2U, /*!< The card should be accessed as sector */ +} mmc_access_mode_t; + +/*! @brief MMC card voltage window(VDD voltage window in OCR). */ +typedef enum _mmc_voltage_window +{ + kMMC_VoltageWindowNone = 0U, /*!< voltage window is not define by user*/ + kMMC_VoltageWindow120 = 0x01U, /*!< Voltage window is 1.20V */ + kMMC_VoltageWindow170to195 = 0x02U, /*!< Voltage window is 1.70V to 1.95V */ + kMMC_VoltageWindows270to360 = 0x1FFU, /*!< Voltage window is 2.70V to 3.60V */ +} mmc_voltage_window_t; + +/*! @brief CSD structure version(CSD_STRUCTURE in CSD). */ +typedef enum _mmc_csd_structure_version +{ + kMMC_CsdStrucureVersion10 = 0U, /*!< CSD version No. 1.0 */ + kMMC_CsdStrucureVersion11 = 1U, /*!< CSD version No. 1.1 */ + kMMC_CsdStrucureVersion12 = 2U, /*!< CSD version No. 1.2 */ + kMMC_CsdStrucureVersionInExtcsd = 3U, /*!< Version coded in Extended CSD */ +} mmc_csd_structure_version_t; + +/*! @brief MMC card specification version(SPEC_VERS in CSD). */ +typedef enum _mmc_specification_version +{ + kMMC_SpecificationVersion0 = 0U, /*!< Allocated by MMCA */ + kMMC_SpecificationVersion1 = 1U, /*!< Allocated by MMCA */ + kMMC_SpecificationVersion2 = 2U, /*!< Allocated by MMCA */ + kMMC_SpecificationVersion3 = 3U, /*!< Allocated by MMCA */ + kMMC_SpecificationVersion4 = 4U, /*!< Version 4.1/4.2/4.3/4.41-4.5-4.51-5.0 */ +} mmc_specification_version_t; + +/*! @brief The bit shift for FREQUENCY UNIT field in TRANSFER SPEED(TRAN-SPEED in Extended CSD) */ +#define MMC_TRANSFER_SPEED_FREQUENCY_UNIT_SHIFT (0U) +/*! @brief The bit mask for FRQEUENCY UNIT in TRANSFER SPEED */ +#define MMC_TRANSFER_SPEED_FREQUENCY_UNIT_MASK (0x07U) +/*! @brief The bit shift for MULTIPLIER field in TRANSFER SPEED */ +#define MMC_TRANSFER_SPEED_MULTIPLIER_SHIFT (3U) +/*! @brief The bit mask for MULTIPLIER field in TRANSFER SPEED */ +#define MMC_TRANSFER_SPEED_MULTIPLIER_MASK (0x78U) + +/*! @brief Read the value of FREQUENCY UNIT in TRANSFER SPEED. */ +#define READ_MMC_TRANSFER_SPEED_FREQUENCY_UNIT(CSD) \ + (((CSD.transferSpeed) & MMC_TRANSFER_SPEED_FREQUENCY_UNIT_MASK) >> MMC_TRANSFER_SPEED_FREQUENCY_UNIT_SHIFT) +/*! @brief Read the value of MULTIPLER filed in TRANSFER SPEED. */ +#define READ_MMC_TRANSFER_SPEED_MULTIPLIER(CSD) \ + (((CSD.transferSpeed) & MMC_TRANSFER_SPEED_MULTIPLIER_MASK) >> MMC_TRANSFER_SPEED_MULTIPLIER_SHIFT) + +/*! @brief MMC card Extended CSD fix version(EXT_CSD_REV in Extended CSD) */ +enum _mmc_extended_csd_revision +{ + kMMC_ExtendedCsdRevision10 = 0U, /*!< Revision 1.0 */ + kMMC_ExtendedCsdRevision11 = 1U, /*!< Revision 1.1 */ + kMMC_ExtendedCsdRevision12 = 2U, /*!< Revision 1.2 */ + kMMC_ExtendedCsdRevision13 = 3U, /*!< Revision 1.3 MMC4.3*/ + kMMC_ExtendedCsdRevision14 = 4U, /*!< Revision 1.4 obsolete*/ + kMMC_ExtendedCsdRevision15 = 5U, /*!< Revision 1.5 MMC4.41*/ + kMMC_ExtendedCsdRevision16 = 6U, /*!< Revision 1.6 MMC4.5*/ + kMMC_ExtendedCsdRevision17 = 7U, /*!< Revision 1.7 MMC5.0 */ +}; + +/*! @brief MMC card command set(COMMAND_SET in Extended CSD) */ +typedef enum _mmc_command_set +{ + kMMC_CommandSetStandard = 0U, /*!< Standard MMC */ + kMMC_CommandSet1 = 1U, /*!< Command set 1 */ + kMMC_CommandSet2 = 2U, /*!< Command set 2 */ + kMMC_CommandSet3 = 3U, /*!< Command set 3 */ + kMMC_CommandSet4 = 4U, /*!< Command set 4 */ +} mmc_command_set_t; + +/*! @brief boot support(BOOT_INFO in Extended CSD) */ +enum _mmc_support_boot_mode +{ + kMMC_SupportAlternateBoot = 1U, /*!< support alternative boot mode*/ + kMMC_SupportDDRBoot = 2U, /*!< support DDR boot mode*/ + kMMC_SupportHighSpeedBoot = 4U, /*!< support high speed boot mode*/ +}; +/*! @brief The power class value bit mask when bus in 4 bit mode */ +#define MMC_POWER_CLASS_4BIT_MASK (0x0FU) +/*! @brief The power class current value bit mask when bus in 8 bit mode */ +#define MMC_POWER_CLASS_8BIT_MASK (0xF0U) + +/*! @brief MMC card high-speed timing(HS_TIMING in Extended CSD) */ +typedef enum _mmc_high_speed_timing +{ + kMMC_HighSpeedTimingNone = 0U, /*!< MMC card using none high-speed timing */ + kMMC_HighSpeedTiming = 1U, /*!< MMC card using high-speed timing */ + kMMC_HighSpeed200Timing = 2U, /*!< MMC card high speed 200 timing*/ + kMMC_HighSpeed400Timing = 3U, /*!< MMC card high speed 400 timing*/ +} mmc_high_speed_timing_t; + +/*! @brief The number of data bus width type */ +#define MMC_DATA_BUS_WIDTH_TYPE_NUMBER (3U) +/*! @brief MMC card data bus width(BUS_WIDTH in Extended CSD) */ +typedef enum _mmc_data_bus_width +{ + kMMC_DataBusWidth1bit = 0U, /*!< MMC data bus width is 1 bit */ + kMMC_DataBusWidth4bit = 1U, /*!< MMC data bus width is 4 bits */ + kMMC_DataBusWidth8bit = 2U, /*!< MMC data bus width is 8 bits */ + kMMC_DataBusWidth4bitDDR = 5U, /*!< MMC data bus width is 4 bits ddr */ + kMMC_DataBusWidth8bitDDR = 6U, /*!< MMC data bus width is 8 bits ddr */ +} mmc_data_bus_width_t; + +/*! @brief MMC card boot partition enabled(BOOT_PARTITION_ENABLE in Extended CSD) */ +typedef enum _mmc_boot_partition_enable +{ + kMMC_BootPartitionEnableNot = 0U, /*!< Device not boot enabled (default) */ + kMMC_BootPartitionEnablePartition1 = 1U, /*!< Boot partition 1 enabled for boot */ + kMMC_BootPartitionEnablePartition2 = 2U, /*!< Boot partition 2 enabled for boot */ + kMMC_BootPartitionEnableUserAera = 7U, /*!< User area enabled for boot */ +} mmc_boot_partition_enable_t; + +/*! @brief boot mode configuration + * Note: HS200 & HS400 is not support during BOOT operation. + */ +typedef enum _mmc_boot_timing_mode +{ + kMMC_BootModeSDRWithDefaultTiming = 0U << 3U, /*!< boot mode single data rate with backward compatiable timings */ + kMMC_BootModeSDRWithHighSpeedTiming = 1U << 3U, /*!< boot mode single data rate with high speed timing */ + kMMC_BootModeDDRTiming = 2U << 3U, /*!< boot mode dual date rate */ +} mmc_boot_timing_mode_t; + +/*! @brief MMC card boot partition write protect configurations + * All the bits in BOOT_WP register, except the two R/W bits B_PERM_WP_DIS + * and B_PERM_WP_EN, shall only be written once per power cycle.The protection + * mdde intended for both boot areas will be set with a single write. + */ +typedef enum _mmc_boot_partition_wp +{ + kMMC_BootPartitionWPDisable = 0x50U, /*!< boot partition write protection disable */ + kMMC_BootPartitionPwrWPToBothPartition = + 0x01U, /*!< power on period write protection apply to both boot partitions */ + kMMC_BootPartitionPermWPToBothPartition = 0x04U, /*!< permanent write protection apply to both boot partitions */ + + kMMC_BootPartitionPwrWPToPartition1 = (1U << 7U) | 1U, /*!< power on period write protection apply to partition1 */ + kMMC_BootPartitionPwrWPToPartition2 = (1U << 7U) | 3U, /*!< power on period write protection apply to partition2 */ + + kMMC_BootPartitionPermWPToPartition1 = + (1U << 7U) | (1U << 2U), /*!< permanent write protection apply to partition1 */ + kMMC_BootPartitionPermWPToPartition2 = + (1U << 7U) | (3U << 2U), /*!< permanent write protection apply to partition2 */ + + kMMC_BootPartitionPermWPToPartition1PwrWPToPartition2 = + (1U << 7U) | (1U << 2U) | + 3U, /*!< permanent write protection apply to partition1, power on period write protection apply to partition2 */ + kMMC_BootPartitionPermWPToPartition2PwrWPToPartition1 = + (1U << 7U) | (3U << 2U) | + 1U, /*!< permanent write protection apply to partition2, power on period write protection apply to partition1 */ +} mmc_boot_partition_wp_t; + +/*! @brief MMC card boot partition write protect status */ +enum _mmc_boot_partition_wp_status +{ + kMMC_BootPartitionNotProtected = 0U, /*!< boot partition not protected */ + kMMC_BootPartitionPwrProtected = 1U, /*!< boot partition is power on period write protected */ + kMMC_BootPartitionPermProtected = 2U, /*!< boot partition is permanently protected */ +}; + +/*! @brief MMC card partition to be accessed(BOOT_PARTITION_ACCESS in Extended CSD) */ +typedef enum _mmc_access_partition +{ + kMMC_AccessPartitionUserAera = 0U, /*!< No access to boot partition (default), normal partition */ + kMMC_AccessPartitionBoot1 = 1U, /*!< Read/Write boot partition 1 */ + kMMC_AccessPartitionBoot2 = 2U, /*!< Read/Write boot partition 2*/ + kMMC_AccessRPMB = 3U, /*!< Replay protected mem block */ + kMMC_AccessGeneralPurposePartition1 = 4U, /*!< access to general purpose partition 1 */ + kMMC_AccessGeneralPurposePartition2 = 5U, /*!< access to general purpose partition 2 */ + kMMC_AccessGeneralPurposePartition3 = 6U, /*!< access to general purpose partition 3 */ + kMMC_AccessGeneralPurposePartition4 = 7U, /*!< access to general purpose partition 4 */ +} mmc_access_partition_t; + +/*! @brief The bit shift for PARTITION ACCESS filed in BOOT CONFIG (BOOT_CONFIG in Extend CSD) */ +#define MMC_PARTITION_CONFIG_PARTITION_ACCESS_SHIFT (0U) +/*! @brief The bit mask for PARTITION ACCESS field in BOOT CONFIG */ +#define MMC_PARTITION_CONFIG_PARTITION_ACCESS_MASK (0x00000007U) +/*! @brief The bit shift for PARTITION ENABLE field in BOOT CONFIG */ +#define MMC_PARTITION_CONFIG_PARTITION_ENABLE_SHIFT (3U) +/*! @brief The bit mask for PARTITION ENABLE field in BOOT CONFIG */ +#define MMC_PARTITION_CONFIG_PARTITION_ENABLE_MASK (0x00000038U) +/*! @brief The bit shift for ACK field in BOOT CONFIG */ +#define MMC_PARTITION_CONFIG_BOOT_ACK_SHIFT (6U) +/*! @brief The bit mask for ACK field in BOOT CONFIG */ +#define MMC_PARTITION_CONFIG_BOOT_ACK_MASK (0x00000040U) +/*! @brief The bit shift for BOOT BUS WIDTH field in BOOT CONFIG */ +#define MMC_BOOT_BUS_CONDITION_BUS_WIDTH_SHIFT (0U) +/*! @brief The bit mask for BOOT BUS WIDTH field in BOOT CONFIG */ +#define MMC_BOOT_BUS_CONDITION_BUS_WIDTH_MASK (3U) +/*! @brief The bit shift for BOOT BUS WIDTH RESET field in BOOT CONFIG */ +#define MMC_BOOT_BUS_CONDITION_RESET_BUS_CONDITION_SHIFT (2U) +/*! @brief The bit mask for BOOT BUS WIDTH RESET field in BOOT CONFIG */ +#define MMC_BOOT_BUS_CONDITION_RESET_BUS_CONDITION_MASK (4U) +/*! @brief The bit mask for BOOT BUS WIDTH RESET field in BOOT CONFIG */ +#define MMC_BOOT_BUS_CONDITION_BOOT_MODE_MASK (0x18U) + +/*! @brief MMC card CSD register flags */ +enum _mmc_csd_flag +{ + kMMC_CsdReadBlockPartialFlag = (1U << 0U), /*!< Partial blocks for read allowed */ + kMMC_CsdWriteBlockMisalignFlag = (1U << 1U), /*!< Write block misalignment */ + kMMC_CsdReadBlockMisalignFlag = (1U << 2U), /*!< Read block misalignment */ + kMMC_CsdDsrImplementedFlag = (1U << 3U), /*!< DSR implemented */ + kMMC_CsdWriteProtectGroupEnabledFlag = (1U << 4U), /*!< Write protect group enabled */ + kMMC_CsdWriteBlockPartialFlag = (1U << 5U), /*!< Partial blocks for write allowed */ + kMMC_ContentProtectApplicationFlag = (1U << 6U), /*!< Content protect application */ + kMMC_CsdFileFormatGroupFlag = (1U << 7U), /*!< File format group */ + kMMC_CsdCopyFlag = (1U << 8U), /*!< Copy flag */ + kMMC_CsdPermanentWriteProtectFlag = (1U << 9U), /*!< Permanent write protection */ + kMMC_CsdTemporaryWriteProtectFlag = (1U << 10U), /*!< Temporary write protection */ +}; + +/*! @brief Extended CSD register access mode(Access mode in CMD6). */ +typedef enum _mmc_extended_csd_access_mode +{ + kMMC_ExtendedCsdAccessModeCommandSet = 0U, /*!< Command set related setting */ + kMMC_ExtendedCsdAccessModeSetBits = 1U, /*!< Set bits in specific byte in Extended CSD */ + kMMC_ExtendedCsdAccessModeClearBits = 2U, /*!< Clear bits in specific byte in Extended CSD */ + kMMC_ExtendedCsdAccessModeWriteBits = 3U, /*!< Write a value to specific byte in Extended CSD */ +} mmc_extended_csd_access_mode_t; + +/*! @brief EXT CSD byte index */ +typedef enum _mmc_extended_csd_index +{ + kMMC_ExtendedCsdIndexBootPartitionWP = 173U, /*!< Boot partition write protect */ + kMMC_ExtendedCsdIndexEraseGroupDefinition = 175U, /*!< Erase Group Def */ + kMMC_ExtendedCsdIndexBootBusConditions = 177U, /*!< Boot Bus conditions */ + kMMC_ExtendedCsdIndexBootConfigWP = 178U, /*!< Boot config write protect */ + kMMC_ExtendedCsdIndexPartitionConfig = 179U, /*!< Partition Config, before BOOT_CONFIG */ + kMMC_ExtendedCsdIndexBusWidth = 183U, /*!< Bus Width */ + kMMC_ExtendedCsdIndexHighSpeedTiming = 185U, /*!< High-speed Timing */ + kMMC_ExtendedCsdIndexPowerClass = 187U, /*!< Power Class */ + kMMC_ExtendedCsdIndexCommandSet = 191U, /*!< Command Set */ +} mmc_extended_csd_index_t; + +/*! @brief mmc driver strength */ +enum _mmc_driver_strength +{ + kMMC_DriverStrength0 = 0U, /*!< Driver type0 ,nominal impedance 50ohm */ + kMMC_DriverStrength1 = 1U, /*!< Driver type1 ,nominal impedance 33ohm */ + kMMC_DriverStrength2 = 2U, /*!< Driver type2 ,nominal impedance 66ohm */ + kMMC_DriverStrength3 = 3U, /*!< Driver type3 ,nominal impedance 100ohm */ + kMMC_DriverStrength4 = 4U, /*!< Driver type4 ,nominal impedance 40ohm */ +}; + +/*! @brief mmc extended csd flags*/ +typedef enum _mmc_extended_csd_flags +{ + kMMC_ExtCsdExtPartitionSupport = (1 << 0U), /*!< partitioning support[160] */ + kMMC_ExtCsdEnhancePartitionSupport = (1 << 1U), /*!< partitioning support[160] */ + kMMC_ExtCsdPartitioningSupport = (1 << 2U), /*!< partitioning support[160] */ + kMMC_ExtCsdPrgCIDCSDInDDRModeSupport = (1 << 3U), /*!< CMD26 and CMD27 are support dual data rate [130]*/ + kMMC_ExtCsdBKOpsSupport = (1 << 4U), /*!< background operation feature support [502]*/ + kMMC_ExtCsdDataTagSupport = (1 << 5U), /*!< data tag support[499]*/ + kMMC_ExtCsdModeOperationCodeSupport = (1 << 6U), /*!< mode operation code support[493]*/ +} mmc_extended_csd_flags_t; + +/*! @brief MMC card boot mode */ +enum _mmc_boot_mode +{ + kMMC_BootModeNormal = 0U, /*!< Normal boot */ + kMMC_BootModeAlternative = 1U, /*!< Alternative boot */ +}; + +/*! @brief The length of Extended CSD register, unit as bytes. */ +#define MMC_EXTENDED_CSD_BYTES (512U) + +/*! @brief MMC card default relative address */ +#define MMC_DEFAULT_RELATIVE_ADDRESS (2U) + +/*! @brief SD card product name length united as bytes. */ +#define SD_PRODUCT_NAME_BYTES (5U) + +/*! @brief sdio card FBR register */ +typedef struct _sdio_fbr +{ + uint8_t flags; /*!< current io flags */ + uint8_t ioStdFunctionCode; /*!< current io standard function code */ + uint8_t ioExtFunctionCode; /*!< current io extended function code*/ + uint32_t ioPointerToCIS; /*!< current io pointer to CIS */ + uint32_t ioPointerToCSA; /*!< current io pointer to CSA*/ + uint16_t ioBlockSize; /*!< current io block size */ +} sdio_fbr_t; + +/*! @brief sdio card common CIS */ +typedef struct _sdio_common_cis +{ + /* manufacturer identification string tuple */ + uint16_t mID; /*!< manufacturer code */ + uint16_t mInfo; /*!< manufacturer information */ + + /*function identification tuple */ + uint8_t funcID; /*!< function ID */ + + /* function extension tuple */ + uint16_t fn0MaxBlkSize; /*!< function 0 max block size */ + uint8_t maxTransSpeed; /*!< max data transfer speed for all function */ + +} sdio_common_cis_t; + +/*! @brief sdio card function CIS */ +typedef struct _sdio_func_cis +{ + /*function identification tuple */ + uint8_t funcID; /*!< function ID */ + + /* function extension tuple */ + uint8_t funcInfo; /*!< function info */ + uint8_t ioVersion; /*!< level of application specification this io support */ + uint32_t cardPSN; /*!< product serial number */ + uint32_t ioCSASize; /*!< avaliable CSA size for io */ + uint8_t ioCSAProperty; /*!< CSA property */ + uint16_t ioMaxBlockSize; /*!< io max transfer data size */ + uint32_t ioOCR; /*!< io ioeration condition */ + uint8_t ioOPMinPwr; /*!< min current in operation mode */ + uint8_t ioOPAvgPwr; /*!< average current in operation mode */ + uint8_t ioOPMaxPwr; /*!< max current in operation mode */ + uint8_t ioSBMinPwr; /*!< min current in standby mode */ + uint8_t ioSBAvgPwr; /*!< average current in standby mode */ + uint8_t ioSBMaxPwr; /*!< max current in standby mode */ + + uint16_t ioMinBandWidth; /*!< io min transfer bandwidth */ + uint16_t ioOptimumBandWidth; /*!< io optimum transfer bandwidth */ + uint16_t ioReadyTimeout; /*!< timeout value from enalbe to ready */ + uint16_t ioHighCurrentAvgCurrent; /*!< the average peak current (mA) + when IO operating in high current mode */ + uint16_t ioHighCurrentMaxCurrent; /*!< the max peak current (mA) + when IO operating in high current mode */ + uint16_t ioLowCurrentAvgCurrent; /*!< the average peak current (mA) + when IO operating in lower current mode */ + uint16_t ioLowCurrentMaxCurrent; /*!< the max peak current (mA) + when IO operating in lower current mode */ +} sdio_func_cis_t; + +/*! @brief SD AU start value */ +#define SD_AU_START_VALUE (1U) +/*! @brief SD UHS AU start value */ +#define SD_UHS_AU_START_VALUE (7U) + +/*! @brief SD card status */ +typedef struct _sd_status +{ + uint8_t busWidth; /*!< current buswidth */ + uint8_t secureMode; /*!< secured mode */ + uint16_t cardType; /*!< sdcard type */ + uint32_t protectedSize; /*!< size of protected area */ + uint8_t speedClass; /*!< speed class of card */ + uint8_t performanceMove; /*!< Performance of move indicated by 1[MB/S]step */ + uint8_t auSize; /*!< size of AU */ + uint16_t eraseSize; /*!< number of AUs to be erased at a time */ + uint8_t eraseTimeout; /*!< timeout value for erasing areas specified by UNIT OF ERASE AU */ + uint8_t eraseOffset; /*!< fixed offset value added to erase time */ + uint8_t uhsSpeedGrade; /*!< speed grade for UHS mode */ + uint8_t uhsAuSize; /*!< size of AU for UHS mode */ +} sd_status_t; + +/*! @brief SD card CID register */ +typedef struct _sd_cid +{ + uint8_t manufacturerID; /*!< Manufacturer ID [127:120] */ + uint16_t applicationID; /*!< OEM/Application ID [119:104] */ + uint8_t productName[SD_PRODUCT_NAME_BYTES]; /*!< Product name [103:64] */ + uint8_t productVersion; /*!< Product revision [63:56] */ + uint32_t productSerialNumber; /*!< Product serial number [55:24] */ + uint16_t manufacturerData; /*!< Manufacturing date [19:8] */ +} sd_cid_t; + +/*! @brief SD card CSD register */ +typedef struct _sd_csd +{ + uint8_t csdStructure; /*!< CSD structure [127:126] */ + uint8_t dataReadAccessTime1; /*!< Data read access-time-1 [119:112] */ + uint8_t dataReadAccessTime2; /*!< Data read access-time-2 in clock cycles (NSAC*100) [111:104] */ + uint8_t transferSpeed; /*!< Maximum data transfer rate [103:96] */ + uint16_t cardCommandClass; /*!< Card command classes [95:84] */ + uint8_t readBlockLength; /*!< Maximum read data block length [83:80] */ + uint16_t flags; /*!< Flags in _sd_csd_flag */ + uint32_t deviceSize; /*!< Device size [73:62] */ + /* Following fields from 'readCurrentVddMin' to 'deviceSizeMultiplier' exist in CSD version 1 */ + uint8_t readCurrentVddMin; /*!< Maximum read current at VDD min [61:59] */ + uint8_t readCurrentVddMax; /*!< Maximum read current at VDD max [58:56] */ + uint8_t writeCurrentVddMin; /*!< Maximum write current at VDD min [55:53] */ + uint8_t writeCurrentVddMax; /*!< Maximum write current at VDD max [52:50] */ + uint8_t deviceSizeMultiplier; /*!< Device size multiplier [49:47] */ + + uint8_t eraseSectorSize; /*!< Erase sector size [45:39] */ + uint8_t writeProtectGroupSize; /*!< Write protect group size [38:32] */ + uint8_t writeSpeedFactor; /*!< Write speed factor [28:26] */ + uint8_t writeBlockLength; /*!< Maximum write data block length [25:22] */ + uint8_t fileFormat; /*!< File format [11:10] */ +} sd_csd_t; + +/*! @brief The bit shift for RATE UNIT field in TRANSFER SPEED */ +#define SD_TRANSFER_SPEED_RATE_UNIT_SHIFT (0U) +/*! @brief The bit mask for RATE UNIT field in TRANSFER SPEED */ +#define SD_TRANSFER_SPEED_RATE_UNIT_MASK (0x07U) +/*! @brief The bit shift for TIME VALUE field in TRANSFER SPEED */ +#define SD_TRANSFER_SPEED_TIME_VALUE_SHIFT (2U) +/*! @brief The bit mask for TIME VALUE field in TRANSFER SPEED */ +#define SD_TRANSFER_SPEED_TIME_VALUE_MASK (0x78U) +/*! @brief Read the value of FREQUENCY UNIT in TRANSFER SPEED field */ +#define SD_RD_TRANSFER_SPEED_RATE_UNIT(x) \ + (((x.transferSpeed) & SD_TRANSFER_SPEED_RATE_UNIT_MASK) >> SD_TRANSFER_SPEED_RATE_UNIT_SHIFT) +/*! @brief Read the value of TIME VALUE in TRANSFER SPEED field */ +#define SD_RD_TRANSFER_SPEED_TIME_VALUE(x) \ + (((x.transferSpeed) & SD_TRANSFER_SPEED_TIME_VALUE_MASK) >> SD_TRANSFER_SPEED_TIME_VALUE_SHIFT) + +/*! @brief SD card SCR register */ +typedef struct _sd_scr +{ + uint8_t scrStructure; /*!< SCR Structure [63:60] */ + uint8_t sdSpecification; /*!< SD memory card specification version [59:56] */ + uint16_t flags; /*!< SCR flags in _sd_scr_flag */ + uint8_t sdSecurity; /*!< Security specification supported [54:52] */ + uint8_t sdBusWidths; /*!< Data bus widths supported [51:48] */ + uint8_t extendedSecurity; /*!< Extended security support [46:43] */ + uint8_t commandSupport; /*!< Command support bits [33:32] 33-support CMD23, 32-support cmd20*/ + uint32_t reservedForManufacturer; /*!< reserved for manufacturer usage [31:0] */ +} sd_scr_t; + +/*! @brief MMC card product name length united as bytes. */ +#define MMC_PRODUCT_NAME_BYTES (6U) +/*! @brief MMC card CID register. */ +typedef struct _mmc_cid +{ + uint8_t manufacturerID; /*!< Manufacturer ID */ + uint16_t applicationID; /*!< OEM/Application ID */ + uint8_t productName[MMC_PRODUCT_NAME_BYTES]; /*!< Product name */ + uint8_t productVersion; /*!< Product revision */ + uint32_t productSerialNumber; /*!< Product serial number */ + uint8_t manufacturerData; /*!< Manufacturing date */ +} mmc_cid_t; + +/*! @brief MMC card CSD register. */ +typedef struct _mmc_csd +{ + uint8_t csdStructureVersion; /*!< CSD structure [127:126] */ + uint8_t systemSpecificationVersion; /*!< System specification version [125:122] */ + uint8_t dataReadAccessTime1; /*!< Data read access-time 1 [119:112] */ + uint8_t dataReadAccessTime2; /*!< Data read access-time 2 in CLOCK cycles (NSAC*100) [111:104] */ + uint8_t transferSpeed; /*!< Max. bus clock frequency [103:96] */ + uint16_t cardCommandClass; /*!< card command classes [95:84] */ + uint8_t readBlockLength; /*!< Max. read data block length [83:80] */ + uint16_t flags; /*!< Contain flags in _mmc_csd_flag */ + uint16_t deviceSize; /*!< Device size [73:62] */ + uint8_t readCurrentVddMin; /*!< Max. read current @ VDD min [61:59] */ + uint8_t readCurrentVddMax; /*!< Max. read current @ VDD max [58:56] */ + uint8_t writeCurrentVddMin; /*!< Max. write current @ VDD min [55:53] */ + uint8_t writeCurrentVddMax; /*!< Max. write current @ VDD max [52:50] */ + uint8_t deviceSizeMultiplier; /*!< Device size multiplier [49:47] */ + uint8_t eraseGroupSize; /*!< Erase group size [46:42] */ + uint8_t eraseGroupSizeMultiplier; /*!< Erase group size multiplier [41:37] */ + uint8_t writeProtectGroupSize; /*!< Write protect group size [36:32] */ + uint8_t defaultEcc; /*!< Manufacturer default ECC [30:29] */ + uint8_t writeSpeedFactor; /*!< Write speed factor [28:26] */ + uint8_t maxWriteBlockLength; /*!< Max. write data block length [25:22] */ + uint8_t fileFormat; /*!< File format [11:10] */ + uint8_t eccCode; /*!< ECC code [9:8] */ +} mmc_csd_t; + +/*! @brief MMC card Extended CSD register (unit: byte). */ +typedef struct _mmc_extended_csd +{ + /*uint8_t SecureRemoveType;*/ /*!< secure removal type[16]*/ + /*uint8_t enProductStateAware;*/ /*!< product state awareness enablement[17]*/ + /*uint32_t maxPreLoadDataSize;*/ /*!< max preload data size[21-18]*/ + /*uint32_t preLoadDataSize;*/ /*!< pre-load data size[25-22]*/ + /*uint8_t ffuStatus;*/ /*!< FFU status [26]*/ + /*uint8_t modeOperationCode;*/ /*!< mode operation code[29]*/ + /*uint8_t modeConfig;*/ /*!< mode config [30]*/ + /*uint8_t cacheCtrl;*/ /*!< control to turn on/off cache[33]*/ + /*uint8_t pwroffNotify;*/ /*!< power off notification[34]*/ + /*uint8_t packedCmdFailIndex;*/ /*!< packed cmd fail index [35]*/ + /*uint8_t packedCmdStatus;*/ /*!< packed cmd status[36]*/ + /*uint32_t contextConfig[4U];*/ /*!< context configuration[51-37]*/ + /*uint16_t extPartitionAttr;*/ /*!< extended partitions attribut[53-52]*/ + /*uint16_t exceptEventStatus;*/ /*!< exception events status[55-54]*/ + /*uint16_t exceptEventControl;*/ /*!< exception events control[57-56]*/ + /*uint8_t toReleaseAddressedGroup;*/ /*!< number of group to be released[58]*/ + /*uint8_t class6CmdCtrl;*/ /*!< class 6 command control[59]*/ + /*uint8_t intTimeoutEmu;*/ /*!< 1st initiallization after disabling sector size emu[60]*/ + /*uint8_t sectorSize;*/ /*!< sector size[61] */ + /*uint8_t sectorSizeEmu;*/ /*!< sector size emulation[62]*/ + /*uint8_t nativeSectorSize;*/ /*!< native sector size[63]*/ + /*uint8_t periodWakeup;*/ /*!< period wakeup [131]*/ + /*uint8_t tCASESupport;*/ /*!< package case temperature is controlled[132]*/ + /*uint8_t productionStateAware;*/ /*!< production state awareness[133]*/ + /*uint32_t enhanceUsrDataStartAddr;*/ /*!< enhanced user data start addr [139-136]*/ + /*uint32_t enhanceUsrDataSize;*/ /*!< enhanced user data area size[142-140]*/ + /*uint32_t generalPartitionSize[3];*/ /*!< general purpose partition size[154-143]*/ + uint8_t partitionAttribute; /*!< partition attribute [156]*/ + /*uint32_t maxEnhanceAreaSize;*/ /*!< max enhance area size [159-157]*/ + /*uint8_t hpiManagementEn;*/ /*!< HPI management [161]*/ + /*uint8_t writeReliabilityParameter;*/ /*!< write reliability parameter register[166] */ + /*uint8_t writeReliabilitySet;*/ /*!< write reliability setting register[167] */ + /*uint8_t rpmbSizeMult;*/ /*!< RPMB size multi [168]*/ + /*uint8_t fwConfig;*/ /*!< FW configuration[169]*/ + uint8_t userWP; /*!< user write protect register[171] */ + uint8_t bootPartitionWP; /*!< boot write protect register[173]*/ + uint8_t bootWPStatus; /*!< boot write protect status register[174]*/ + uint8_t highDensityEraseGroupDefinition; /*!< High-density erase group definition [175] */ + uint8_t bootDataBusConditions; /*!< Boot bus conditions [177] */ + uint8_t bootConfigProtect; /*!< Boot config protection [178]*/ + uint8_t partitionConfig; /*!< Boot configuration [179] */ + uint8_t eraseMemoryContent; /*!< Erased memory content [181] */ + uint8_t dataBusWidth; /*!< Data bus width mode [183] */ + uint8_t highSpeedTiming; /*!< High-speed interface timing [185] */ + uint8_t powerClass; /*!< Power class [187] */ + uint8_t commandSetRevision; /*!< Command set revision [189] */ + uint8_t commandSet; /*!< Command set [191] */ + uint8_t extendecCsdVersion; /*!< Extended CSD revision [192] */ + uint8_t csdStructureVersion; /*!< CSD structure version [194] */ + uint8_t cardType; /*!< Card Type [196] */ + uint8_t ioDriverStrength; /*!< IO driver strength [197] */ + /*uint8_t OutofInterruptBusyTiming;*/ /*!< out of interrupt busy timing [198] */ + /*uint8_t partitionSwitchTiming;*/ /*!< partition switch timing [199] */ + uint8_t powerClass52MHz195V; /*!< Power Class for 52MHz @ 1.95V [200] */ + uint8_t powerClass26MHz195V; /*!< Power Class for 26MHz @ 1.95V [201] */ + uint8_t powerClass52MHz360V; /*!< Power Class for 52MHz @ 3.6V [202] */ + uint8_t powerClass26MHz360V; /*!< Power Class for 26MHz @ 3.6V [203] */ + uint8_t minimumReadPerformance4Bit26MHz; /*!< Minimum Read Performance for 4bit at 26MHz [205] */ + uint8_t minimumWritePerformance4Bit26MHz; /*!< Minimum Write Performance for 4bit at 26MHz [206] */ + uint8_t minimumReadPerformance8Bit26MHz4Bit52MHz; + /*!< Minimum read Performance for 8bit at 26MHz/4bit @52MHz [207] */ + uint8_t minimumWritePerformance8Bit26MHz4Bit52MHz; + /*!< Minimum Write Performance for 8bit at 26MHz/4bit @52MHz [208] */ + uint8_t minimumReadPerformance8Bit52MHz; /*!< Minimum Read Performance for 8bit at 52MHz [209] */ + uint8_t minimumWritePerformance8Bit52MHz; /*!< Minimum Write Performance for 8bit at 52MHz [210] */ + uint32_t sectorCount; /*!< Sector Count [215:212] */ + /*uint8_t sleepNotificationTimeout;*/ /*!< sleep notification timeout [216]*/ + uint8_t sleepAwakeTimeout; /*!< Sleep/awake timeout [217] */ + /*uint8_t productionStateAwareTimeout;*/ /*!< Production state awareness timeout [218]*/ + uint8_t sleepCurrentVCCQ; /*!< Sleep current (VCCQ) [219] */ + uint8_t sleepCurrentVCC; /*!< Sleep current (VCC) [220] */ + uint8_t highCapacityWriteProtectGroupSize; /*!< High-capacity write protect group size [221] */ + uint8_t reliableWriteSectorCount; /*!< Reliable write sector count [222] */ + uint8_t highCapacityEraseTimeout; /*!< High-capacity erase timeout [223] */ + uint8_t highCapacityEraseUnitSize; /*!< High-capacity erase unit size [224] */ + uint8_t accessSize; /*!< Access size [225] */ + /*uint8_t secureTrimMultiplier;*/ /*!< secure trim multiplier[229]*/ + /*uint8_t secureEraseMultiplier;*/ /*!< secure erase multiplier[230]*/ + /*uint8_t secureFeatureSupport;*/ /*!< secure feature support[231]*/ + /*uint32_t trimMultiplier;*/ /*!< trim multiplier[232]*/ + uint8_t minReadPerformance8bitAt52MHZDDR; /*!< Minimum read performance for 8bit at DDR 52MHZ[234]*/ + uint8_t minWritePerformance8bitAt52MHZDDR; /*!< Minimum write performance for 8bit at DDR 52MHZ[235]*/ + uint8_t powerClass200MHZVCCQ130VVCC360V; /*!< power class for 200MHZ, at VCCQ= 1.3V,VCC=3.6V[236]*/ + uint8_t powerClass200MHZVCCQ195VVCC360V; /*!< power class for 200MHZ, at VCCQ= 1.95V,VCC=3.6V[237]*/ + uint8_t powerClass52MHZDDR195V; /*!< power class for 52MHZ,DDR at Vcc 1.95V[238]*/ + uint8_t powerClass52MHZDDR360V; /*!< power class for 52MHZ,DDR at Vcc 3.6V[239]*/ + /*uint8_t iniTimeoutAP;*/ /*!< 1st initialization time after partitioning[241]*/ + /*uint32_t correctPrgSectorNum;*/ /*!< correct prg sectors number[245-242]*/ + /*uint8_t bkOpsStatus;*/ /*!< background operations status[246]*/ + /*uint8_t powerOffNotifyTimeout;*/ /*!< power off notification timeout[247]*/ + /*uint8_t genericCMD6Timeout;*/ /*!< generic CMD6 timeout[248]*/ + uint32_t cacheSize; /*!< cache size[252-249]*/ + uint8_t powerClass200MHZDDR360V; /*!< power class for 200MHZ, DDR at VCC=2.6V[253]*/ + /*uint32_t fwVer[2U];*/ /*!< fw VERSION [261-254]*/ + /*uint16_t deviceVer;*/ /*!< device version[263-262]*/ + /*uint8_t optimalTrimSize;*/ /*!< optimal trim size[264]*/ + /*uint8_t optimalWriteSize;*/ /*!< optimal write size[265]*/ + /*uint8_t optimalReadSize;*/ /*!< optimal read size[266]*/ + /*uint8_t preEolInfo;*/ /*!< pre EOL information[267]*/ + /*uint8_t deviceLifeTimeEstimationA;*/ /*!< device life time estimation typeA[268]*/ + /*uint8_t deviceLifeTimeEstimationB;*/ /*!< device life time estimation typeB[269]*/ + /*uint32_t correctPrgFWSectorNum;*/ /*!< number of FW sectors correctly programmed[305-302]*/ + /*uint32_t ffuArg;*/ /*!< FFU argument[490-487]*/ + /*uint8_t operationCodeTimeout;*/ /*!< operation code timeout[491]*/ + /*uint8_t supportMode;*/ /*!< support mode [493]*/ + uint8_t extPartitionSupport; /*!< extended partition attribute support[494]*/ + /*uint8_t largeUnitSize;*/ /*!< large unit size[495]*/ + /*uint8_t contextManageCap;*/ /*!< context management capability[496]*/ + /*uint8_t tagResourceSize;*/ /*!< tag resource size[497]*/ + /*uint8_t tagUnitSize;*/ /*!< tag unit size[498]*/ + /*uint8_t maxPackedWriteCmd;*/ /*!< max packed write cmd[500]*/ + /*uint8_t maxPackedReadCmd;*/ /*!< max packed read cmd[501]*/ + /*uint8_t hpiFeature;*/ /*!< HPI feature[503]*/ + uint8_t supportedCommandSet; /*!< Supported Command Sets [504] */ + /*uint8_t extSecurityCmdError;*/ /*!< extended security commands error[505]*/ +} mmc_extended_csd_t; + +/*! @brief The bit shift for COMMAND SET field in SWITCH command. */ +#define MMC_SWITCH_COMMAND_SET_SHIFT (0U) +/*! @brief The bit mask for COMMAND set field in SWITCH command. */ +#define MMC_SWITCH_COMMAND_SET_MASK (0x00000007U) +/*! @brief The bit shift for VALUE field in SWITCH command */ +#define MMC_SWITCH_VALUE_SHIFT (8U) +/*! @brief The bit mask for VALUE field in SWITCH command */ +#define MMC_SWITCH_VALUE_MASK (0x0000FF00U) +/*! @brief The bit shift for BYTE INDEX field in SWITCH command */ +#define MMC_SWITCH_BYTE_INDEX_SHIFT (16U) +/*! @brief The bit mask for BYTE INDEX field in SWITCH command */ +#define MMC_SWITCH_BYTE_INDEX_MASK (0x00FF0000U) +/*! @brief The bit shift for ACCESS MODE field in SWITCH command */ +#define MMC_SWITCH_ACCESS_MODE_SHIFT (24U) +/*! @brief The bit mask for ACCESS MODE field in SWITCH command */ +#define MMC_SWTICH_ACCESS_MODE_MASK (0x03000000U) + +/*! @brief MMC Extended CSD configuration. */ +typedef struct _mmc_extended_csd_config +{ + mmc_command_set_t commandSet; /*!< Command set */ + uint8_t ByteValue; /*!< The value to set */ + uint8_t ByteIndex; /*!< The byte index in Extended CSD(mmc_extended_csd_index_t) */ + mmc_extended_csd_access_mode_t accessMode; /*!< Access mode */ +} mmc_extended_csd_config_t; + +/*! @brief MMC card boot configuration definition. */ +typedef struct _mmc_boot_config +{ + bool enableBootAck; /*!< Enable boot ACK */ + mmc_boot_partition_enable_t bootPartition; /*!< Boot partition */ + + mmc_boot_timing_mode_t bootTimingMode; /*!< boot mode */ + mmc_data_bus_width_t bootDataBusWidth; /*!< Boot data bus width */ + bool retainBootbusCondition; /*!< If retain boot bus width and boot mode conditions */ + + bool pwrBootConfigProtection; /*!< Disable the change of boot configuration register bits from at this point + until next power cycle or next H/W reset operation */ + bool premBootConfigProtection; /*!< Disable the change of boot configuration register bits permanently */ + + mmc_boot_partition_wp_t bootPartitionWP; /*!< boot partition write protect configurations */ + +} mmc_boot_config_t; + +/* @} */ + +#endif /* _FSL_SDMMC_SPEC_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/Makefile new file mode 100644 index 000000000..2f8f43cdf --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/Makefile @@ -0,0 +1,3 @@ +SRC_DIR += usdhc + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/fsl_sdmmc_event.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/fsl_sdmmc_event.h new file mode 100644 index 000000000..e508365d3 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/fsl_sdmmc_event.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_SDMMC_EVENT_H_ +#define _FSL_SDMMC_EVENT_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief Event type */ +typedef enum _sdmmc_event +{ + kSDMMCEVENT_TransferComplete = 0U, /*!< Transfer complete event */ + kSDMMCEVENT_CardDetect = 1U, /*!< Card detect event */ +} sdmmc_event_t; + +/******************************************************************************* + * API + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name Event Function + * @{ + */ + +/*! + * @brief Initialize timer to implement wait event timeout. + */ +void SDMMCEVENT_InitTimer(void); + +/* Callback function for SDHC */ + +/*! + * @brief Create event. + * @param eventType The event type + * @retval true Create event successfully. + * @retval false Create event failed. + */ +bool SDMMCEVENT_Create(sdmmc_event_t eventType); + +/*! + * @brief Wait event. + * + * @param eventType The event type + * @param timeoutMilliseconds Timeout time in milliseconds. + * @retval true Wait event successfully. + * @retval false Wait event failed. + */ +bool SDMMCEVENT_Wait(sdmmc_event_t eventType, uint32_t timeoutMilliseconds); + +/*! + * @brief Notify event. + * @param eventType The event type + * @retval true Notify event successfully. + * @retval false Notify event failed. + */ +bool SDMMCEVENT_Notify(sdmmc_event_t eventType); + +/*! + * @brief Delete event. + * @param eventType The event type + */ +void SDMMCEVENT_Delete(sdmmc_event_t eventType); + +/*! + * @brief sdmmc delay. + * @param milliseconds time to delay + */ +void SDMMCEVENT_Delay(uint32_t milliseconds); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +#endif /* _FSL_SDMMC_EVENT_H_*/ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/Makefile new file mode 100644 index 000000000..e29c55dfd --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/Makefile @@ -0,0 +1,3 @@ +SRC_DIR += polling + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/Makefile new file mode 100644 index 000000000..f8edb2a00 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := fsl_sdmmc_host.c fsl_sdmmc_event.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/fsl_sdmmc_event.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/fsl_sdmmc_event.c new file mode 100644 index 000000000..70baec303 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/fsl_sdmmc_event.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "fsl_sdmmc_event.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief Get event instance. + * @param eventType The event type + * @return The event instance's pointer. + */ +static volatile uint32_t *SDMMCEVENT_GetInstance(sdmmc_event_t eventType); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief Card detect event. */ +static volatile uint32_t g_eventCardDetect; + +/*! @brief transfer complete event. */ +static volatile uint32_t g_eventTransferComplete; + +/*! @brief Time variable unites as milliseconds. */ +volatile uint32_t g_eventTimeMilliseconds; + +/******************************************************************************* + * Code + ******************************************************************************/ +static void SysTickHandler(void) +{ +#ifdef __CA7_REV + SystemClearSystickFlag(); +#endif + g_eventTimeMilliseconds++; +} + +void SDMMCEVENT_InitTimer(void) +{ +#ifdef __CA7_REV + /* special for i.mx6ul */ + SystemSetupSystick(1000U, (void *)SysTickHandler, 32U); + SystemClearSystickFlag(); +#else + /* Set systick reload value to generate 1ms interrupt */ + SysTick_Config(CLOCK_GetFreq(kCLOCK_CoreSysClk) / 1000U); +#endif +} + +static volatile uint32_t *SDMMCEVENT_GetInstance(sdmmc_event_t eventType) +{ + volatile uint32_t *event; + + switch (eventType) + { + case kSDMMCEVENT_TransferComplete: + event = &g_eventTransferComplete; + break; + case kSDMMCEVENT_CardDetect: + event = &g_eventCardDetect; + break; + default: + event = NULL; + break; + } + + return event; +} + +bool SDMMCEVENT_Create(sdmmc_event_t eventType) +{ + volatile uint32_t *event = SDMMCEVENT_GetInstance(eventType); + + if (event) + { + *event = 0; + return true; + } + else + { + return false; + } +} + +bool SDMMCEVENT_Wait(sdmmc_event_t eventType, uint32_t timeoutMilliseconds) +{ + uint32_t startTime; + uint32_t elapsedTime; + + volatile uint32_t *event = SDMMCEVENT_GetInstance(eventType); + + if (timeoutMilliseconds && event) + { + startTime = g_eventTimeMilliseconds; + do + { + elapsedTime = (g_eventTimeMilliseconds - startTime); + } while ((*event == 0U) && (elapsedTime < timeoutMilliseconds)); + *event = 0U; + + return ((elapsedTime < timeoutMilliseconds) ? true : false); + } + else + { + return false; + } +} + +bool SDMMCEVENT_Notify(sdmmc_event_t eventType) +{ + volatile uint32_t *event = SDMMCEVENT_GetInstance(eventType); + + if (event) + { + *event = 1U; + return true; + } + else + { + return false; + } +} + +void SDMMCEVENT_Delete(sdmmc_event_t eventType) +{ + volatile uint32_t *event = SDMMCEVENT_GetInstance(eventType); + + if (event) + { + *event = 0U; + } +} + +void SDMMCEVENT_Delay(uint32_t milliseconds) +{ + uint32_t startTime = g_eventTimeMilliseconds; + uint32_t periodTime = 0; + while (periodTime < milliseconds) + { + periodTime = g_eventTimeMilliseconds - startTime; + } +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/fsl_sdmmc_host.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/fsl_sdmmc_host.c new file mode 100644 index 000000000..cf87ba6ab --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/fsl_sdmmc_host.c @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_sdmmc_event.h" +#include "fsl_sdmmc_host.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief SDMMCHOST notify card insertion status. + * @param inserted true is inserted, false is not + * @param cd card detect descriptor + */ +static void SDMMCHOST_NofiyCardInsertStatus(bool inserted, const sdmmchost_detect_card_t *cd); + +/*! + * @brief SDMMCHOST detect card insert status by host controller. + * @param base host base address. + * @param userData user can register a application card insert callback through userData. + */ +static void SDMMCHOST_DetectCardInsertByHost(SDMMCHOST_TYPE *base, void *userData); + +/*! + * @brief SDMMCHOST detect card remove status by host controller. + * @param base host base address. + * @param userData user can register a application card insert callback through userData. + */ +static void SDMMCHOST_DetectCardRemoveByHost(SDMMCHOST_TYPE *base, void *userData); + +/*! + * @brief SDMMCHOST transfer function. + * @param base host base address. + * @param content transfer configurations. + */ +static status_t SDMMCHOST_TransferFunction(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER *content); + +/*! + * @brief SDMMCHOST transfer complete callback. + * @param base host base address. + * @param handle host handle. + * @param status interrupt status. + * @param userData user data. + */ +static void SDMMCHOST_TransferCompleteCallback(SDMMCHOST_TYPE *base, + usdhc_handle_t *handle, + status_t status, + void *userData); + +/*! + * @brief SDMMCHOST re-tuning callback + * @param base host base address. + * @param userData user can register a application card insert callback through userData. + */ +static void SDMMCHOST_ReTuningCallback(SDMMCHOST_TYPE *base, void *userData); + +/*! + * @brief card detect deinit function. + */ +static void SDMMCHOST_CardDetectDeinit(void); + +/*! + * @brief card detect deinit function. + * @param host base address. + * @param host detect card configuration. + */ +static status_t SDMMCHOST_CardDetectInit(SDMMCHOST_TYPE *base, const sdmmchost_detect_card_t *cd); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/* DMA descriptor should allocate at non-cached memory */ +AT_NONCACHEABLE_SECTION_ALIGN(uint32_t g_usdhcAdma2Table[USDHC_ADMA_TABLE_WORDS], USDHC_ADMA2_ADDR_ALIGN); + +usdhc_handle_t g_usdhcHandle; +volatile status_t g_usdhcTransferStatus = kStatus_Success; +static volatile bool s_sdInsertedFlag = false; +volatile status_t g_reTuningFlag = false; + +/******************************************************************************* + * Code + ******************************************************************************/ +static void SDMMCHOST_NofiyCardInsertStatus(bool inserted, const sdmmchost_detect_card_t *cd) +{ + if (inserted == false) + { + s_sdInsertedFlag = false; + if (cd && (cd->cardRemoved)) + { + cd->cardRemoved(false, cd->userData); + } + } + else + { + s_sdInsertedFlag = true; + if (cd && (cd->cardInserted)) + { + cd->cardInserted(true, cd->userData); + } + } +} + +static void SDMMCHOST_DetectCardInsertByHost(SDMMCHOST_TYPE *base, void *userData) +{ + s_sdInsertedFlag = true; + SDMMCEVENT_Notify(kSDMMCEVENT_CardDetect); + /* application callback */ + if (userData && (((sdmmhostcard_usr_param_t *)userData)->cd) && + ((sdmmhostcard_usr_param_t *)userData)->cd->cardInserted) + { + ((sdmmhostcard_usr_param_t *)userData) + ->cd->cardInserted(true, ((sdmmhostcard_usr_param_t *)userData)->cd->userData); + } +} + +static void SDMMCHOST_DetectCardRemoveByHost(SDMMCHOST_TYPE *base, void *userData) +{ + s_sdInsertedFlag = false; + /* application callback */ + if (userData && (((sdmmhostcard_usr_param_t *)userData)->cd) && + ((sdmmhostcard_usr_param_t *)userData)->cd->cardRemoved) + { + ((sdmmhostcard_usr_param_t *)userData) + ->cd->cardRemoved(false, ((sdmmhostcard_usr_param_t *)userData)->cd->userData); + } +} + +static void SDMMCHOST_CardInterrupt(SDMMCHOST_TYPE *base, void *userData) +{ + /* application callback */ + if (userData && ((sdmmhostcard_usr_param_t *)userData)->cardInt) + { + ((sdmmhostcard_usr_param_t *)userData) + ->cardInt->cardInterrupt(((sdmmhostcard_usr_param_t *)userData)->cardInt->userData); + } +} + +void SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_HANDLER(void) +{ + if (SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_STATUS() & (1U << BOARD_USDHC_CD_GPIO_PIN)) + { + SDMMCHOST_NofiyCardInsertStatus((SDMMCHOST_CARD_DETECT_GPIO_STATUS() == SDMMCHOST_CARD_INSERT_CD_LEVEL), + ((sdmmhostcard_usr_param_t *)g_usdhcHandle.userData)->cd); + } + /* Clear interrupt flag.*/ + SDMMCHOST_CARD_DETECT_GPIO_INTERRUPT_STATUS_CLEAR(~0U); + SDMMCEVENT_Notify(kSDMMCEVENT_CardDetect); +} + +static void SDMMCHOST_TransferCompleteCallback(SDMMCHOST_TYPE *base, + usdhc_handle_t *handle, + status_t status, + void *userData) +{ + /* if reading data from sdcard, ignore the command error, usdhc will continue transfer data */ + if (!((handle->data) && (handle->data->rxData) && (status == kStatus_USDHC_SendCommandFailed))) + { + SDMMCEVENT_Notify(kSDMMCEVENT_TransferComplete); + } + /* wait the target status and then notify the transfer complete */ + g_usdhcTransferStatus = status; +} + +static void SDMMCHOST_ReTuningCallback(SDMMCHOST_TYPE *base, void *userData) +{ + g_reTuningFlag = true; + SDMMCEVENT_Notify(kSDMMCEVENT_TransferComplete); +} + +static status_t SDMMCHOST_TransferFunction(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER *content) +{ + status_t error = kStatus_Success; + + usdhc_adma_config_t dmaConfig; + + if (content->data != NULL) + { + memset(&dmaConfig, 0, sizeof(usdhc_adma_config_t)); + /* config adma */ + dmaConfig.dmaMode = USDHC_DMA_MODE; + dmaConfig.burstLen = kUSDHC_EnBurstLenForINCR; + dmaConfig.admaTable = g_usdhcAdma2Table; + dmaConfig.admaTableWords = USDHC_ADMA_TABLE_WORDS; + } + + /* make sure complete event is cleared. */ + SDMMCEVENT_Delete(kSDMMCEVENT_TransferComplete); + + do + { + error = USDHC_TransferNonBlocking(base, &g_usdhcHandle, &dmaConfig, content); + } while (error == kStatus_USDHC_BusyTransferring); + + if ((error != kStatus_Success) || + (false == SDMMCEVENT_Wait(kSDMMCEVENT_TransferComplete, SDMMCHOST_TRANSFER_COMPLETE_TIMEOUT)) || + (g_reTuningFlag) || (g_usdhcTransferStatus != kStatus_Success)) + { + if (g_reTuningFlag || (error == kStatus_USDHC_ReTuningRequest)) + { + if (g_reTuningFlag) + { + g_reTuningFlag = false; + error = kStatus_USDHC_TuningError; + } + } + else + { + error = g_usdhcTransferStatus; + /* host error recovery */ + SDMMCHOST_ErrorRecovery(base); + } + } + + return error; +} + +void SDMMCHOST_ErrorRecovery(SDMMCHOST_TYPE *base) +{ + uint32_t status = 0U; + /* get host present status */ + status = USDHC_GetPresentStatusFlags(base); + /* check command inhibit status flag */ + if ((status & kUSDHC_CommandInhibitFlag) != 0U) + { + /* reset command line */ + USDHC_Reset(base, kUSDHC_ResetCommand, 100U); + } + /* check data inhibit status flag */ + if ((status & kUSDHC_DataInhibitFlag) != 0U) + { + /* reset data line */ + USDHC_Reset(base, kUSDHC_ResetData, 100U); + } +} + +static status_t SDMMCHOST_CardDetectInit(SDMMCHOST_TYPE *base, const sdmmchost_detect_card_t *cd) +{ + sdmmchost_detect_card_type_t cdType = kSDMMCHOST_DetectCardByGpioCD; + bool cardInserted = false; + + if (cd != NULL) + { + cdType = cd->cdType; + } + + if (!SDMMCEVENT_Create(kSDMMCEVENT_CardDetect)) + { + return kStatus_Fail; + } + + if (cdType == kSDMMCHOST_DetectCardByGpioCD) + { + SDMMCHOST_CARD_DETECT_GPIO_INIT(); + + /* Open card detection pin NVIC. */ + SDMMCHOST_ENABLE_IRQ(SDMMCHOST_CARD_DETECT_GPIO_IRQ); + /* detect card insert status */ + if (SDMMCHOST_CARD_DETECT_GPIO_STATUS() == SDMMCHOST_CARD_INSERT_CD_LEVEL) + { + cardInserted = true; + } + } + else + { + /* enable card detect through DATA3 */ + if (cdType == kSDMMCHOST_DetectCardByHostDATA3) + { + SDMMCHOST_CARD_DETECT_DATA3_ENABLE(base, true); + } + /* enable card detect interrupt */ + SDMMCHOST_CARD_DETECT_INSERT_ENABLE(base); + /* check if card is inserted */ + if (SDMMCHOST_CARD_DETECT_INSERT_STATUS(base)) + { + cardInserted = true; + } + else + { + SDMMCHOST_CARD_DETECT_INSERT_INTERRUPT_ENABLE(base); + SDMMCHOST_CARD_DETECT_REMOVE_INTERRUPT_ENABLE(base); + } + } + + /* notify application about the card insertion status */ + SDMMCHOST_NofiyCardInsertStatus(cardInserted, cd); + + return kStatus_Success; +} + +static void SDMMCHOST_CardDetectDeinit(void) +{ + SDMMCEVENT_Delete(kSDMMCEVENT_CardDetect); + s_sdInsertedFlag = false; +} + +void SDMMCHOST_Delay(uint32_t milliseconds) +{ + SDMMCEVENT_Delay(milliseconds); +} + +status_t SDMMCHOST_WaitCardDetectStatus(SDMMCHOST_TYPE *base, const sdmmchost_detect_card_t *cd, bool waitCardStatus) +{ + uint32_t timeout = SDMMCHOST_CARD_DETECT_TIMEOUT; + + if (cd != NULL) + { + timeout = cd->cdTimeOut_ms; + } + + if (waitCardStatus != s_sdInsertedFlag) + { + /* Wait card inserted. */ + do + { + if (!SDMMCEVENT_Wait(kSDMMCEVENT_CardDetect, timeout)) + { + return kStatus_Fail; + } + } while (waitCardStatus != s_sdInsertedFlag); + } + + return kStatus_Success; +} + +bool SDMMCHOST_IsCardPresent(void) +{ + return s_sdInsertedFlag; +} + +void SDMMCHOST_PowerOffCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +{ + if (pwr != NULL) + { + pwr->powerOff(); + SDMMCHOST_Delay(pwr->powerOffDelay_ms); + } + else + { + /* only SD card need card detect*/ + SDMMCHOST_ENABLE_SD_POWER(false); + /* Delay several milliseconds to make card stable. */ + SDMMCHOST_Delay(500U); + } +} + +void SDMMCHOST_PowerOnCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +{ + /* use user define the power on function */ + if (pwr != NULL) + { + pwr->powerOn(); + SDMMCHOST_Delay(pwr->powerOnDelay_ms); + } + else + { + /* card power on */ + SDMMCHOST_ENABLE_SD_POWER(true); + /* Delay several milliseconds to make card stable. */ + SDMMCHOST_Delay(500U); + } +} + +status_t SDMMCHOST_Init(SDMMCHOST_CONFIG *host, void *userData) +{ + usdhc_host_t *usdhcHost = (usdhc_host_t *)host; + usdhc_transfer_callback_t callback = { + .TransferComplete = SDMMCHOST_TransferCompleteCallback, + .ReTuning = SDMMCHOST_ReTuningCallback, + .CardInserted = SDMMCHOST_DetectCardInsertByHost, + .CardRemoved = SDMMCHOST_DetectCardRemoveByHost, + .SdioInterrupt = SDMMCHOST_CardInterrupt, + .BlockGap = NULL, + }; + /* init card power control */ + SDMMCHOST_INIT_SD_POWER(); + SDMMCHOST_INIT_MMC_POWER(); + + /* Initializes USDHC. */ + usdhcHost->config.dataTimeout = USDHC_DATA_TIMEOUT; + usdhcHost->config.endianMode = USDHC_ENDIAN_MODE; + usdhcHost->config.readWatermarkLevel = USDHC_READ_WATERMARK_LEVEL; + usdhcHost->config.writeWatermarkLevel = USDHC_WRITE_WATERMARK_LEVEL; + usdhcHost->config.readBurstLen = USDHC_READ_BURST_LEN; + usdhcHost->config.writeBurstLen = USDHC_WRITE_BURST_LEN; + + USDHC_Init(usdhcHost->base, &(usdhcHost->config)); + + /* disable the card insert/remove interrupt, due to use GPIO interrupt detect card */ + USDHC_DisableInterruptSignal(usdhcHost->base, kUSDHC_CardRemovalFlag | kUSDHC_CardInsertionFlag); + /* create interrupt handler */ + USDHC_TransferCreateHandle(usdhcHost->base, &g_usdhcHandle, &callback, userData); + /* Create transfer complete event. */ + SDMMCEVENT_InitTimer(); + + if (false == SDMMCEVENT_Create(kSDMMCEVENT_TransferComplete)) + { + return kStatus_Fail; + } + + /* Define transfer function. */ + usdhcHost->transfer = SDMMCHOST_TransferFunction; + /* card detect init */ + SDMMCHOST_CardDetectInit(usdhcHost->base, (userData == NULL) ? NULL : (((sdmmhostcard_usr_param_t *)userData)->cd)); + + return kStatus_Success; +} + +void SDMMCHOST_Reset(SDMMCHOST_TYPE *base) +{ + /* voltage switch to normal but not 1.8V */ + SDMMCHOST_SWITCH_VOLTAGE180V(base, false); + /* Disable DDR mode */ + SDMMCHOST_ENABLE_DDR_MODE(base, false, 0U); + /* disable tuning */ + SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, false); + /* Disable HS400 mode */ + SDMMCHOST_ENABLE_HS400_MODE(base, false); + /* Disable DLL */ + SDMMCHOST_ENABLE_STROBE_DLL(base, false); +} + +void SDMMCHOST_Deinit(void *host) +{ + usdhc_host_t *usdhcHost = (usdhc_host_t *)host; + SDMMCHOST_Reset(usdhcHost->base); + USDHC_Deinit(usdhcHost->base); + SDMMCHOST_CardDetectDeinit(); +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/Makefile new file mode 100644 index 000000000..eea447bec --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := fsl_sdmmc_host.c fsl_sdmmc_event.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/fsl_sdmmc_event.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/fsl_sdmmc_event.c new file mode 100644 index 000000000..b811d738d --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/fsl_sdmmc_event.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_sdmmc_event.h" +#include "xiuos.h" +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief Get event instance. + * @param eventType The event type + * @return The event instance's pointer. + */ +static volatile uint32_t *SDMMCEVENT_GetInstance(sdmmc_event_t eventType); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief Card detect event. */ +static volatile uint32_t g_eventCardDetect; + +/*! @brief transfer complete event. */ +static volatile uint32_t g_eventTransferComplete; + +/*! @brief Time variable unites as milliseconds. */ +volatile uint32_t g_eventTimeMilliseconds; + +/******************************************************************************* + * Code + ******************************************************************************/ +// void SysTick_Handler(void) +// { +// #ifdef __CA7_REV +// SystemClearSystickFlag(); +// #endif +// g_eventTimeMilliseconds++; +// } + +void SDMMCEVENT_InitTimer(void) +{ +#ifdef __CA7_REV + /* special for i.mx6ul */ + SystemSetupSystick(1000U, (void *)SysTick_Handler, 32U); + SystemClearSystickFlag(); +#else + /* Set systick reload value to generate 1ms interrupt */ + SysTick_Config(CLOCK_GetFreq(kCLOCK_CoreSysClk) / 1000U); +#endif +} + +static volatile uint32_t *SDMMCEVENT_GetInstance(sdmmc_event_t eventType) +{ + volatile uint32_t *event; + + switch (eventType) + { + case kSDMMCEVENT_TransferComplete: + event = &g_eventTransferComplete; + break; + case kSDMMCEVENT_CardDetect: + event = &g_eventCardDetect; + break; + default: + event = NULL; + break; + } + + return event; +} + +bool SDMMCEVENT_Create(sdmmc_event_t eventType) +{ + volatile uint32_t *event = SDMMCEVENT_GetInstance(eventType); + + if (event) + { + *event = 0; + return true; + } + else + { + return false; + } +} + +bool SDMMCEVENT_Wait(sdmmc_event_t eventType, uint32_t timeoutMilliseconds) +{ + uint32_t startTime; + uint32_t elapsedTime; + + volatile uint32_t *event = SDMMCEVENT_GetInstance(eventType); + + if (timeoutMilliseconds && event) + { + startTime = CurrentTicksGain(); + do + { + elapsedTime = (CurrentTicksGain() - startTime); + } while ((*event == 0U) && (elapsedTime < timeoutMilliseconds)); + *event = 0U; + + return ((elapsedTime < timeoutMilliseconds) ? true : false); + } + else + { + return false; + } +} + +bool SDMMCEVENT_Notify(sdmmc_event_t eventType) +{ + volatile uint32_t *event = SDMMCEVENT_GetInstance(eventType); + + if (event) + { + *event = 1U; + return true; + } + else + { + return false; + } +} + +void SDMMCEVENT_Delete(sdmmc_event_t eventType) +{ + volatile uint32_t *event = SDMMCEVENT_GetInstance(eventType); + + if (event) + { + *event = 0U; + } +} + +void SDMMCEVENT_Delay(uint32_t milliseconds) +{ + uint32_t startTime = CurrentTicksGain(); + uint32_t periodTime = 0; + while (periodTime < milliseconds) + { + KPrintf("period time %u millisecond %u event %u start %u\n", + periodTime, milliseconds, CurrentTicksGain(), startTime); + periodTime = CurrentTicksGain() - startTime; + } +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/fsl_sdmmc_host.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/fsl_sdmmc_host.c new file mode 100644 index 000000000..18c371039 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/fsl_sdmmc_host.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_sdmmc_host.h" +#include "fsl_sdmmc_event.h" +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief SDMMCHOST notify card insertion status. + * @param inserted true is inserted, false is not + * @param cd card detect descriptor + */ +static void SDMMCHOST_NofiyCardInsertStatus(bool inserted, const sdmmchost_detect_card_t *cd); + +/*! + * @brief SDMMCHOST transfer function. + * @param base host base address. + * @param content transfer configurations. + */ +static status_t SDMMCHOST_TransferFunction(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER *content); + +/*! + * @brief card detect deinit function. + */ +static void SDMMCHOST_CardDetectDeinit(void); + +/*! + * @brief card detect deinit function. + * @param host base address. + * @param host detect card configuration. + */ +static status_t SDMMCHOST_CardDetectInit(SDMMCHOST_TYPE *base, const sdmmchost_detect_card_t *cd); +/******************************************************************************* + * Variables + ******************************************************************************/ +/* DMA descriptor should allocate at non-cached memory */ +AT_NONCACHEABLE_SECTION_ALIGN(uint32_t g_usdhcAdma2Table[USDHC_ADMA_TABLE_WORDS], USDHC_ADMA2_ADDR_ALIGN); +static volatile bool s_sdInsertedFlag = false; +/******************************************************************************* + * Code + ******************************************************************************/ +static void SDMMCHOST_NofiyCardInsertStatus(bool inserted, const sdmmchost_detect_card_t *cd) +{ + if (inserted == false) + { + s_sdInsertedFlag = false; + if (cd && (cd->cardRemoved)) + { + cd->cardRemoved(false, cd->userData); + } + } + else + { + s_sdInsertedFlag = true; + if (cd && (cd->cardInserted)) + { + cd->cardInserted(true, cd->userData); + } + } +} + +static status_t SDMMCHOST_TransferFunction(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER *content) +{ + usdhc_adma_config_t dmaConfig; + status_t error = kStatus_Success; + + if (content->data != NULL) + { + memset(&dmaConfig, 0, sizeof(usdhc_adma_config_t)); + /* config adma */ + dmaConfig.dmaMode = USDHC_DMA_MODE; + dmaConfig.burstLen = kUSDHC_EnBurstLenForINCR; + dmaConfig.admaTable = g_usdhcAdma2Table; + dmaConfig.admaTableWords = USDHC_ADMA_TABLE_WORDS; + } + + error = USDHC_TransferBlocking(base, &dmaConfig, content); + + if (error != kStatus_Success) + { + /* host error recovery */ + SDMMCHOST_ErrorRecovery(base); + } + + return error; +} + +void SDMMCHOST_ErrorRecovery(SDMMCHOST_TYPE *base) +{ + uint32_t status = 0U; + /* get host present status */ + status = USDHC_GetPresentStatusFlags(base); + /* check command inhibit status flag */ + if ((status & kUSDHC_CommandInhibitFlag) != 0U) + { + /* reset command line */ + USDHC_Reset(base, kUSDHC_ResetCommand, 100U); + } + /* check data inhibit status flag */ + if ((status & kUSDHC_DataInhibitFlag) != 0U) + { + /* reset data line */ + USDHC_Reset(base, kUSDHC_ResetData, 100U); + } +} + +static status_t SDMMCHOST_CardDetectInit(SDMMCHOST_TYPE *base, const sdmmchost_detect_card_t *cd) +{ + sdmmchost_detect_card_type_t cdType = kSDMMCHOST_DetectCardByGpioCD; + bool cardInserted = false; + + if (cd != NULL) + { + cdType = cd->cdType; + } + + if (cdType == kSDMMCHOST_DetectCardByGpioCD) + { + SDMMCHOST_CARD_DETECT_GPIO_INIT(); + /* detect card insert status */ + if (SDMMCHOST_CARD_DETECT_GPIO_STATUS() == SDMMCHOST_CARD_INSERT_CD_LEVEL) + { + cardInserted = true; + } + } + else + { + /* enable card detect through DATA3 */ + if (cdType == kSDMMCHOST_DetectCardByHostDATA3) + { + SDMMCHOST_CARD_DETECT_DATA3_ENABLE(base, true); + } + /* enable card detect status */ + SDMMCHOST_CARD_DETECT_INSERT_ENABLE(base); + SDMMCHOST_CARD_DETECT_REMOVE_ENABLE(base); + /* check if card is inserted */ + if (SDMMCHOST_CARD_DETECT_INSERT_STATUS(base)) + { + cardInserted = true; + } + } + + /* notify application about the card insertion status */ + SDMMCHOST_NofiyCardInsertStatus(cardInserted, cd); + + return kStatus_Success; +} + +static void SDMMCHOST_CardDetectDeinit(void) +{ + SDMMCEVENT_Delete(kSDMMCEVENT_CardDetect); + s_sdInsertedFlag = false; +} + +void SDMMCHOST_Delay(uint32_t milliseconds) +{ + SDMMCEVENT_Delay(milliseconds); +} + +status_t SDMMCHOST_WaitCardDetectStatus(SDMMCHOST_TYPE *base, const sdmmchost_detect_card_t *cd, bool waitCardStatus) +{ + sdmmchost_detect_card_type_t cdType = kSDMMCHOST_DetectCardByGpioCD; + + if (cd != NULL) + { + cdType = cd->cdType; + } + + if (waitCardStatus != s_sdInsertedFlag) + { + /* Wait card inserted. */ + do + { + if (cdType != kSDMMCHOST_DetectCardByGpioCD) + { + if (SDMMCHOST_CARD_DETECT_INSERT_STATUS(base)) + { + s_sdInsertedFlag = true; + } + } + else + { + if (SDMMCHOST_CARD_DETECT_INSERT_STATUS(base)) + { + s_sdInsertedFlag = true; + } + } + } while (waitCardStatus != s_sdInsertedFlag); + } + + return kStatus_Success; +} + +bool SDMMCHOST_IsCardPresent(void) +{ + return s_sdInsertedFlag; +} + +void SDMMCHOST_PowerOffCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +{ + if (pwr != NULL) + { + pwr->powerOff(); + SDMMCHOST_Delay(pwr->powerOffDelay_ms); + } + else + { + /* only SD card need card detect*/ + SDMMCHOST_ENABLE_SD_POWER(false); + /* Delay several milliseconds to make card stable. */ + SDMMCHOST_Delay(500U); + } +} + +void SDMMCHOST_PowerOnCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +{ + /* use user define the power on function */ + if (pwr != NULL) + { + pwr->powerOn(); + SDMMCHOST_Delay(pwr->powerOnDelay_ms); + } + else + { + /* card power on */ + SDMMCHOST_ENABLE_SD_POWER(true); + /* Delay several milliseconds to make card stable. */ + SDMMCHOST_Delay(500U); + } +} + +status_t SDMMCHOST_Init(SDMMCHOST_CONFIG *host, void *userData) +{ + usdhc_host_t *usdhcHost = (usdhc_host_t *)host; + + /* init card power control */ + SDMMCHOST_INIT_SD_POWER(); + SDMMCHOST_INIT_MMC_POWER(); + + /* Initializes SDHC. */ + usdhcHost->config.dataTimeout = USDHC_DATA_TIMEOUT; + usdhcHost->config.endianMode = USDHC_ENDIAN_MODE; + usdhcHost->config.readWatermarkLevel = USDHC_READ_WATERMARK_LEVEL; + usdhcHost->config.writeWatermarkLevel = USDHC_WRITE_WATERMARK_LEVEL; + usdhcHost->config.readBurstLen = USDHC_READ_BURST_LEN; + usdhcHost->config.writeBurstLen = USDHC_WRITE_BURST_LEN; + + USDHC_Init(usdhcHost->base, &(usdhcHost->config)); + + /* Define transfer function. */ + usdhcHost->transfer = SDMMCHOST_TransferFunction; + /* event init timer */ + SDMMCEVENT_InitTimer(); + /* card detect init */ + SDMMCHOST_CardDetectInit(usdhcHost->base, (userData == NULL) ? NULL : (((sdmmhostcard_usr_param_t *)userData)->cd)); + + return kStatus_Success; +} + +void SDMMCHOST_Reset(SDMMCHOST_TYPE *base) +{ + /* voltage switch to normal but not 1.8V */ + SDMMCHOST_SWITCH_VOLTAGE180V(base, false); + /* Disable DDR mode */ + SDMMCHOST_ENABLE_DDR_MODE(base, false, 0U); + /* disable tuning */ + SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, false); + /* Disable HS400 mode */ + SDMMCHOST_ENABLE_HS400_MODE(base, false); + /* Disable DLL */ + SDMMCHOST_ENABLE_STROBE_DLL(base, false); +} + +void SDMMCHOST_Deinit(void *host) +{ + usdhc_host_t *usdhcHost = (usdhc_host_t *)host; + SDMMCHOST_Reset(usdhcHost->base); + USDHC_Deinit(usdhcHost->base); + SDMMCHOST_CardDetectDeinit(); +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/Makefile new file mode 100644 index 000000000..2eb2d47b7 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := fsl_sd.c fsl_sdmmc_common.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_mmc.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_mmc.c new file mode 100644 index 000000000..04faa8b10 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_mmc.c @@ -0,0 +1,2671 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "fsl_mmc.h" + +/******************************************************************************* + * Definitons + ******************************************************************************/ +/*! @brief The divide value used to avoid float point calculation when calculate max speed in normal mode. */ +#define DIVIDER_IN_TRANSFER_SPEED (10U) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief Send SELECT_CARD command to set the card enter or exit transfer state. + * + * @param card Card descriptor. + * @param isSelected True to enter transfer state. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t inline MMC_SelectCard(mmc_card_t *card, bool isSelected); + +/*! + * @brief Wait write process complete. + * + * @param card Card descriptor. + * @retval kStatus_Timeout Operation timeout. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_WaitWriteComplete(mmc_card_t *card); + +/*! + * @brief Send SET_BLOCK_COUNT command. + * + * @param card Card descriptor. + * @param blockCount Block count. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t inline MMC_SetBlockCount(mmc_card_t *card, uint32_t blockCount); + +/*! + * @brief Send GO_IDLE command to reset all cards to idle state + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t inline MMC_GoIdle(mmc_card_t *card); + +/*! + * @brief Send STOP_TRANSMISSION command to card to stop ongoing data transferring. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_StopTransmission(mmc_card_t *card); + +/*! + * @brief Send SET_BLOCK_SIZE command to set the block length in bytes for MMC cards. + * + * @param card Card descriptor. + * @param blockSize Block size. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t inline MMC_SetBlockSize(mmc_card_t *card, uint32_t blockSize); + +/*! + * @brief switch voltage. + * + * @param card Card descriptor. + * @param opcode use to send operation condition + * @retval kStatus_SDMMC_HostNotSupport Host doesn't support the voltage window to access the card. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SwitchVoltage(mmc_card_t *card, uint32_t *opCode); + +/*! + * @brief Send SEND_OPERATION_CONDITION command to validate if the card support host's voltage window + * + * @param card Card descriptor. + * @param arg Command argument. + * @retval kStatus_SDMMC_TransferFailed Transfers failed. + * @retval kStatus_Timeout Operation timeout. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SendOperationCondition(mmc_card_t *card, uint32_t arg); + +/*! + * @brief Send SET_RCA command to set the relative address of the card. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SetRelativeAddress(mmc_card_t *card); + +/*! + * @brief Decode CSD register content. + * + * @param card Card descriptor. + * @param rawCsd raw CSD register content. + */ +static void MMC_DecodeCsd(mmc_card_t *card, uint32_t *rawCsd); + +/*! + * @brief Set the card to max transfer speed in non-high speed mode. + * + * @param card Card descriptor. + */ +static void MMC_SetMaxFrequency(mmc_card_t *card); + +/*! + * @brief Set erase unit size of the card + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure Extended CSD failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card); + +/*! + * @brief Send SWITCH command to set the specific byte in Extended CSD. + * + * Example: + @code + mmc_extended_csd_config_t config; + config.accessMode = kMMC_ExtendedCsdAccessModeSetBits; + config.ByteIndex = 1U; + config.ByteValue = 0x033U; + config.commandSet = kMMC_CommandSetStandard; + MMC_SetExtendedCsdConfig(card, &config); + @endcode + * + * @param card Card descriptor. + * @param config Configuration for Extended CSD. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_WaitWriteCompleteFailed Wait write complete failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SetExtendedCsdConfig(mmc_card_t *card, const mmc_extended_csd_config_t *config); + +/*! + * @brief Decode the Extended CSD register + * + * @param card Card descriptor. + * @param rawExtendedCsd Raw extended CSD register content. + */ +static void MMC_DecodeExtendedCsd(mmc_card_t *card, uint32_t *rawExtendedCsd); + +/*! + * @brief Send SEND_EXTENDED_CSD command to get the content of the Extended CSD register + * Allow read the special byte index value if targetAddr is not NULL + * @param card Card descriptor. + * @param targetAddr Pointer to store the target byte value. + * @param byteIndex Target byte index. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SendExtendedCsd(mmc_card_t *card, uint8_t *targetAddr, uint32_t byteIndex); + +/*! + * @brief Set the power class of the card at specific bus width and host intended voltage window. + * + * @param card Card descriptor. + * @return The power class switch status. + */ +static status_t MMC_SetPowerClass(mmc_card_t *card); + +/*! + * @brief Send test pattern to get the functional pin in the MMC bus + * + * @param card Card descriptor. + * @param blockSize Test pattern block size. + * @param pattern Test pattern data buffer. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SendTestPattern(mmc_card_t *card, uint32_t blockSize, uint32_t *pattern); + +/*! + * @brief Receive test pattern reversed by the card. + * + * @param card Card descriptor. + * @param blockSize Test pattern block size. + * @param pattern Test pattern data buffer. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_ReceiveTestPattern(mmc_card_t *card, uint32_t blockSize, uint32_t *pattern); + +/*! + * @brief Bus test procedure to get the functional data pin in the bus + * + * @param card Card descriptor. + * @param width Data bus width. + * @retval kStatus_SDMMC_SendTestPatternFailed Send test pattern failed. + * @retval kStatus_SDMMC_ReceiveTestPatternFailed Receive test pattern failed. + * @retval kStatus_Fail Test failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_TestDataBusWidth(mmc_card_t *card, mmc_data_bus_width_t width); + +/*! + * @brief Send SET_BUS_WIDTH command to set the bus width. + * + * @param card Card descriptor. + * @param width Data bus width. + * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure extended CSD failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SetDataBusWidth(mmc_card_t *card, mmc_data_bus_width_t width); + +/*! + * @brief Set max the bus width automatically + * + * @param card Card descriptor. + * @param targetTiming switch target timing + * @retval kStatus_SDMMC_SetDataBusWidthFailed switch fail. + * @retval kStatus_Success switch success. + */ +static status_t MMC_SetMaxDataBusWidth(mmc_card_t *card, mmc_high_speed_timing_t targetTiming); + +/*! + * @brief Switch the card to high speed mode + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure extended CSD failed. + * @retval kStatus_SDMMC_CardNotSupport Card doesn't support high speed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SelectBusTiming(mmc_card_t *card); + +/*! + * @brief select card HS_TIMING value and card driver strength + * + * @param card Card descriptor. + * @param timing Timing interface value. + * @param driverStrength driver strength value. + * @retval kStatus_Success switch success. + * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed , config extend csd register fail. + */ +static status_t MMC_SwitchHSTiming(mmc_card_t *card, uint8_t timing, uint8_t driverStrength); + +/*! + * @brief switch to HS400 mode. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure extended CSD failed. + * @retval kStatus_SDMMC_SwitchBusTimingFailed switch bus timing fail. + * @retval kStatus_SDMMC_SetDataBusWidthFailed switch bus width fail. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SwitchToHS400(mmc_card_t *card); + +/*! + * @brief switch to HS200 mode. + * + * @param card Card descriptor. + * @param freq Target frequency. + * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure extended CSD failed. + * @retval kStatus_SDMMC_TuningFail tuning fail. + * @retval kStatus_SDMMC_SetDataBusWidthFailed switch bus width fail. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SwitchToHS200(mmc_card_t *card, uint32_t freq); + +/*! + * @brief switch to HS400 mode. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure extended CSD failed. + * @retval kStatus_SDMMC_SetDataBusWidthFailed switch bus width fail. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SwitchToHighSpeed(mmc_card_t *card); + +/*! + * @brief Decode CID register + * + * @param card Card descriptor. + * @param rawCid Raw CID register content. + */ +static void MMC_DecodeCid(mmc_card_t *card, uint32_t *rawCid); + +/*! + * @brief Send ALL_SEND_CID command + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_AllSendCid(mmc_card_t *card); + +/*! + * @brief Send SEND_CSD command to get CSD from card + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_SendCsd(mmc_card_t *card); + +/*! + * @brief Check if the block range accessed is within current partition. + * + * @param card Card descriptor. + * @param startBlock Start block to access. + * @param blockCount Block count to access. + * @retval kStatus_InvalidArgument Invalid argument. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_CheckBlockRange(mmc_card_t *card, uint32_t startBlock, uint32_t blockCount); + +/*! + * @brief Check if the erase group range accessed is within current partition. + * + * @param card Card descriptor. + * @param startGroup Start group to access. + * @param endGroup End group to access. + * @retval kStatus_InvalidArgument Invalid argument. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_CheckEraseGroupRange(mmc_card_t *card, uint32_t startGroup, uint32_t endGroup); + +/*! + * @brief MMC excute tuning function. + * + * @param card Card descriptor. + * @retval kStatus_Success Operate successfully. + * @retval kStatus_SDMMC_TuningFail tuning fail. + * @retval kStatus_SDMMC_TransferFailed transfer fail + */ +static status_t inline MMC_ExecuteTuning(mmc_card_t *card); + +/*! + * @brief Read data from specific MMC card + * + * @param card Card descriptor. + * @param buffer Buffer to save received data. + * @param startBlock Start block to read. + * @param blockSize Block size. + * @param blockCount Block count to read. + * @retval kStatus_SDMMC_CardNotSupport Card doesn't support. + * @retval kStatus_SDMMC_WaitWriteCompleteFailed Wait write complete failed. + * @retval kStatus_SDMMC_SetBlockCountFailed Set block count failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_StopTransmissionFailed Stop transmission failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_Read( + mmc_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockSize, uint32_t blockCount); + +/*! + * @brief Write data from specific MMC card + * + * @param card Card descriptor. + * @param buffer Buffer to hold the data to write. + * @param startBlock Start block to write. + * @param blockSize Block size. + * @param blockCount Block count to write. + * @retval kStatus_SDMMC_CardNotSupport Card doesn't support. + * @retval kStatus_SDMMC_SetBlockCountFailed Set block count failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_StopTransmissionFailed Stop transmission failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t MMC_Write( + mmc_card_t *card, const uint8_t *buffer, uint32_t startBlock, uint32_t blockSize, uint32_t blockCount); + +/*! + * @brief card transfer function wrapper + * This function is used to do tuning before transfer if the cmd won't casue re-tuning + * request, then you can call host transfer function directly + * @param card Card descriptor. + * @param content Transfer content. + * @param retry Retry times. + * @retval kStatus_SDMMC_TransferFailed transfer fail + * @retval kStatus_SDMMC_TuningFail tuning fail + * @retval kStatus_Success transfer success + */ +static status_t MMC_Transfer(mmc_card_t *card, SDMMCHOST_TRANSFER *content, uint32_t retry); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/* Frequency unit defined in TRANSFER SPEED field in CSD */ +static const uint32_t g_transerSpeedFrequencyUnit[] = {100000U, 1000000U, 10000000U, 100000000U}; +/* The multiplying value defined in TRANSFER SPEED field in CSD */ +static const uint32_t g_transerSpeedMultiplierFactor[] = {0U, 10U, 12U, 13U, 15U, 20U, 26U, 30U, + 35U, 40U, 45U, 52U, 55U, 60U, 70U, 80U}; +/* g_sdmmc statement */ +extern uint32_t g_sdmmc[SDK_SIZEALIGN(SDMMC_GLOBAL_BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)]; + +/******************************************************************************* + * Code + ******************************************************************************/ +static status_t inline MMC_SelectCard(mmc_card_t *card, bool isSelected) +{ + assert(card); + + return SDMMC_SelectCard(card->host.base, card->host.transfer, card->relativeAddress, isSelected); +} + +static status_t inline MMC_SetBlockCount(mmc_card_t *card, uint32_t blockCount) +{ + assert(card); + + return SDMMC_SetBlockCount(card->host.base, card->host.transfer, blockCount); +} + +static status_t inline MMC_GoIdle(mmc_card_t *card) +{ + assert(card); + + return SDMMC_GoIdle(card->host.base, card->host.transfer); +} + +static status_t inline MMC_SetBlockSize(mmc_card_t *card, uint32_t blockSize) +{ + assert(card); + + return SDMMC_SetBlockSize(card->host.base, card->host.transfer, blockSize); +} + +static status_t MMC_ExecuteTuning(mmc_card_t *card) +{ + assert(card); + + uint32_t blockSize = 0U; + + if (card->busWidth == kMMC_DataBusWidth4bit) + { + blockSize = 64U; + } + else if (card->busWidth == kMMC_DataBusWidth8bit) + { + blockSize = 128U; + } + else + { + /* do not need tuning in this situation */ + return kStatus_Success; + } + + return SDMMC_ExecuteTuning(card->host.base, card->host.transfer, kMMC_SendTuningBlock, blockSize); +} + +static status_t MMC_Transfer(mmc_card_t *card, SDMMCHOST_TRANSFER *content, uint32_t retry) +{ + assert(card->host.transfer); + assert(content); + status_t error; + + do + { + error = card->host.transfer(card->host.base, content); +#if SDMMC_ENABLE_SOFTWARE_TUNING + if (((error == SDMMCHOST_RETUNING_REQUEST) || (error == SDMMCHOST_TUNING_ERROR)) && + ((card->busTiming == kMMC_HighSpeed200Timing) || (card->busTiming == kMMC_HighSpeed400Timing))) + { + /* tuning error need reset tuning circuit */ + if (error == SDMMCHOST_TUNING_ERROR) + { + SDMMCHOST_RESET_TUNING(card->host.base, 100U); + } + /* execute re-tuning */ + if (MMC_ExecuteTuning(card) != kStatus_Success) + { + error = kStatus_SDMMC_TuningFail; + break; + } + else + { + continue; + } + } + else +#endif + if (error != kStatus_Success) + { + error = kStatus_SDMMC_TransferFailed; + } + else + { + } + + if (retry != 0U) + { + retry--; + } + else + { + break; + } + + } while (error != kStatus_Success); + + return error; +} + +static status_t MMC_WaitWriteComplete(mmc_card_t *card) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + + command.index = kSDMMC_SendStatus; + command.argument = card->relativeAddress << 16U; + command.responseType = kCARD_ResponseTypeR1; + + do + { + content.command = &command; + content.data = 0U; + if (kStatus_Success != MMC_Transfer(card, &content, 2U)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* check the response error */ + if ((command.response[0U] & (SDMMC_R1_ALL_ERROR_FLAG | SDMMC_MASK(kSDMMC_R1SwitchErrorFlag)))) + { + return kStatus_SDMMC_WaitWriteCompleteFailed; + } + + if ((command.response[0U] & SDMMC_MASK(kSDMMC_R1ReadyForDataFlag)) && + (SDMMC_R1_CURRENT_STATE(command.response[0U]) != kSDMMC_R1StateProgram)) + { + break; + } + } while (true); + + return kStatus_Success; +} + +static status_t MMC_StopTransmission(mmc_card_t *card) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + + command.index = kSDMMC_StopTransmission; + command.argument = 0U; + command.type = kCARD_CommandTypeAbort; + command.responseType = kCARD_ResponseTypeR1b; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; + + content.command = &command; + content.data = 0U; + if (kStatus_Success != MMC_Transfer(card, &content, 2U)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +static status_t MMC_SwitchVoltage(mmc_card_t *card, uint32_t *opCode) +{ + mmc_voltage_window_t tempVoltage = kMMC_VoltageWindowNone; + /* Get host's voltage window. */ + if (((kSDMMCHOST_SupportV330 != SDMMCHOST_NOT_SUPPORT) || (kSDMMCHOST_SupportV300 != SDMMCHOST_NOT_SUPPORT)) && + (card->ocr & MMC_OCR_V270TO360_MASK) && ((card->hostVoltageWindowVCC == kMMC_VoltageWindowNone) || + (card->hostVoltageWindowVCC == kMMC_VoltageWindows270to360))) + { + /* Save host intended voltage range */ + tempVoltage = kMMC_VoltageWindows270to360; + /* set the opcode */ + *opCode = MMC_OCR_V270TO360_MASK; + /* power off the card first */ + SDMMCHOST_ENABLE_MMC_POWER(false); + /* power off time */ + SDMMCHOST_Delay(1U); + /*switch voltage to 3.3V*/ + SDMMCHOST_SWITCH_VCC_TO_330V(); + /* repower the card */ + SDMMCHOST_ENABLE_MMC_POWER(true); + /* meet emmc spec, wait 1ms and 74 clocks */ + SDMMCHOST_Delay(2U); + } + + if ((kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) && (card->ocr & MMC_OCR_V170TO195_MASK) && + ((card->hostVoltageWindowVCC == kMMC_VoltageWindowNone) || + (card->hostVoltageWindowVCC == kMMC_VoltageWindow170to195))) + { + /* Save host intended voltage range */ + tempVoltage = kMMC_VoltageWindow170to195; + /* set the opcode */ + *opCode = MMC_OCR_V170TO195_MASK; + /* power off the card first */ + SDMMCHOST_ENABLE_MMC_POWER(false); + /* power off time */ + SDMMCHOST_Delay(1U); + /* switch voltage to 1.8V */ + SDMMCHOST_SWITCH_VCC_TO_180V(); + /* repower the card */ + SDMMCHOST_ENABLE_MMC_POWER(true); + /* meet emmc spec, wait 1ms and 74 clocks */ + SDMMCHOST_Delay(2U); + } + + card->hostVoltageWindowVCC = tempVoltage; + + return kStatus_Success; +} + +static status_t MMC_SendOperationCondition(mmc_card_t *card, uint32_t arg) +{ + assert(card); + assert(card->host.transfer); + + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_TRANSFER content = {0}; + status_t error; + uint32_t i = FSL_SDMMC_MAX_VOLTAGE_RETRIES; + + /* Send CMD1 with the intended voltage range in the argument(either 0x00FF8000 or 0x00000080) */ + command.index = kMMC_SendOperationCondition; + command.argument = arg; + command.responseType = kCARD_ResponseTypeR3; + + content.command = &command; + content.data = NULL; + do + { + if (kStatus_Success != card->host.transfer(card->host.base, &content)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* record OCR register */ + card->ocr = command.response[0U]; + + if ((arg == 0U) && (command.response[0U] != 0U)) + { + error = kStatus_Success; + } + /* Repeat CMD1 until the busy bit is cleared. */ + else if (!(command.response[0U] & MMC_OCR_BUSY_MASK)) + { + error = kStatus_Timeout; + } + else + { + error = kStatus_Success; + if (((card->ocr & MMC_OCR_ACCESS_MODE_MASK) >> MMC_OCR_ACCESS_MODE_SHIFT) == kMMC_AccessModeSector) + { + card->flags |= kMMC_SupportHighCapacityFlag; + } + } + } while ((i--) && (error != kStatus_Success)); + + return error; +} + +static status_t MMC_SetRelativeAddress(mmc_card_t *card) +{ + assert(card); + assert(card->host.transfer); + + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_TRANSFER content = {0}; + + /* Send CMD3 with a chosen relative address, with value greater than 1 */ + command.index = kMMC_SetRelativeAddress; + command.argument = (MMC_DEFAULT_RELATIVE_ADDRESS << 16U); + command.responseType = kCARD_ResponseTypeR1; + + content.command = &command; + content.data = NULL; + if ((kStatus_Success == card->host.transfer(card->host.base, &content)) || + (!((command.response[0U]) & SDMMC_R1_ALL_ERROR_FLAG))) + { + card->relativeAddress = MMC_DEFAULT_RELATIVE_ADDRESS; + return kStatus_Success; + } + + return kStatus_SDMMC_TransferFailed; +} + +static void MMC_DecodeCsd(mmc_card_t *card, uint32_t *rawCsd) +{ + assert(card); + assert(rawCsd); + + mmc_csd_t *csd; + uint32_t multiplier; + + csd = &(card->csd); + csd->csdStructureVersion = (uint8_t)((rawCsd[3U] & 0xC0000000U) >> 30U); + csd->systemSpecificationVersion = (uint8_t)((rawCsd[3U] & 0x3C000000U) >> 26U); + csd->dataReadAccessTime1 = (uint8_t)((rawCsd[3U] & 0xFF0000U) >> 16U); + csd->dataReadAccessTime2 = (uint8_t)((rawCsd[3U] & 0xFF00U) >> 8U); + csd->transferSpeed = (uint8_t)(rawCsd[3U] & 0xFFU); + csd->cardCommandClass = (uint16_t)((rawCsd[2U] & 0xFFF00000U) >> 20U); + /* Max block length read/write one time */ + csd->readBlockLength = (uint8_t)((rawCsd[2U] & 0xF0000U) >> 16U); + if (rawCsd[2U] & 0x8000U) + { + csd->flags |= kMMC_CsdReadBlockPartialFlag; + } + if (rawCsd[2U] & 0x4000U) + { + csd->flags |= kMMC_CsdWriteBlockMisalignFlag; + } + if (rawCsd[2U] & 0x2000U) + { + csd->flags |= kMMC_CsdReadBlockMisalignFlag; + } + if (rawCsd[2U] & 0x1000U) + { + csd->flags |= kMMC_CsdDsrImplementedFlag; + } + csd->deviceSize = (uint16_t)(((rawCsd[2U] & 0x3FFU) << 2U) + ((rawCsd[1U] & 0xC0000000U) >> 30U)); + csd->readCurrentVddMin = (uint8_t)((rawCsd[1U] & 0x38000000U) >> 27U); + csd->readCurrentVddMax = (uint8_t)((rawCsd[1U] & 0x07000000U) >> 24U); + csd->writeCurrentVddMin = (uint8_t)((rawCsd[1U] & 0x00E00000U) >> 21U); + csd->writeCurrentVddMax = (uint8_t)((rawCsd[1U] & 0x001C0000U) >> 18U); + csd->deviceSizeMultiplier = (uint8_t)((rawCsd[1U] & 0x00038000U) >> 15U); + csd->eraseGroupSize = (uint8_t)((rawCsd[1U] & 0x00007C00U) >> 10U); + csd->eraseGroupSizeMultiplier = (uint8_t)((rawCsd[1U] & 0x000003E0U) >> 5U); + csd->writeProtectGroupSize = (uint8_t)(rawCsd[1U] & 0x0000001FU); + if (rawCsd[0U] & 0x80000000U) + { + csd->flags |= kMMC_CsdWriteProtectGroupEnabledFlag; + } + csd->defaultEcc = (uint8_t)((rawCsd[0U] & 0x60000000U) >> 29U); + csd->writeSpeedFactor = (uint8_t)((rawCsd[0U] & 0x1C000000U) >> 26U); + csd->maxWriteBlockLength = (uint8_t)((rawCsd[0U] & 0x03C00000U) >> 22U); + if (rawCsd[0U] & 0x00200000U) + { + csd->flags |= kMMC_CsdWriteBlockPartialFlag; + } + if (rawCsd[0U] & 0x00010000U) + { + csd->flags |= kMMC_ContentProtectApplicationFlag; + } + if (rawCsd[0U] & 0x00008000U) + { + csd->flags |= kMMC_CsdFileFormatGroupFlag; + } + if (rawCsd[0U] & 0x00004000U) + { + csd->flags |= kMMC_CsdCopyFlag; + } + if (rawCsd[0U] & 0x00002000U) + { + csd->flags |= kMMC_CsdPermanentWriteProtectFlag; + } + if (rawCsd[0U] & 0x00001000U) + { + csd->flags |= kMMC_CsdTemporaryWriteProtectFlag; + } + csd->fileFormat = (uint8_t)((rawCsd[0U] & 0x00000C00U) >> 10U); + csd->eccCode = (uint8_t)((rawCsd[0U] & 0x00000300U) >> 8U); + + /* Calculate the device total block count. */ + /* For the card capacity of witch higher than 2GB, the maximum possible value should be set to this register + is 0xFFF. */ + if (card->csd.deviceSize != 0xFFFU) + { + multiplier = (2U << (card->csd.deviceSizeMultiplier + 2U - 1U)); + card->userPartitionBlocks = (((card->csd.deviceSize + 1U) * multiplier) / FSL_SDMMC_DEFAULT_BLOCK_SIZE); + } + + card->blockSize = FSL_SDMMC_DEFAULT_BLOCK_SIZE; +} + +static void MMC_SetMaxFrequency(mmc_card_t *card) +{ + assert(card); + + uint32_t frequencyUnit; + uint32_t multiplierFactor; + uint32_t maxBusClock_Hz; + + /* g_fsdhcCommandUnitInTranSpeed and g_transerSpeedMultiplierFactor are used to calculate the max speed in normal + mode not high speed mode. + For cards supporting version 4.0, 4.1, and 4.2 of the specification, the value shall be 20MHz(0x2A). + For cards supporting version 4.3, the value shall be 26 MHz (0x32H). In High speed mode, the max + frequency is decided by CARD_TYPE in Extended CSD. */ + frequencyUnit = g_transerSpeedFrequencyUnit[READ_MMC_TRANSFER_SPEED_FREQUENCY_UNIT(card->csd)]; + multiplierFactor = g_transerSpeedMultiplierFactor[READ_MMC_TRANSFER_SPEED_MULTIPLIER(card->csd)]; + maxBusClock_Hz = (frequencyUnit * multiplierFactor) / DIVIDER_IN_TRANSFER_SPEED; + card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, maxBusClock_Hz); +} + +static status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card) +{ + assert(card); + + uint32_t erase_group_size; + uint32_t erase_group_multiplier; + mmc_extended_csd_config_t extendedCsdconfig; + + if (((!(card->flags & kMMC_SupportHighCapacityFlag)) || (card->extendedCsd.highCapacityEraseUnitSize == 0)) || + (card->extendedCsd.highCapacityEraseTimeout == 0)) + { + erase_group_size = card->csd.eraseGroupSize; + erase_group_multiplier = card->csd.eraseGroupSizeMultiplier; + card->eraseGroupBlocks = ((erase_group_size + 1U) * (erase_group_multiplier + 1U)); + } + else + { + /* Erase Unit Size = 512Kbyte * HC_ERASE_GRP_SIZE. Block size is 512 bytes. */ + card->eraseGroupBlocks = (card->extendedCsd.highCapacityEraseUnitSize * 1024U); + /* Enable high capacity erase unit size. */ + extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeSetBits; + extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexEraseGroupDefinition; + extendedCsdconfig.ByteValue = 0x01U; /* The high capacity erase unit size enable bit is bit 0 */ + extendedCsdconfig.commandSet = kMMC_CommandSetStandard; + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) + { + return kStatus_SDMMC_ConfigureExtendedCsdFailed; + } + } + + return kStatus_Success; +} + +static status_t MMC_SetExtendedCsdConfig(mmc_card_t *card, const mmc_extended_csd_config_t *config) +{ + assert(card); + assert(card->host.transfer); + assert(config); + + uint32_t parameter = 0U; + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_TRANSFER content = {0}; + + parameter |= ((uint32_t)(config->commandSet) << MMC_SWITCH_COMMAND_SET_SHIFT); + parameter |= ((uint32_t)(config->ByteValue) << MMC_SWITCH_VALUE_SHIFT); + parameter |= ((uint32_t)(config->ByteIndex) << MMC_SWITCH_BYTE_INDEX_SHIFT); + parameter |= ((uint32_t)(config->accessMode) << MMC_SWITCH_ACCESS_MODE_SHIFT); + + command.index = kMMC_Switch; + command.argument = parameter; + command.responseType = kCARD_ResponseTypeR1b; /* Send switch command to set the pointed byte in Extended CSD. */ + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG | SDMMC_MASK(kSDMMC_R1SwitchErrorFlag); + + content.command = &command; + content.data = NULL; + if (kStatus_Success != MMC_Transfer(card, &content, 2U)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* Wait for the card write process complete because of that card read process and write process use one buffer. */ + if (kStatus_Success != MMC_WaitWriteComplete(card)) + { + return kStatus_SDMMC_WaitWriteCompleteFailed; + } + + return kStatus_Success; +} + +static void MMC_DecodeExtendedCsd(mmc_card_t *card, uint32_t *rawExtendedCsd) +{ + assert(card); + assert(rawExtendedCsd); + + uint8_t *buffer = (uint8_t *)rawExtendedCsd; + mmc_extended_csd_t *extendedCsd = &(card->extendedCsd); + + /* Extended CSD is transferred as a data block from least byte indexed 0. */ + extendedCsd->bootPartitionWP = buffer[173U]; + extendedCsd->bootWPStatus = buffer[174U]; + extendedCsd->highDensityEraseGroupDefinition = buffer[175U]; + extendedCsd->bootDataBusConditions = buffer[177U]; + extendedCsd->bootConfigProtect = buffer[178U]; + extendedCsd->partitionConfig = buffer[179U]; + extendedCsd->eraseMemoryContent = buffer[181U]; + extendedCsd->dataBusWidth = buffer[183U]; + extendedCsd->highSpeedTiming = buffer[185U]; + extendedCsd->powerClass = buffer[187U]; + extendedCsd->commandSetRevision = buffer[189U]; + extendedCsd->commandSet = buffer[191U]; + extendedCsd->extendecCsdVersion = buffer[192U]; + extendedCsd->csdStructureVersion = buffer[194U]; + extendedCsd->partitionAttribute = buffer[156U]; + extendedCsd->extPartitionSupport = buffer[494U]; + extendedCsd->cardType = buffer[196U]; + /* This field define the type of the card. The only currently valid values for this field are 0x01 and 0x03. */ + card->flags |= extendedCsd->cardType; + + extendedCsd->ioDriverStrength = buffer[197U]; + + extendedCsd->powerClass52MHz195V = buffer[200U]; + extendedCsd->powerClass26MHz195V = buffer[201U]; + extendedCsd->powerClass52MHz360V = buffer[202U]; + extendedCsd->powerClass26MHz360V = buffer[203U]; + extendedCsd->powerClass200MHZVCCQ130VVCC360V = buffer[236U]; + extendedCsd->powerClass200MHZVCCQ195VVCC360V = buffer[237U]; + extendedCsd->powerClass52MHZDDR195V = buffer[238U]; + extendedCsd->powerClass52MHZDDR360V = buffer[239U]; + extendedCsd->powerClass200MHZDDR360V = buffer[253U]; + extendedCsd->minimumReadPerformance4Bit26MHz = buffer[205U]; + extendedCsd->minimumWritePerformance4Bit26MHz = buffer[206U]; + extendedCsd->minimumReadPerformance8Bit26MHz4Bit52MHz = buffer[207U]; + extendedCsd->minimumWritePerformance8Bit26MHz4Bit52MHz = buffer[208U]; + extendedCsd->minimumReadPerformance8Bit52MHz = buffer[209U]; + extendedCsd->minimumWritePerformance8Bit52MHz = buffer[210U]; + extendedCsd->minReadPerformance8bitAt52MHZDDR = buffer[234U]; + extendedCsd->minWritePerformance8bitAt52MHZDDR = buffer[235U]; + /* Get user partition size. */ + extendedCsd->sectorCount = ((((uint32_t)buffer[215U]) << 24U) + (((uint32_t)buffer[214U]) << 16U) + + (((uint32_t)buffer[213U]) << 8U) + (uint32_t)buffer[212U]); + if (card->flags & kMMC_SupportHighCapacityFlag) + { + card->userPartitionBlocks = card->extendedCsd.sectorCount; + } + + extendedCsd->sleepAwakeTimeout = buffer[217U]; + extendedCsd->sleepCurrentVCCQ = buffer[219U]; + extendedCsd->sleepCurrentVCC = buffer[220U]; + extendedCsd->highCapacityWriteProtectGroupSize = buffer[221U]; + extendedCsd->reliableWriteSectorCount = buffer[222U]; + extendedCsd->highCapacityEraseTimeout = buffer[223U]; + extendedCsd->highCapacityEraseUnitSize = buffer[224U]; + extendedCsd->accessSize = buffer[225U]; + + /* Get boot partition size: 128KB * BOOT_SIZE_MULT*/ + card->bootPartitionBlocks = ((128U * 1024U * buffer[226U]) / FSL_SDMMC_DEFAULT_BLOCK_SIZE); + + /* Check if card support boot mode. */ + if (buffer[228U] & 0x1U) + { + card->flags |= kMMC_SupportAlternateBootFlag; + } + else if (buffer[228U] & 0x2U) + { + card->flags |= kMMC_SupportDDRBootFlag; + } + else if (buffer[228U] & 0x4U) + { + card->flags |= kMMC_SupportHighSpeedBootFlag; + } + else + { + } + /* cache size unit 1kb */ + extendedCsd->cacheSize = (((uint32_t)buffer[252U]) << 24) | (((uint32_t)buffer[251U]) << 16) | + (((uint32_t)buffer[250U]) << 8) | (((uint32_t)buffer[249U])); + + extendedCsd->supportedCommandSet = buffer[504U]; +} + +static status_t MMC_SendExtendedCsd(mmc_card_t *card, uint8_t *targetAddr, uint32_t byteIndex) +{ + assert(card); + assert(card->host.transfer); + + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_DATA data = {0}; + uint32_t i; + + command.index = kMMC_SendExtendedCsd; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR1; + + data.blockCount = 1U; + data.blockSize = MMC_EXTENDED_CSD_BYTES; + data.rxData = card->rawExtendedCsd; + + content.command = &command; + content.data = &data; + if ((kStatus_Success == card->host.transfer(card->host.base, &content)) && + (!(command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG))) + { + /* The response is from bit 127:8 in R2, corresponding to command.response[3][31:0] to + command.response[0U][31:8] */ + switch (card->host.config.endianMode) + { + case kSDMMCHOST_EndianModeLittle: + /* Doesn't need to switch byte sequence when decode bytes as little endian sequence. */ + break; + case kSDMMCHOST_EndianModeBig: + /* In big endian mode, the SD bus byte transferred first is the byte stored in highest position + in a word which cause 4 byte's sequence in a word is not consistent with their original sequence + from card. */ + for (i = 0U; i < MMC_EXTENDED_CSD_BYTES / 4U; i++) + { + card->rawExtendedCsd[i] = SWAP_WORD_BYTE_SEQUENCE(card->rawExtendedCsd[i]); + } + break; + case kSDMMCHOST_EndianModeHalfWordBig: + for (i = 0U; i < MMC_EXTENDED_CSD_BYTES / 4U; i++) + { + card->rawExtendedCsd[i] = SWAP_HALF_WROD_BYTE_SEQUENCE(card->rawExtendedCsd[i]); + } + break; + default: + return kStatus_SDMMC_NotSupportYet; + } + if (targetAddr != NULL) + { + *targetAddr = ((uint8_t *)card->rawExtendedCsd)[byteIndex]; + } + else + { + MMC_DecodeExtendedCsd(card, card->rawExtendedCsd); + } + + return kStatus_Success; + } + + return kStatus_SDMMC_TransferFailed; +} + +static status_t MMC_SetPowerClass(mmc_card_t *card) +{ + assert(card); + + uint8_t mask = 0, shift = 0U; + uint8_t powerClass = 0; + mmc_extended_csd_config_t extendedCsdconfig; + + if ((card->busWidth == kMMC_DataBusWidth4bit) || (card->busWidth == kMMC_DataBusWidth4bitDDR)) + { + mask = MMC_POWER_CLASS_4BIT_MASK; /* The mask of 4 bit bus width's power class */ + shift = 0U; + } + else if ((card->busWidth == kMMC_DataBusWidth8bit) || (card->busWidth == kMMC_DataBusWidth8bitDDR)) + { + mask = MMC_POWER_CLASS_8BIT_MASK; /* The mask of 8 bit bus width's power class */ + shift = 4U; + } + else + { + return kStatus_Success; + } + + switch (card->hostVoltageWindowVCC) + { + case kMMC_VoltageWindows270to360: + + if (card->busTiming == kMMC_HighSpeed200Timing) + { + if (card->hostVoltageWindowVCCQ == kMMC_VoltageWindow170to195) + { + powerClass = ((card->extendedCsd.powerClass200MHZVCCQ195VVCC360V) & mask); + } + else if (card->hostVoltageWindowVCCQ == kMMC_VoltageWindow120) + { + powerClass = ((card->extendedCsd.powerClass200MHZVCCQ130VVCC360V) & mask); + } + } + else if (card->busTiming == kMMC_HighSpeed400Timing) + { + powerClass = ((card->extendedCsd.powerClass200MHZDDR360V) & mask); + } + else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busWidth > kMMC_DataBusWidth8bit)) + { + powerClass = ((card->extendedCsd.powerClass52MHZDDR360V) & mask); + } + else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busClock_Hz > MMC_CLOCK_26MHZ)) + { + powerClass = ((card->extendedCsd.powerClass52MHz360V) & mask); + } + else if (card->busTiming == kMMC_HighSpeedTiming) + { + powerClass = ((card->extendedCsd.powerClass26MHz360V) & mask); + } + + break; + + case kMMC_VoltageWindow170to195: + + if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busClock_Hz <= MMC_CLOCK_26MHZ)) + { + powerClass = ((card->extendedCsd.powerClass26MHz195V) & mask); + } + else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busClock_Hz > MMC_CLOCK_26MHZ)) + { + powerClass = ((card->extendedCsd.powerClass52MHz195V) & mask); + } + else if ((card->busTiming == kMMC_HighSpeedTiming) && (card->busWidth > kMMC_DataBusWidth8bit)) + { + powerClass = ((card->extendedCsd.powerClass52MHZDDR195V) & mask); + } + + break; + default: + powerClass = 0; + break; + } + + /* due to 8bit power class position [7:4] */ + powerClass >>= shift; + + if (powerClass > 0U) + { + extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; + extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexPowerClass; + extendedCsdconfig.ByteValue = powerClass; + extendedCsdconfig.commandSet = kMMC_CommandSetStandard; + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) + { + return kStatus_SDMMC_ConfigureExtendedCsdFailed; + } + /* restore power class */ + card->extendedCsd.powerClass = powerClass; + } + + return kStatus_Success; +} + +static status_t MMC_SendTestPattern(mmc_card_t *card, uint32_t blockSize, uint32_t *pattern) +{ + assert(card); + assert(card->host.transfer); + assert(blockSize <= FSL_SDMMC_DEFAULT_BLOCK_SIZE); + assert(pattern); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_DATA data = {0}; + + command.index = kMMC_SendingBusTest; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR1; + + /* Ignore errors in bus test procedure to improve chances that the test will work. */ + data.enableIgnoreError = true; + data.blockCount = 1U; + data.blockSize = blockSize; + data.txData = pattern; + + content.command = &command; + content.data = &data; + if ((kStatus_Success != card->host.transfer(card->host.base, &content)) || + (command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +static status_t MMC_ReceiveTestPattern(mmc_card_t *card, uint32_t blockSize, uint32_t *pattern) +{ + assert(card); + assert(card->host.transfer); + assert(blockSize <= FSL_SDMMC_DEFAULT_BLOCK_SIZE); + assert(pattern); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_DATA data = {0}; + + command.index = kMMC_BusTestRead; + command.responseType = kCARD_ResponseTypeR1; + + /* Ignore errors in bus test procedure to improve chances that the test will work. */ + data.enableIgnoreError = true; + data.blockCount = 1U; + data.blockSize = blockSize; + data.rxData = pattern; + + content.command = &command; + content.data = &data; + if ((kStatus_Success != card->host.transfer(card->host.base, &content)) || + ((command.response[0U]) & SDMMC_R1_ALL_ERROR_FLAG)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +static status_t MMC_TestDataBusWidth(mmc_card_t *card, mmc_data_bus_width_t width) +{ + assert(card); + + uint32_t blockSize = 0U; + uint32_t tempsendPattern = 0U; + uint32_t *tempPattern = g_sdmmc; + uint32_t xorMask = 0U; + uint32_t xorResult = 0U; + + /* For 8 data lines the data block would be (MSB to LSB): 0x0000_0000_0000_AA55, + For 4 data lines the data block would be (MSB to LSB): 0x0000_005A, + For only 1 data line the data block would be: 0x80 */ + switch (width) + { + case kMMC_DataBusWidth8bit: + case kMMC_DataBusWidth8bitDDR: + blockSize = 8U; + tempPattern[0U] = 0xAA55U; + xorMask = 0xFFFFU; + xorResult = 0xFFFFU; + break; + case kMMC_DataBusWidth4bit: + case kMMC_DataBusWidth4bitDDR: + blockSize = 4U; + tempPattern[0U] = 0x5AU; + xorMask = 0xFFU; + xorResult = 0xFFU; + break; + default: + blockSize = 4U; + tempPattern[0U] = 0x80U; + xorMask = 0xFFU; + xorResult = 0xC0U; + break; + } + switch (card->host.config.endianMode) + { + case kSDMMCHOST_EndianModeLittle: + /* Doesn't need to switch byte sequence when decodes bytes as little endian sequence. */ + break; + case kSDMMCHOST_EndianModeBig: + /* In big endian mode, the byte transferred first is the byte stored in highest byte position in a word + which will cause the card receive the inverted byte sequence in a word in bus test procedure. So the + sequence of 4 bytes stored in a word should be converted. */ + tempPattern[0] = SWAP_WORD_BYTE_SEQUENCE(tempPattern[0]); + xorMask = SWAP_WORD_BYTE_SEQUENCE(xorMask); + xorResult = SWAP_WORD_BYTE_SEQUENCE(xorResult); + break; + case kSDMMCHOST_EndianModeHalfWordBig: + /* In half word big endian mode, the byte transferred first is the lower byte in the higher half word. + 0xAA55U should be converted to 0xAA550000U to set the 0x55 to be the first byte to transfer. */ + tempPattern[0] = SWAP_HALF_WROD_BYTE_SEQUENCE(tempPattern[0]); + xorMask = SWAP_HALF_WROD_BYTE_SEQUENCE(xorMask); + xorResult = SWAP_HALF_WROD_BYTE_SEQUENCE(xorResult); + tempPattern[0] = SWAP_WORD_BYTE_SEQUENCE(tempPattern[0]); + xorMask = SWAP_WORD_BYTE_SEQUENCE(xorMask); + xorResult = SWAP_WORD_BYTE_SEQUENCE(xorResult); + break; + default: + return kStatus_SDMMC_NotSupportYet; + } + + if (kStatus_Success != MMC_SendTestPattern(card, blockSize, tempPattern)) + { + return kStatus_SDMMC_SendTestPatternFailed; + } + /* restore the send pattern */ + tempsendPattern = tempPattern[0U]; + /* reset the global buffer */ + tempPattern[0U] = 0U; + + if (kStatus_Success != MMC_ReceiveTestPattern(card, blockSize, tempPattern)) + { + return kStatus_SDMMC_ReceiveTestPatternFailed; + } + + /* XOR the send pattern and receive pattern */ + if (((tempPattern[0U] ^ tempsendPattern) & xorMask) != xorResult) + { + return kStatus_Fail; + } + + return kStatus_Success; +} + +static status_t MMC_SetDataBusWidth(mmc_card_t *card, mmc_data_bus_width_t width) +{ + assert(card); + + mmc_extended_csd_config_t extendedCsdconfig; + + /* Set data bus width */ + extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; + extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexBusWidth; + extendedCsdconfig.ByteValue = width; + extendedCsdconfig.commandSet = kMMC_CommandSetStandard; + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) + { + return kStatus_SDMMC_ConfigureExtendedCsdFailed; + } + /* restore data bus width */ + card->extendedCsd.dataBusWidth = width; + + return kStatus_Success; +} + +static status_t MMC_SetMaxDataBusWidth(mmc_card_t *card, mmc_high_speed_timing_t targetTiming) +{ + assert(card); + + status_t error = kStatus_Fail; + + switch (card->busWidth) + { + case kMMC_DataBusWidth1bit: + case kMMC_DataBusWidth8bitDDR: + /* Test and set the data bus width for card. */ + if ((SDMMCHOST_NOT_SUPPORT != kSDMMCHOST_Support8BitBusWidth) && + (card->flags & (kMMC_SupportHighSpeedDDR52MHZ180V300VFlag | kMMC_SupportHighSpeedDDR52MHZ120VFlag)) && + ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed400Timing))) + { + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH8BIT); + if ((kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth8bitDDR)) && + (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth8bitDDR))) + { + error = kStatus_Success; + card->busWidth = kMMC_DataBusWidth8bitDDR; + break; + } + /* HS400 mode only support 8bit data bus */ + else if (card->busTiming == kMMC_HighSpeed400Timing) + { + return kStatus_SDMMC_SetDataBusWidthFailed; + } + } + case kMMC_DataBusWidth4bitDDR: + if ((SDMMCHOST_NOT_SUPPORT != kSDMMCHOST_Support4BitBusWidth) && + (card->flags & (kMMC_SupportHighSpeedDDR52MHZ180V300VFlag | kMMC_SupportHighSpeedDDR52MHZ120VFlag)) && + ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed400Timing))) + { + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH4BIT); + if ((kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth4bitDDR)) && + (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth4bitDDR))) + { + error = kStatus_Success; + card->busWidth = kMMC_DataBusWidth4bitDDR; + + break; + } + } + case kMMC_DataBusWidth8bit: + if ((SDMMCHOST_NOT_SUPPORT != kSDMMCHOST_Support8BitBusWidth) && + ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed200Timing))) + { + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH8BIT); + if ((kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth8bit)) && + (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth8bit))) + { + error = kStatus_Success; + card->busWidth = kMMC_DataBusWidth8bit; + break; + } + } + + case kMMC_DataBusWidth4bit: + if ((SDMMCHOST_NOT_SUPPORT != kSDMMCHOST_Support4BitBusWidth) && + ((targetTiming == kMMC_HighSpeedTiming) || (targetTiming == kMMC_HighSpeed200Timing))) + { + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH4BIT); + if ((kStatus_Success == MMC_TestDataBusWidth(card, kMMC_DataBusWidth4bit)) && + (kStatus_Success == MMC_SetDataBusWidth(card, kMMC_DataBusWidth4bit))) + { + error = kStatus_Success; + card->busWidth = kMMC_DataBusWidth4bit; + break; + } + /* HS200 mode only support 4bit/8bit data bus */ + else if (targetTiming == kMMC_HighSpeed200Timing) + { + return kStatus_SDMMC_SetDataBusWidthFailed; + } + } + default: + break; + } + + if (error == kStatus_Fail) + { + /* Card's data bus width will be default 1 bit mode. */ + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH1BIT); + } + + return kStatus_Success; +} + +static status_t MMC_SwitchHSTiming(mmc_card_t *card, uint8_t timing, uint8_t driverStrength) +{ + assert(card); + + uint8_t hsTiming = 0; + + mmc_extended_csd_config_t extendedCsdconfig; + + /* check the target driver strength support or not */ + if (((card->extendedCsd.ioDriverStrength & (1 << driverStrength)) == 0U) && + (card->extendedCsd.extendecCsdVersion >= kMMC_ExtendedCsdRevision17)) + { + return kStatus_SDMMC_NotSupportYet; + } + /* calucate the register value */ + hsTiming = (timing & 0xF) | (uint8_t)(driverStrength << 4U); + + /* Switch to high speed timing. */ + extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; + extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexHighSpeedTiming; + extendedCsdconfig.ByteValue = hsTiming; + extendedCsdconfig.commandSet = kMMC_CommandSetStandard; + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) + { + return kStatus_SDMMC_ConfigureExtendedCsdFailed; + } + + card->extendedCsd.highSpeedTiming = hsTiming; + + return kStatus_Success; +} + +static status_t MMC_SwitchToHighSpeed(mmc_card_t *card) +{ + assert(card); + + uint32_t freq = 0U; + + /* check VCCQ voltage supply */ + if (kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) + { + if ((card->hostVoltageWindowVCCQ != kMMC_VoltageWindow170to195) && + (card->extendedCsd.extendecCsdVersion > kMMC_ExtendedCsdRevision10)) + { + SDMMCHOST_SWITCH_VOLTAGE180V(card->host.base, true); + card->hostVoltageWindowVCCQ = kMMC_VoltageWindow170to195; + } + } + else if (kSDMMCHOST_SupportV120 != SDMMCHOST_NOT_SUPPORT) + { + if ((card->hostVoltageWindowVCCQ != kMMC_VoltageWindow120) && + (card->extendedCsd.extendecCsdVersion >= kMMC_ExtendedCsdRevision16)) + { + SDMMCHOST_SWITCH_VOLTAGE120V(card->host.base, true); + card->hostVoltageWindowVCCQ = kMMC_VoltageWindow120; + } + } + else + { + card->hostVoltageWindowVCCQ = kMMC_VoltageWindows270to360; + } + + if (kStatus_Success != MMC_SwitchHSTiming(card, kMMC_HighSpeedTiming, kMMC_DriverStrength0)) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + + if ((card->busWidth == kMMC_DataBusWidth4bitDDR) || (card->busWidth == kMMC_DataBusWidth8bitDDR)) + { + freq = MMC_CLOCK_DDR52; + SDMMCHOST_ENABLE_DDR_MODE(card->host.base, true, 0U); + } + else if (card->flags & kMMC_SupportHighSpeed52MHZFlag) + { + freq = MMC_CLOCK_52MHZ; + } + else if (card->flags & kMMC_SupportHighSpeed26MHZFlag) + { + freq = MMC_CLOCK_26MHZ; + } + + card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, freq); + /* config io speed and strength */ + SDMMCHOST_CONFIG_MMC_IO(CARD_BUS_FREQ_100MHZ1, CARD_BUS_STRENGTH_7); + + /* Set card data width, it is nessesary to config the the data bus here, to meet emmc5.0 specification, + * when you are working in DDR mode , HS_TIMING must set before set bus width + */ + if (MMC_SetMaxDataBusWidth(card, kMMC_HighSpeedTiming) != kStatus_Success) + { + return kStatus_SDMMC_SetDataBusWidthFailed; + } + + card->busTiming = kMMC_HighSpeedTiming; + + return kStatus_Success; +} + +static status_t MMC_SwitchToHS200(mmc_card_t *card, uint32_t freq) +{ + assert(card); + + /* check VCCQ voltage supply */ + if (kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) + { + if (card->hostVoltageWindowVCCQ != kMMC_VoltageWindow170to195) + { + SDMMCHOST_SWITCH_VOLTAGE180V(card->host.base, true); + card->hostVoltageWindowVCCQ = kMMC_VoltageWindow170to195; + } + } + else if (kSDMMCHOST_SupportV120 != SDMMCHOST_NOT_SUPPORT) + { + if (card->hostVoltageWindowVCCQ != kMMC_VoltageWindow120) + { + SDMMCHOST_SWITCH_VOLTAGE120V(card->host.base, true); + card->hostVoltageWindowVCCQ = kMMC_VoltageWindow120; + } + } + else + { + return kStatus_SDMMC_InvalidVoltage; + } + + /* select bus width before select bus timing for HS200 mode */ + if (MMC_SetMaxDataBusWidth(card, kMMC_HighSpeed200Timing) != kStatus_Success) + { + return kStatus_SDMMC_SetDataBusWidthFailed; + } + + /* switch to HS200 mode */ + if (kStatus_Success != MMC_SwitchHSTiming(card, kMMC_HighSpeed200Timing, kMMC_DriverStrength0)) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + + card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, freq); + /* config io speed and strength */ + SDMMCHOST_CONFIG_MMC_IO(CARD_BUS_FREQ_200MHZ, CARD_BUS_STRENGTH_7); + + /* excute tuning for HS200 */ + if (MMC_ExecuteTuning(card) != kStatus_Success) + { + return kStatus_SDMMC_TuningFail; + } + + /* Wait for the card status ready. */ + if (kStatus_Success != MMC_WaitWriteComplete(card)) + { + return kStatus_SDMMC_WaitWriteCompleteFailed; + } + + card->busTiming = kMMC_HighSpeed200Timing; + + return kStatus_Success; +} + +static status_t MMC_SwitchToHS400(mmc_card_t *card) +{ + assert(card); + + /* check VCCQ voltage supply */ + if (kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) + { + if (card->hostVoltageWindowVCCQ != kMMC_VoltageWindow170to195) + { + SDMMCHOST_SWITCH_VOLTAGE180V(card->host.base, true); + card->hostVoltageWindowVCCQ = kMMC_VoltageWindow170to195; + } + } + else if (kSDMMCHOST_SupportV120 != SDMMCHOST_NOT_SUPPORT) + { + if (card->hostVoltageWindowVCCQ != kMMC_VoltageWindow120) + { + SDMMCHOST_SWITCH_VOLTAGE120V(card->host.base, true); + card->hostVoltageWindowVCCQ = kMMC_VoltageWindow120; + } + } + else + { + return kStatus_SDMMC_InvalidVoltage; + } + + /* check data bus width is 8 bit , otherwise return false */ + if (card->busWidth == kMMC_DataBusWidth8bit) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + + /* switch to high speed first */ + card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, MMC_CLOCK_52MHZ); + SDMMCHOST_CONFIG_MMC_IO(CARD_BUS_FREQ_100MHZ1, CARD_BUS_STRENGTH_5); + /*switch to high speed*/ + if (kStatus_Success != MMC_SwitchHSTiming(card, kMMC_HighSpeedTiming, kMMC_DriverStrength0)) + { + return kStatus_SDMMC_ConfigureExtendedCsdFailed; + } + card->busTiming = kMMC_HighSpeed400Timing; + /* switch to 8 bit DDR data bus width */ + if (kStatus_Success != MMC_SetDataBusWidth(card, kMMC_DataBusWidth8bitDDR)) + { + return kStatus_SDMMC_SetDataBusWidthFailed; + } + /* switch to HS400 */ + if (kStatus_Success != MMC_SwitchHSTiming(card, kMMC_HighSpeed400Timing, kMMC_DriverStrength0)) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + /* config to target freq */ + card->busClock_Hz = + SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SDMMCHOST_SUPPORT_HS400_FREQ); + /* config io speed and strength */ + SDMMCHOST_CONFIG_MMC_IO(CARD_BUS_FREQ_200MHZ, CARD_BUS_STRENGTH_7); + /* enable HS400 mode */ + SDMMCHOST_ENABLE_HS400_MODE(card->host.base, true); + /* enable DDR mode */ + SDMMCHOST_ENABLE_DDR_MODE(card->host.base, true, 0U); + /* config strobe DLL */ + SDMMCHOST_CONFIG_STROBE_DLL(card->host.base, SDMMCHOST_STROBE_DLL_DELAY_TARGET, + SDMMCHOST_STROBE_DLL_DELAY_UPDATE_INTERVAL); + /* enable DLL */ + SDMMCHOST_ENABLE_STROBE_DLL(card->host.base, true); + + return kStatus_Success; +} + +static status_t MMC_SelectBusTiming(mmc_card_t *card) +{ + assert(card); + + mmc_high_speed_timing_t targetTiming = card->busTiming; + + switch (targetTiming) + { + case kMMC_HighSpeedTimingNone: + case kMMC_HighSpeed400Timing: + if ((card->flags & (kMMC_SupportHS400DDR200MHZ180VFlag | kMMC_SupportHS400DDR200MHZ120VFlag)) && + ((kSDMMCHOST_SupportHS400 != SDMMCHOST_NOT_SUPPORT))) + { + /* switch to HS200 perform tuning */ + if (kStatus_Success != MMC_SwitchToHS200(card, SDMMCHOST_SUPPORT_HS400_FREQ / 2U)) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + /* switch to HS400 */ + if (kStatus_Success != MMC_SwitchToHS400(card)) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + break; + } + case kMMC_HighSpeed200Timing: + if ((card->flags & (kMMC_SupportHS200200MHZ180VFlag | kMMC_SupportHS200200MHZ120VFlag)) && + ((kSDMMCHOST_SupportHS200 != SDMMCHOST_NOT_SUPPORT))) + { + if (kStatus_Success != MMC_SwitchToHS200(card, SDMMCHOST_SUPPORT_HS200_FREQ)) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + break; + } + case kMMC_HighSpeedTiming: + if (kStatus_Success != MMC_SwitchToHighSpeed(card)) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + break; + + default: + card->busTiming = kMMC_HighSpeedTimingNone; + } + + return kStatus_Success; +} + +static void MMC_DecodeCid(mmc_card_t *card, uint32_t *rawCid) +{ + assert(card); + assert(rawCid); + + mmc_cid_t *cid; + + cid = &(card->cid); + cid->manufacturerID = (uint8_t)((rawCid[3U] & 0xFF000000U) >> 24U); + cid->applicationID = (uint16_t)((rawCid[3U] & 0xFFFF00U) >> 8U); + + cid->productName[0U] = (uint8_t)((rawCid[3U] & 0xFFU)); + cid->productName[1U] = (uint8_t)((rawCid[2U] & 0xFF000000U) >> 24U); + cid->productName[2U] = (uint8_t)((rawCid[2U] & 0xFF0000U) >> 16U); + cid->productName[3U] = (uint8_t)((rawCid[2U] & 0xFF00U) >> 8U); + cid->productName[4U] = (uint8_t)((rawCid[2U] & 0xFFU)); + + cid->productVersion = (uint8_t)((rawCid[1U] & 0xFF000000U) >> 24U); + + cid->productSerialNumber = (uint32_t)((rawCid[1U] & 0xFFFFFFU) << 8U); + cid->productSerialNumber |= (uint32_t)((rawCid[0U] & 0xFF000000U) >> 24U); + + cid->manufacturerData = (uint16_t)((rawCid[0U] & 0xFFF00U) >> 8U); +} + +static status_t MMC_AllSendCid(mmc_card_t *card) +{ + assert(card); + assert(card->host.transfer); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + + command.index = kSDMMC_AllSendCid; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR2; + + content.command = &command; + content.data = NULL; + if (kStatus_Success == card->host.transfer(card->host.base, &content)) + { + memcpy(card->rawCid, command.response, sizeof(card->rawCid)); + MMC_DecodeCid(card, command.response); + + return kStatus_Success; + } + + return kStatus_SDMMC_TransferFailed; +} + +static status_t MMC_SendCsd(mmc_card_t *card) +{ + assert(card); + assert(card->host.transfer); + + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_TRANSFER content = {0}; + + command.index = kSDMMC_SendCsd; + command.argument = (card->relativeAddress << 16U); + command.responseType = kCARD_ResponseTypeR2; + + content.command = &command; + content.data = 0U; + if (kStatus_Success == card->host.transfer(card->host.base, &content)) + { + memcpy(card->rawCsd, command.response, sizeof(card->rawCsd)); + /* The response is from bit 127:8 in R2, corresponding to command.response[3][31:0] to + command.response[0U][31:8]. */ + MMC_DecodeCsd(card, card->rawCsd); + + return kStatus_Success; + } + + return kStatus_SDMMC_TransferFailed; +} + +static status_t MMC_CheckBlockRange(mmc_card_t *card, uint32_t startBlock, uint32_t blockCount) +{ + assert(card); + assert(blockCount); + + status_t error = kStatus_Success; + uint32_t partitionBlocks; + + switch (card->currentPartition) + { + case kMMC_AccessPartitionUserAera: + { + partitionBlocks = card->userPartitionBlocks; + break; + } + case kMMC_AccessPartitionBoot1: + case kMMC_AccessPartitionBoot2: + { + /* Boot partition 1 and partition 2 have the same partition size. */ + partitionBlocks = card->bootPartitionBlocks; + break; + } + default: + error = kStatus_InvalidArgument; + break; + } + /* Check if the block range accessed is within current partition's block boundary. */ + if ((error == kStatus_Success) && ((startBlock + blockCount) > partitionBlocks)) + { + error = kStatus_InvalidArgument; + } + + return error; +} + +static status_t MMC_CheckEraseGroupRange(mmc_card_t *card, uint32_t startGroup, uint32_t endGroup) +{ + assert(card); + + status_t error = kStatus_Success; + uint32_t partitionBlocks; + uint32_t eraseGroupBoundary; + + switch (card->currentPartition) + { + case kMMC_AccessPartitionUserAera: + { + partitionBlocks = card->userPartitionBlocks; + break; + } + case kMMC_AccessPartitionBoot1: + case kMMC_AccessPartitionBoot2: + { + /* Boot partition 1 and partition 2 have the same partition size. */ + partitionBlocks = card->bootPartitionBlocks; + break; + } + default: + error = kStatus_InvalidArgument; + break; + } + + if (error == kStatus_Success) + { + /* Check if current partition's total block count is integer multiples of the erase group size. */ + if ((partitionBlocks % card->eraseGroupBlocks) == 0U) + { + eraseGroupBoundary = (partitionBlocks / card->eraseGroupBlocks); + } + else + { + /* Card will ignore the unavailable blocks within the last erase group automatically. */ + eraseGroupBoundary = (partitionBlocks / card->eraseGroupBlocks + 1U); + } + + /* Check if the group range accessed is within current partition's erase group boundary. */ + if ((startGroup > eraseGroupBoundary) || (endGroup > eraseGroupBoundary)) + { + error = kStatus_InvalidArgument; + } + } + + return error; +} + +static status_t MMC_Read( + mmc_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockSize, uint32_t blockCount) +{ + assert(card); + assert(card->host.transfer); + assert(buffer); + assert(blockCount); + assert(blockSize); + assert(blockSize == FSL_SDMMC_DEFAULT_BLOCK_SIZE); + + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_DATA data = {0}; + SDMMCHOST_TRANSFER content = {0}; + status_t error; + + if (((card->flags & kMMC_SupportHighCapacityFlag) && (blockSize != 512U)) || (blockSize > card->blockSize) || + (blockSize > card->host.capability.maxBlockLength) || (blockSize % 4U)) + { + return kStatus_SDMMC_CardNotSupport; + } + + /* Wait for the card write process complete because of that card read process and write process use one buffer. */ + if (kStatus_Success != MMC_WaitWriteComplete(card)) + { + return kStatus_SDMMC_WaitWriteCompleteFailed; + } + + data.blockSize = blockSize; + data.blockCount = blockCount; + data.rxData = (uint32_t *)buffer; + data.enableAutoCommand12 = true; + command.index = kSDMMC_ReadMultipleBlock; + if (data.blockCount == 1U) + { + command.index = kSDMMC_ReadSingleBlock; + } + else + { + if ((!(data.enableAutoCommand12)) && (card->enablePreDefinedBlockCount)) + { + /* If enabled the pre-define count read/write feature of the card, need to set block count firstly. */ + if (kStatus_Success != MMC_SetBlockCount(card, blockCount)) + { + return kStatus_SDMMC_SetBlockCountFailed; + } + } + } + command.argument = startBlock; + if (!(card->flags & kMMC_SupportHighCapacityFlag)) + { + command.argument *= data.blockSize; + } + command.responseType = kCARD_ResponseTypeR1; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; + + content.command = &command; + content.data = &data; + + /* should check tuning error during every transfer */ + error = MMC_Transfer(card, &content, 1U); + if (kStatus_Success != error) + { + return error; + } + + /* When host's AUTO_COMMAND12 feature isn't enabled and PRE_DEFINED_COUNT command isn't enabled in multiple + blocks transmission, sends STOP_TRANSMISSION command. */ + if ((blockCount > 1U) && (!(data.enableAutoCommand12)) && (!card->enablePreDefinedBlockCount)) + { + if (kStatus_Success != MMC_StopTransmission(card)) + { + return kStatus_SDMMC_StopTransmissionFailed; + } + } + + return kStatus_Success; +} + +static status_t MMC_Write( + mmc_card_t *card, const uint8_t *buffer, uint32_t startBlock, uint32_t blockSize, uint32_t blockCount) +{ + assert(card); + assert(card->host.transfer); + assert(buffer); + assert(blockCount); + assert(blockSize); + assert(blockSize == FSL_SDMMC_DEFAULT_BLOCK_SIZE); + + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_DATA data = {0}; + SDMMCHOST_TRANSFER content = {0}; + status_t error; + + /* Check address range */ + if (((card->flags & kMMC_SupportHighCapacityFlag) && (blockSize != 512U)) || (blockSize > card->blockSize) || + (blockSize > card->host.capability.maxBlockLength) || (blockSize % 4U)) + { + return kStatus_SDMMC_CardNotSupport; + } + + /* Wait for the card's buffer to be not full to write to improve the write performance. */ + while ((GET_SDMMCHOST_STATUS(card->host.base) & CARD_DATA0_STATUS_MASK) != CARD_DATA0_NOT_BUSY) + { + } + + /* Wait for the card write process complete */ + if (kStatus_Success != MMC_WaitWriteComplete(card)) + { + return kStatus_SDMMC_WaitWriteCompleteFailed; + } + + data.blockSize = blockSize; + data.blockCount = blockCount; + data.txData = (const uint32_t *)buffer; + data.enableAutoCommand12 = true; + + command.index = kSDMMC_WriteMultipleBlock; + if (data.blockCount == 1U) + { + command.index = kSDMMC_WriteSingleBlock; + } + else + { + if ((!(data.enableAutoCommand12)) && (card->enablePreDefinedBlockCount)) + { + /* If enabled the pre-define count read/write featue of the card, need to set block count firstly */ + if (kStatus_Success != MMC_SetBlockCount(card, blockCount)) + { + return kStatus_SDMMC_SetBlockCountFailed; + } + } + } + command.argument = startBlock; + if (!(card->flags & kMMC_SupportHighCapacityFlag)) + { + command.argument *= blockSize; + } + command.responseType = kCARD_ResponseTypeR1; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; + + content.command = &command; + content.data = &data; + + /* should check tuning error during every transfer */ + error = MMC_Transfer(card, &content, 1U); + if (kStatus_Success != error) + { + return error; + } + + /* When host's AUTO_COMMAND12 feature isn't enabled and PRE_DEFINED_COUNT command isn't enabled in multiple + blocks transmission, sends STOP_TRANSMISSION command. */ + if ((blockCount > 1U) && (!(data.enableAutoCommand12)) && (!card->enablePreDefinedBlockCount)) + { + if (kStatus_Success != MMC_StopTransmission(card)) + { + return kStatus_SDMMC_StopTransmissionFailed; + } + } + + return kStatus_Success; +} + +status_t MMC_CardInit(mmc_card_t *card) +{ + assert(card); + assert((card->hostVoltageWindowVCC != kMMC_VoltageWindowNone) && + (card->hostVoltageWindowVCC != kMMC_VoltageWindow120)); + + uint32_t opcode = 0U; + + if (!card->isHostReady) + { + return kStatus_SDMMC_HostNotReady; + } + /* set DATA bus width */ + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH1BIT); + /* Set clock to 400KHz. */ + card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SDMMC_CLOCK_400KHZ); + /* get host capability first */ + GET_SDMMCHOST_CAPABILITY(card->host.base, &(card->host.capability)); + + /* Send CMD0 to reset the bus */ + if (kStatus_Success != MMC_GoIdle(card)) + { + return kStatus_SDMMC_GoIdleFailed; + } + + /* Hand-shaking with card to validata the voltage range Host first sending its expected + information.*/ + if (kStatus_Success != MMC_SendOperationCondition(card, 0U)) + { + return kStatus_SDMMC_HandShakeOperationConditionFailed; + } + + /* switch the host voltage which the card can support */ + if (kStatus_Success != MMC_SwitchVoltage(card, &opcode)) + { + return kStatus_SDMMC_HandShakeOperationConditionFailed; + } + + /* Get host's access mode. */ + if (card->host.capability.maxBlockLength >= FSL_SDMMC_DEFAULT_BLOCK_SIZE) + { + opcode |= kMMC_AccessModeSector << MMC_OCR_ACCESS_MODE_SHIFT; + } + else + { + opcode |= kMMC_AccessModeByte << MMC_OCR_ACCESS_MODE_SHIFT; + } + + if (kStatus_Success != MMC_SendOperationCondition(card, opcode)) + { + return kStatus_SDMMC_HandShakeOperationConditionFailed; + } + + /* Get card CID */ + if (kStatus_Success != MMC_AllSendCid(card)) + { + return kStatus_SDMMC_AllSendCidFailed; + } + + /* Set the card relative address */ + if (kStatus_Success != MMC_SetRelativeAddress(card)) + { + return kStatus_SDMMC_SetRelativeAddressFailed; + } + + /* Get the CSD register content */ + if (kStatus_Success != MMC_SendCsd(card)) + { + return kStatus_SDMMC_SendCsdFailed; + } + + /* Set to maximum speed in normal mode. */ + MMC_SetMaxFrequency(card); + + /* Send CMD7 with the card's relative address to place the card in transfer state. Puts current selected card in + transfer state. */ + if (kStatus_Success != MMC_SelectCard(card, true)) + { + return kStatus_SDMMC_SelectCardFailed; + } + + /* Get Extended CSD register content. */ + if (kStatus_Success != MMC_SendExtendedCsd(card, NULL, 0U)) + { + return kStatus_SDMMC_SendExtendedCsdFailed; + } + + /* set block size */ + if (kStatus_Success != MMC_SetBlockSize(card, FSL_SDMMC_DEFAULT_BLOCK_SIZE)) + { + return kStatus_SDMMC_SetCardBlockSizeFailed; + } + + /* switch to host support speed mode, then switch MMC data bus width and select power class */ + if (kStatus_Success != MMC_SelectBusTiming(card)) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + + /* switch power class */ + if (kStatus_Success != MMC_SetPowerClass(card)) + { + return kStatus_SDMMC_SetPowerClassFail; + } + + /* Set to max erase unit size */ + if (kStatus_Success != MMC_SetMaxEraseUnitSize(card)) + { + return kStatus_SDMMC_EnableHighCapacityEraseFailed; + } + + /* Set card default to access non-boot partition */ + card->currentPartition = kMMC_AccessPartitionUserAera; + + return kStatus_Success; +} + +void MMC_CardDeinit(mmc_card_t *card) +{ + assert(card); + + MMC_SelectCard(card, false); +} + +status_t MMC_HostInit(mmc_card_t *card) +{ + assert(card); + + if ((!card->isHostReady) && SDMMCHOST_Init(&(card->host), NULL) != kStatus_Success) + { + return kStatus_Fail; + } + + /* set the host status flag, after the card re-plug in, don't need init host again */ + card->isHostReady = true; + + return kStatus_Success; +} + +void MMC_HostDeinit(mmc_card_t *card) +{ + assert(card); + + SDMMCHOST_Deinit(&(card->host)); + /* should re-init host */ + card->isHostReady = false; +} + +void MMC_HostReset(SDMMCHOST_CONFIG *host) +{ + SDMMCHOST_Reset(host->base); +} + +void MMC_PowerOnCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +{ + SDMMCHOST_PowerOnCard(base, pwr); +} + +void MMC_PowerOffCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +{ + SDMMCHOST_PowerOffCard(base, pwr); +} + +status_t MMC_Init(mmc_card_t *card) +{ + assert(card); + + if (!card->isHostReady) + { + if (MMC_HostInit(card) != kStatus_Success) + { + return kStatus_SDMMC_HostNotReady; + } + } + else + { + /* reset the host */ + MMC_HostReset(&(card->host)); + } + + /*first power off card*/ + MMC_PowerOffCard(card->host.base, card->usrParam.pwr); + + /*power on card*/ + MMC_PowerOnCard(card->host.base, card->usrParam.pwr); + + return MMC_CardInit(card); +} + +void MMC_Deinit(mmc_card_t *card) +{ + assert(card); + + MMC_CardDeinit(card); + MMC_HostDeinit(card); +} + +bool MMC_CheckReadOnly(mmc_card_t *card) +{ + assert(card); + + return ((card->csd.flags & kMMC_CsdPermanentWriteProtectFlag) || + (card->csd.flags & kMMC_CsdTemporaryWriteProtectFlag)); +} + +status_t MMC_SelectPartition(mmc_card_t *card, mmc_access_partition_t partitionNumber) +{ + assert(card); + + uint8_t bootConfig; + mmc_extended_csd_config_t extendedCsdconfig; + + bootConfig = card->extendedCsd.partitionConfig; + bootConfig &= ~MMC_PARTITION_CONFIG_PARTITION_ACCESS_MASK; + bootConfig |= ((uint32_t)partitionNumber << MMC_PARTITION_CONFIG_PARTITION_ACCESS_SHIFT); + + extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; + extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexPartitionConfig; + extendedCsdconfig.ByteValue = bootConfig; + extendedCsdconfig.commandSet = kMMC_CommandSetStandard; + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) + { + return kStatus_SDMMC_ConfigureExtendedCsdFailed; + } + + /* Save current configuration. */ + card->extendedCsd.partitionConfig = bootConfig; + card->currentPartition = partitionNumber; + + return kStatus_Success; +} + +status_t MMC_ReadBlocks(mmc_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockCount) +{ + assert(card); + assert(buffer); + assert(blockCount); + + uint32_t blockCountOneTime; /* The block count can be erased in one time sending READ_BLOCKS command. */ + uint32_t blockDone; /* The blocks has been read. */ + uint32_t blockLeft; /* Left blocks to be read. */ + uint8_t *nextBuffer; + bool dataAddrAlign = true; + + blockLeft = blockCount; + blockDone = 0U; + if (kStatus_Success != MMC_CheckBlockRange(card, startBlock, blockCount)) + { + return kStatus_InvalidArgument; + } + + while (blockLeft) + { + nextBuffer = (buffer + blockDone * FSL_SDMMC_DEFAULT_BLOCK_SIZE); + if (!card->noInteralAlign && (!dataAddrAlign || (((uint32_t)nextBuffer) & (sizeof(uint32_t) - 1U)))) + { + blockLeft--; + blockCountOneTime = 1U; + memset(g_sdmmc, 0U, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + dataAddrAlign = false; + } + else + { + if (blockLeft > card->host.capability.maxBlockCount) + { + blockLeft = (blockLeft - card->host.capability.maxBlockCount); + blockCountOneTime = card->host.capability.maxBlockCount; + } + else + { + blockCountOneTime = blockLeft; + blockLeft = 0U; + } + } + + if (kStatus_Success != MMC_Read(card, dataAddrAlign ? nextBuffer : (uint8_t *)g_sdmmc, (startBlock + blockDone), + FSL_SDMMC_DEFAULT_BLOCK_SIZE, blockCountOneTime)) + { + return kStatus_SDMMC_TransferFailed; + } + + blockDone += blockCountOneTime; + + if (!card->noInteralAlign && (!dataAddrAlign)) + { + memcpy(nextBuffer, (uint8_t *)&g_sdmmc, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + } + } + + return kStatus_Success; +} + +status_t MMC_WriteBlocks(mmc_card_t *card, const uint8_t *buffer, uint32_t startBlock, uint32_t blockCount) +{ + assert(card); + assert(buffer); + assert(blockCount); + + uint32_t blockCountOneTime; + uint32_t blockLeft; + uint32_t blockDone; + const uint8_t *nextBuffer; + bool dataAddrAlign = true; + + blockLeft = blockCount; + blockDone = 0U; + + if (kStatus_Success != MMC_CheckBlockRange(card, startBlock, blockCount)) + { + return kStatus_InvalidArgument; + } + + while (blockLeft) + { + nextBuffer = (buffer + blockDone * FSL_SDMMC_DEFAULT_BLOCK_SIZE); + if (!card->noInteralAlign && (!dataAddrAlign || (((uint32_t)nextBuffer) & (sizeof(uint32_t) - 1U)))) + { + blockLeft--; + blockCountOneTime = 1U; + memcpy((uint8_t *)&g_sdmmc, nextBuffer, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + dataAddrAlign = false; + } + else + { + if (blockLeft > card->host.capability.maxBlockCount) + { + blockLeft = (blockLeft - card->host.capability.maxBlockCount); + blockCountOneTime = card->host.capability.maxBlockCount; + } + else + { + blockCountOneTime = blockLeft; + blockLeft = 0U; + } + } + + if (kStatus_Success != MMC_Write(card, dataAddrAlign ? nextBuffer : (uint8_t *)g_sdmmc, + (startBlock + blockDone), FSL_SDMMC_DEFAULT_BLOCK_SIZE, blockCountOneTime)) + { + return kStatus_SDMMC_TransferFailed; + } + + blockDone += blockCountOneTime; + if (!card->noInteralAlign) + { + memset(g_sdmmc, 0U, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + } + } + + return kStatus_Success; +} + +status_t MMC_EraseGroups(mmc_card_t *card, uint32_t startGroup, uint32_t endGroup) +{ + assert(card); + assert(card->host.transfer); + + uint32_t startGroupAddress; + uint32_t endGroupAddress; + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_TRANSFER content = {0}; + + if (kStatus_Success != MMC_CheckEraseGroupRange(card, startGroup, endGroup)) + { + return kStatus_InvalidArgument; + } + + /* Wait for the card's buffer to be not full to write to improve the write performance. */ + while ((GET_SDMMCHOST_STATUS(card->host.base) & CARD_DATA0_STATUS_MASK) != CARD_DATA0_NOT_BUSY) + { + } + + if (kStatus_Success != MMC_WaitWriteComplete(card)) + { + return kStatus_SDMMC_WaitWriteCompleteFailed; + } + + /* Calculate the start group address and end group address */ + startGroupAddress = startGroup; + endGroupAddress = endGroup; + if (card->flags & kMMC_SupportHighCapacityFlag) + { + /* The implementation of a higher than 2GB of density of memory will not be backwards compatible with the + lower densities.First of all the address argument for higher than 2GB of density of memory is changed to + be sector address (512B sectors) instead of byte address */ + startGroupAddress = (startGroupAddress * (card->eraseGroupBlocks)); + endGroupAddress = (endGroupAddress * (card->eraseGroupBlocks)); + } + else + { + /* The address unit is byte when card capacity is lower than 2GB */ + startGroupAddress = (startGroupAddress * (card->eraseGroupBlocks) * FSL_SDMMC_DEFAULT_BLOCK_SIZE); + endGroupAddress = (endGroupAddress * (card->eraseGroupBlocks) * FSL_SDMMC_DEFAULT_BLOCK_SIZE); + } + + /* Set the start erase group address */ + command.index = kMMC_EraseGroupStart; + command.argument = startGroupAddress; + command.responseType = kCARD_ResponseTypeR1; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; + + content.command = &command; + content.data = NULL; + if (kStatus_Success != MMC_Transfer(card, &content, 0U)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* Set the end erase group address */ + command.index = kMMC_EraseGroupEnd; + command.argument = endGroupAddress; + + content.command = &command; + content.data = NULL; + if (kStatus_Success != MMC_Transfer(card, &content, 0U)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* Start the erase process */ + command.index = kSDMMC_Erase; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR1b; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; + + content.command = &command; + content.data = NULL; + if (kStatus_Success != MMC_Transfer(card, &content, 0U)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t MMC_SetBootConfigWP(mmc_card_t *card, uint8_t wp) +{ + assert(card); + + mmc_extended_csd_config_t extendedCsdconfig; + extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; + extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexBootConfigWP; + extendedCsdconfig.ByteValue = wp; + extendedCsdconfig.commandSet = kMMC_CommandSetStandard; + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) + { + return kStatus_SDMMC_ConfigureExtendedCsdFailed; + } + + card->extendedCsd.bootConfigProtect = wp; + + return kStatus_Success; +} + +status_t MMC_SetBootPartitionWP(mmc_card_t *card, mmc_boot_partition_wp_t bootPartitionWP) +{ + assert(card); + + mmc_extended_csd_config_t extendedCsdconfig; + extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; + extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexBootPartitionWP; + extendedCsdconfig.ByteValue = bootPartitionWP; + extendedCsdconfig.commandSet = kMMC_CommandSetStandard; + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) + { + return kStatus_SDMMC_ConfigureExtendedCsdFailed; + } + + card->extendedCsd.bootPartitionWP = bootPartitionWP; + + return kStatus_Success; +} + +status_t MMC_SetBootConfig(mmc_card_t *card, const mmc_boot_config_t *config) +{ + assert(card); + assert(config); + + uint8_t bootParameter; + uint8_t bootBusWidth = config->bootDataBusWidth; + mmc_extended_csd_config_t extendedCsdconfig; + + if (card->extendedCsd.extendecCsdVersion <= + kMMC_ExtendedCsdRevision13) /* V4.3 or above version card support boot mode */ + { + return kStatus_SDMMC_NotSupportYet; + } + + /* Set the BOOT_CONFIG field of Extended CSD */ + bootParameter = card->extendedCsd.partitionConfig; + bootParameter &= ~(MMC_PARTITION_CONFIG_BOOT_ACK_MASK | MMC_PARTITION_CONFIG_PARTITION_ENABLE_MASK); + bootParameter |= ((config->enableBootAck ? 1U : 0U) << MMC_PARTITION_CONFIG_BOOT_ACK_SHIFT); + bootParameter |= ((uint32_t)(config->bootPartition) << MMC_PARTITION_CONFIG_PARTITION_ENABLE_SHIFT); + + extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; + extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexPartitionConfig; + extendedCsdconfig.ByteValue = bootParameter; + extendedCsdconfig.commandSet = kMMC_CommandSetStandard; + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) + { + return kStatus_SDMMC_ConfigureExtendedCsdFailed; + } + + card->extendedCsd.partitionConfig = bootParameter; + + /* data bus remapping */ + if (bootBusWidth == kMMC_DataBusWidth1bit) + { + bootBusWidth = 0U; + } + else if ((bootBusWidth == kMMC_DataBusWidth4bit) || (bootBusWidth == kMMC_DataBusWidth4bitDDR)) + { + bootBusWidth = 1U; + } + else + { + bootBusWidth = 2U; + } + + /*Set BOOT_BUS_CONDITIONS in Extended CSD */ + bootParameter = card->extendedCsd.bootDataBusConditions; + bootParameter &= ~(MMC_BOOT_BUS_CONDITION_RESET_BUS_CONDITION_MASK | MMC_BOOT_BUS_CONDITION_BUS_WIDTH_MASK | + MMC_BOOT_BUS_CONDITION_BOOT_MODE_MASK); + bootParameter |= + ((config->retainBootbusCondition ? true : false) << MMC_BOOT_BUS_CONDITION_RESET_BUS_CONDITION_SHIFT); + bootParameter |= bootBusWidth << MMC_BOOT_BUS_CONDITION_BUS_WIDTH_SHIFT; + bootParameter |= (uint32_t)(config->bootTimingMode); + + extendedCsdconfig.accessMode = kMMC_ExtendedCsdAccessModeWriteBits; + extendedCsdconfig.ByteIndex = kMMC_ExtendedCsdIndexBootBusConditions; + extendedCsdconfig.ByteValue = bootParameter; + if (kStatus_Success != MMC_SetExtendedCsdConfig(card, &extendedCsdconfig)) + { + return kStatus_SDMMC_ConfigureBootFailed; + } + + card->extendedCsd.bootDataBusConditions = bootParameter; + /* check and configure the boot config write protect */ + bootParameter = config->pwrBootConfigProtection | ((uint8_t)(config->premBootConfigProtection) << 4U); + if (bootParameter != (card->extendedCsd.bootConfigProtect)) + { + if (kStatus_Success != MMC_SetBootConfigWP(card, bootParameter)) + { + return kStatus_SDMMC_ConfigureBootFailed; + } + } + /* check and configure the boot partition write protect */ + if (card->extendedCsd.bootPartitionWP != (uint8_t)(config->bootPartitionWP)) + { + if (kStatus_Success != MMC_SetBootPartitionWP(card, config->bootPartitionWP)) + { + return kStatus_SDMMC_ConfigureBootFailed; + } + } + + return kStatus_Success; +} + +status_t MMC_StartBoot(mmc_card_t *card, + const mmc_boot_config_t *mmcConfig, + uint8_t *buffer, + SDMMCHOST_BOOT_CONFIG *hostConfig) +{ + assert(card); + assert(mmcConfig); + assert(buffer); + + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_DATA data = {0}; + uint32_t tempClock = 0U; + + if (!card->isHostReady) + { + return kStatus_Fail; + } + + /* send card active */ + SDMMCHOST_SEND_CARD_ACTIVE(card->host.base, 100U); + /* config the host */ + SDMMCHOST_SETMMCBOOTCONFIG(card->host.base, hostConfig); + /* enable MMC boot */ + SDMMCHOST_ENABLE_MMC_BOOT(card->host.base, true); + + if (mmcConfig->bootTimingMode == kMMC_BootModeSDRWithDefaultTiming) + { + /* Set clock to 400KHz. */ + tempClock = SDMMC_CLOCK_400KHZ; + } + else + { + /* Set clock to 52MHZ. */ + tempClock = MMC_CLOCK_52MHZ; + } + SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, tempClock); + + if (mmcConfig->bootTimingMode == kMMC_BootModeDDRTiming) + { + /* enable DDR mode */ + SDMMCHOST_ENABLE_DDR_MODE(card->host.base, true, 0U); + } + + /* data bus remapping */ + if (mmcConfig->bootDataBusWidth == kMMC_DataBusWidth1bit) + { + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH1BIT); + } + else if ((mmcConfig->bootDataBusWidth == kMMC_DataBusWidth4bit) || + (mmcConfig->bootDataBusWidth == kMMC_DataBusWidth4bitDDR)) + { + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH4BIT); + } + else + { + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH8BIT); + } + + if (kMMC_BootModeAlternative == (uint32_t)SDMMCHOST_GET_HOST_CONFIG_BOOT_MODE(hostConfig)) + { + /* alternative boot mode */ + command.argument = 0xFFFFFFFA; + } + + command.index = kSDMMC_GoIdleState; + + data.blockSize = SDMMCHOST_GET_HOST_CONFIG_BLOCK_SIZE(hostConfig); + data.blockCount = SDMMCHOST_GET_HOST_CONFIG_BLOCK_COUNT(hostConfig); + data.rxData = (uint32_t *)buffer; + SDMMCHOST_ENABLE_BOOT_FLAG(data); + + content.data = &data; + content.command = &command; + + /* should check tuning error during every transfer*/ + if (kStatus_Success != MMC_Transfer(card, &content, 1U)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t MMC_ReadBootData(mmc_card_t *card, uint8_t *buffer, SDMMCHOST_BOOT_CONFIG *hostConfig) +{ + assert(card); + assert(buffer); + + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_DATA data = {0}; + + /* enable MMC boot */ + SDMMCHOST_ENABLE_MMC_BOOT(card->host.base, true); + /* config the host */ + SDMMCHOST_SETMMCBOOTCONFIG(card->host.base, hostConfig); + data.blockSize = SDMMCHOST_GET_HOST_CONFIG_BLOCK_SIZE(hostConfig); + data.blockCount = SDMMCHOST_GET_HOST_CONFIG_BLOCK_COUNT(hostConfig); + data.rxData = (uint32_t *)buffer; + SDMMCHOST_ENABLE_BOOT_CONTINOUS_FLAG(data); + /* no command should be send out */ + SDMMCHOST_EMPTY_CMD_FLAG(command); + + content.data = &data; + content.command = &command; + + /* should check tuning error during every transfer*/ + if (kStatus_Success != MMC_Transfer(card, &content, 1U)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t MMC_StopBoot(mmc_card_t *card, uint32_t bootMode) +{ + assert(card); + /* Disable boot mode */ + if (kMMC_BootModeAlternative == bootMode) + { + /* Send CMD0 to reset the bus */ + if (kStatus_Success != MMC_GoIdle(card)) + { + return kStatus_SDMMC_GoIdleFailed; + } + } + /* disable MMC boot */ + SDMMCHOST_ENABLE_MMC_BOOT(card->host.base, false); + + return kStatus_Success; +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sd.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sd.c new file mode 100644 index 000000000..2fa494e4d --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sd.c @@ -0,0 +1,1982 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "fsl_sd.h" + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief Wait write process complete. + * + * @param card Card descriptor. + * @retval kStatus_Timeout Send command timeout. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_WaitWriteComplete(sd_card_t *card); + +/*! + * @brief send write success blocks. + * + * @param card Card descriptor. + * @param blocks blocks number wirte successed + * @retval kStatus_SDMMC_TransferFailed Send command failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_SendWriteSuccessBlocks(sd_card_t *card, uint32_t *blocks); + +/*! + * @brief Send SEND_APPLICATION_COMMAND command. + * + * @param card Card descriptor. + * @param relativeaddress + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_CardNotSupport Card doesn't support. + * @retval kStatus_Success Operate successfully. + */ +static status_t inline SD_SendApplicationCmd(sd_card_t *card, uint32_t relativeAddress); + +/*! + * @brief Send GO_IDLE command to set the card to be idle state. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t inline SD_GoIdle(sd_card_t *card); + +/*! + * @brief Send STOP_TRANSMISSION command after multiple blocks read/write. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_StopTransmission(sd_card_t *card); + +/*! + * @brief Send SET_BLOCK_SIZE command. + * + * @param card Card descriptor. + * @param blockSize Block size. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t inline SD_SetBlockSize(sd_card_t *card, uint32_t blockSize); + +/*! + * @brief Send GET_RCA command to get card relative address. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_SendRca(sd_card_t *card); + +/*! + * @brief Send SWITCH_FUNCTION command to switch the card function group. + * + * @param card Card descriptor. + * @param mode 0 to check function group. 1 to switch function group + * @param group Function group + * @param number Function number in the function group. + * @param status Switch function status. + * @retval kStatus_SDMMC_SetCardBlockSizeFailed Set card block size failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_SwitchFunction(sd_card_t *card, uint32_t mode, uint32_t group, uint32_t number, uint32_t *status); + +/*! + * @brief Decode raw SCR register content in the data blocks. + * + * @param card Card descriptor. + * @param rawScr Raw SCR register content. + */ +static void SD_DecodeScr(sd_card_t *card, uint32_t *rawScr); + +/*! + * @brief Send GET_SCR command. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_SendApplicationCommandFailed Send application command failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_NotSupportYet Not support yet. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_SendScr(sd_card_t *card); + +/*! + * @brief Switch the card to be high speed mode. + * + * @param card Card descriptor. + * @param group Group number. + * @param functio Function number. + * @retval kStatus_SDMMC_CardNotSupport Card not support. + * @retval kStatus_SDMMC_SwitchFailed Switch failed. + * @retval kStatus_SDMMC_NotSupportYet Not support yet. + * @retval kStatus_Fail Switch failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_SelectFunction(sd_card_t *card, uint32_t group, uint32_t function); + +/*! + * @brief Send SET_DATA_WIDTH command to set SD bus width. + * + * @param card Card descriptor. + * @param width Data bus width. + * @retval kStatus_SDMMC_SendApplicationCommandFailed Send application command failed. + * @retval kStatus_InvalidArgument Invalid argument. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_SetDataBusWidth(sd_card_t *card, sd_data_bus_width_t width); + +/*! + * @brief Decode raw CSD register content in the data blocks. + * + * @param card Card descriptor. + * @param rawCsd Raw CSD register content. + */ +static void SD_DecodeCsd(sd_card_t *card, uint32_t *rawCsd); + +/*! + * @brief Send SEND_CSD command to get CSD register content from Card. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_SendCsd(sd_card_t *card); + +/*! + * @brief Decode raw CID register content in the data blocks. + * + * @param rawCid raw CID register content. + * @param card Card descriptor. + */ +static void SD_DecodeCid(sd_card_t *card, uint32_t *rawCid); + +/*! + * @brief Send GET_CID command to get CID from card. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_AllSendCid(sd_card_t *card); + +/*! + * @brief Send SEND_OPERATION_CONDITION command. + * + * This function sends host capacity support information and asks the accessed card to send its operating condition + * register content. + * + * @param card Card descriptor. + * @param argument The argument of the send operation condition ncomamnd. + * @retval kStatus_SDMMC_SendApplicationCommandFailed Send application command failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Timeout Timeout. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_ApplicationSendOperationCondition(sd_card_t *card, uint32_t argument); + +/*! + * @brief Send GET_INTERFACE_CONDITION command to get card interface condition. + * + * This function checks card interface condition, which includes host supply voltage information and asks the card + * whether card supports the specified host voltage. + * + * @param card Card descriptor. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_CardNotSupport Card doesn't support. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_SendInterfaceCondition(sd_card_t *card); + +/*! + * @brief Send switch voltage command + * switch card voltage to 1.8v + * + * @param card Card descriptor. + */ +static status_t SD_SwitchVoltage(sd_card_t *card); + +/*! + * @brief select bus timing + * select card timing + * @param card Card descriptor. + */ +static status_t SD_SelectBusTiming(sd_card_t *card); + +/*! + * @brief Decode sd 512 bit status + * @param card Card descriptor. + * @param 512 bits satus raw data. + */ +static void SD_DecodeStatus(sd_card_t *card, uint32_t *src); + +/*! + * @brief Read data from specific SD card. + * + * @param card Card descriptor. + * @param buffer Buffer to save data blocks read. + * @param startBlock Card start block number to be read. + * @param blockSize Block size. + * @param blockCount Block count. + * @retval kStatus_SDMMC_CardNotSupport Card doesn't support. + * @retval kStatus_SDMMC_WaitWriteCompleteFailed Wait write complete failed. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_StopTransmissionFailed Stop transmission failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_Read(sd_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockSize, uint32_t blockCount); + +/*! + * @brief Write data to specific card + * + * @param card Card descriptor. + * @param buffer Buffer to be sent. + * @param startBlock Card start block number to be written. + * @param blockSize Block size. + * @param blockCount Block count. + * @param blockWritten successfully write blocks + * @retval kStatus_SDMMC_CardNotSupport Card doesn't support. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_SDMMC_StopTransmissionFailed Stop transmission failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_Write(sd_card_t *card, + const uint8_t *buffer, + uint32_t startBlock, + uint32_t blockSize, + uint32_t blockCount, + uint32_t *blockWritten); + +/*! + * @brief Erase data for the given block range. + * + * @param card Card descriptor. + * @param startBlock Card start block number to be erased. + * @param blockCount The block count to be erased. + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t SD_Erase(sd_card_t *card, uint32_t startBlock, uint32_t blockCount); + +/*! + * @brief card transfer function. + * + * @param card Card descriptor. + * @param content Transfer content. + * @param retry Retry times + * @retval kStatus_SDMMC_TransferFailed Transfer failed. + * @retval kStatus_Success Operate successfully. + * @retval kStatus_SDMMC_TuningFail tuning fail + */ +static status_t SD_Transfer(sd_card_t *card, SDMMCHOST_TRANSFER *content, uint32_t retry); + +/*! + * @brief card execute tuning function. + * + * @param card Card descriptor. + * @retval kStatus_Success Operate successfully. + * @retval kStatus_SDMMC_TuningFail tuning fail. + * @retval kStatus_SDMMC_TransferFailed transfer fail + */ +static status_t inline SD_ExecuteTuning(sd_card_t *card); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/* g_sdmmc statement */ +extern uint32_t g_sdmmc[SDK_SIZEALIGN(SDMMC_GLOBAL_BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)]; +static uint32_t s_sdAuSizeMap[] = {0, + 16 * 1024, + 32 * 1024, + 64 * 1024, + 128 * 1024, + 256 * 1024, + 512 * 1024, + 1024 * 1024, + 2 * 1024 * 1024, + 4 * 1024 * 1024, + 8 * 1024 * 1024, + 12 * 1024 * 1024, + 16 * 1024 * 1024, + 24 * 1024 * 1024, + 32 * 1024 * 1024, + 64 * 1024 * 1024}; +/******************************************************************************* + * Code + ******************************************************************************/ +static status_t inline SD_SendApplicationCmd(sd_card_t *card, uint32_t relativeAddress) +{ + assert(card); + + return SDMMC_SendApplicationCommand(card->host.base, card->host.transfer, relativeAddress); +} + +static status_t inline SD_GoIdle(sd_card_t *card) +{ + assert(card); + + return SDMMC_GoIdle(card->host.base, card->host.transfer); +} + +static status_t inline SD_SetBlockSize(sd_card_t *card, uint32_t blockSize) +{ + assert(card); + + return SDMMC_SetBlockSize(card->host.base, card->host.transfer, blockSize); +} + +static status_t inline SD_ExecuteTuning(sd_card_t *card) +{ + assert(card); + + return SDMMC_ExecuteTuning(card->host.base, card->host.transfer, kSD_SendTuningBlock, 64U); +} + +static status_t SD_SwitchVoltage(sd_card_t *card) +{ + assert(card); + + if ((card->usrParam.cardVoltage != NULL) && (card->usrParam.cardVoltage->cardSignalLine1V8 != NULL)) + { + return SDMMC_SwitchToVoltage(card->host.base, card->host.transfer, + card->usrParam.cardVoltage->cardSignalLine1V8); + } + + return SDMMC_SwitchToVoltage(card->host.base, card->host.transfer, NULL); +} + +static status_t SD_StopTransmission(sd_card_t *card) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + status_t error = kStatus_Success; + + command.index = kSDMMC_StopTransmission; + command.argument = 0U; + command.type = kCARD_CommandTypeAbort; + command.responseType = kCARD_ResponseTypeR1b; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; + + content.command = &command; + content.data = 0U; + error = card->host.transfer(card->host.base, &content); + if (kStatus_Success != error) + { + SDMMC_LOG("\r\nError: send CMD12 failed with host error %d, reponse %x\r\n", error, command.response[0U]); + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +static status_t SD_Transfer(sd_card_t *card, SDMMCHOST_TRANSFER *content, uint32_t retry) +{ + assert(card->host.transfer); + assert(content); + status_t error; + + do + { + error = card->host.transfer(card->host.base, content); +#if SDMMC_ENABLE_SOFTWARE_TUNING + if (((error == SDMMCHOST_RETUNING_REQUEST) || (error == SDMMCHOST_TUNING_ERROR)) && + (card->currentTiming == kSD_TimingSDR104Mode)) + { + /* tuning error need reset tuning circuit */ + if (error == SDMMCHOST_TUNING_ERROR) + { + SDMMCHOST_RESET_TUNING(card->host.base, 100U); + } + + /* execute re-tuning */ + if (SD_ExecuteTuning(card) != kStatus_Success) + { + error = kStatus_SDMMC_TuningFail; + break; + } + else + { + continue; + } + } + else +#endif + if (error != kStatus_Success) + { + /* if transfer data failed, send cmd12 to abort current transfer */ + if (content->data) + { + SD_StopTransmission(card); + } + } + + if (retry != 0U) + { + retry--; + } + else + { + break; + } + + } while (error != kStatus_Success); + + return error; +} + +static status_t SD_WaitWriteComplete(sd_card_t *card) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + status_t error = kStatus_Success; + + command.index = kSDMMC_SendStatus; + command.argument = card->relativeAddress << 16U; + command.responseType = kCARD_ResponseTypeR1; + + do + { + content.command = &command; + content.data = 0U; + error = SD_Transfer(card, &content, 2U); + if (kStatus_Success != error) + { + SDMMC_LOG("\r\nError: send CMD13 failed with host error %d, response %x", error, command.response[0U]); + break; + } + + if ((command.response[0U] & SDMMC_MASK(kSDMMC_R1ReadyForDataFlag)) && + (SDMMC_R1_CURRENT_STATE(command.response[0U]) != kSDMMC_R1StateProgram)) + { + break; + } + } while (true); + + return error; +} + +static status_t SD_SendWriteSuccessBlocks(sd_card_t *card, uint32_t *blocks) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_DATA data = {0}; + status_t error = kStatus_Success; + + memset(g_sdmmc, 0U, sizeof(g_sdmmc)); + + /* Wait for the card write process complete because of that card read process and write process use one buffer. */ + if (kStatus_Success != SD_WaitWriteComplete(card)) + { + return kStatus_SDMMC_WaitWriteCompleteFailed; + } + + if (kStatus_Success != SD_SendApplicationCmd(card, card->relativeAddress)) + { + return kStatus_SDMMC_SendApplicationCommandFailed; + } + + command.index = kSD_ApplicationSendNumberWriteBlocks; + command.responseType = kCARD_ResponseTypeR1; + + data.blockSize = 4U; + data.blockCount = 1U; + data.rxData = &g_sdmmc[0]; + + content.command = &command; + content.data = &data; + error = card->host.transfer(card->host.base, &content); + if ((kStatus_Success != error) || ((command.response[0U]) & SDMMC_R1_ALL_ERROR_FLAG)) + { + SDMMC_LOG("\r\nError: send ACMD13 failed with host error %d, response %x", error, command.response[0U]); + } + else + { + *blocks = SWAP_WORD_BYTE_SEQUENCE(g_sdmmc[0]); + } + + return error; +} + +static status_t SD_SendRca(sd_card_t *card) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + status_t error = kStatus_Success; + + command.index = kSD_SendRelativeAddress; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR6; + + content.command = &command; + content.data = NULL; + + error = card->host.transfer(card->host.base, &content); + if (kStatus_Success == error) + { + card->relativeAddress = (command.response[0U] >> 16U); + } + else + { + SDMMC_LOG("\r\nError: send CMD3 failed with host error %d, response %x", error, command.response[0U]); + } + + return error; +} + +static status_t SD_SwitchFunction(sd_card_t *card, uint32_t mode, uint32_t group, uint32_t number, uint32_t *status) +{ + assert(card); + assert(status); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_DATA data = {0}; + status_t error = kStatus_Success; + + command.index = kSD_Switch; + command.argument = (mode << 31U | 0x00FFFFFFU); + command.argument &= ~((uint32_t)(0xFU) << (group * 4U)); + command.argument |= (number << (group * 4U)); + command.responseType = kCARD_ResponseTypeR1; + + data.blockSize = 64U; + data.blockCount = 1U; + data.rxData = status; + + content.command = &command; + content.data = &data; + error = card->host.transfer(card->host.base, &content); + if ((kStatus_Success != error) || ((command.response[0U]) & SDMMC_R1_ALL_ERROR_FLAG)) + { + SDMMC_LOG("\r\n\r\nError: send CMD6 failed with host error %d, response %x", error, command.response[0U]); + } + + return error; +} + +static void SD_DecodeScr(sd_card_t *card, uint32_t *rawScr) +{ + assert(card); + assert(rawScr); + + sd_scr_t *scr; + + scr = &(card->scr); + scr->scrStructure = (uint8_t)((rawScr[0U] & 0xF0000000U) >> 28U); + scr->sdSpecification = (uint8_t)((rawScr[0U] & 0xF000000U) >> 24U); + if ((uint8_t)((rawScr[0U] & 0x800000U) >> 23U)) + { + scr->flags |= kSD_ScrDataStatusAfterErase; + } + scr->sdSecurity = (uint8_t)((rawScr[0U] & 0x700000U) >> 20U); + scr->sdBusWidths = (uint8_t)((rawScr[0U] & 0xF0000U) >> 16U); + if ((uint8_t)((rawScr[0U] & 0x8000U) >> 15U)) + { + scr->flags |= kSD_ScrSdSpecification3; + } + scr->extendedSecurity = (uint8_t)((rawScr[0U] & 0x7800U) >> 10U); + scr->commandSupport = (uint8_t)(rawScr[0U] & 0x3U); + scr->reservedForManufacturer = rawScr[1U]; + /* Get specification version. */ + switch (scr->sdSpecification) + { + case 0U: + card->version = kSD_SpecificationVersion1_0; + break; + case 1U: + card->version = kSD_SpecificationVersion1_1; + break; + case 2U: + card->version = kSD_SpecificationVersion2_0; + if (card->scr.flags & kSD_ScrSdSpecification3) + { + card->version = kSD_SpecificationVersion3_0; + } + break; + default: + break; + } + if (card->scr.sdBusWidths & 0x4U) + { + card->flags |= kSD_Support4BitWidthFlag; + } + /* speed class control cmd */ + if (card->scr.commandSupport & 0x01U) + { + card->flags |= kSD_SupportSpeedClassControlCmd; + } + /* set block count cmd */ + if (card->scr.commandSupport & 0x02U) + { + card->flags |= kSD_SupportSetBlockCountCmd; + } +} + +static status_t SD_SendScr(sd_card_t *card) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_DATA data = {0}; + uint32_t *rawScr = g_sdmmc; + status_t error = kStatus_Success; + + /* memset the global buffer */ + memset(g_sdmmc, 0U, sizeof(g_sdmmc)); + + if (kStatus_Success != SD_SendApplicationCmd(card, card->relativeAddress)) + { + return kStatus_SDMMC_SendApplicationCommandFailed; + } + + command.index = kSD_ApplicationSendScr; + command.responseType = kCARD_ResponseTypeR1; + command.argument = 0U; + + data.blockSize = 8U; + data.blockCount = 1U; + data.rxData = rawScr; + + content.data = &data; + content.command = &command; + error = card->host.transfer(card->host.base, &content); + if ((kStatus_Success != error) || ((command.response[0U]) & SDMMC_R1_ALL_ERROR_FLAG)) + { + SDMMC_LOG("\r\nError: send ACMD51 failed with host error %d, response %x", error, command.response[0U]); + } + else + { + /* SCR register data byte sequence from card is big endian(MSB first). */ + switch (card->host.config.endianMode) + { + case kSDMMCHOST_EndianModeLittle: + /* In little endian mode, SD bus byte transferred first is the byte stored in lowest byte position in a + word which will cause 4 byte's sequence in a word is not consistent with their original sequence from + card. So the sequence of 4 bytes received in a word should be converted. */ + rawScr[0U] = SWAP_WORD_BYTE_SEQUENCE(rawScr[0U]); + rawScr[1U] = SWAP_WORD_BYTE_SEQUENCE(rawScr[1U]); + break; + case kSDMMCHOST_EndianModeBig: + break; /* Doesn't need to switch byte sequence when decodes bytes as big endian sequence. */ + case kSDMMCHOST_EndianModeHalfWordBig: + rawScr[0U] = SWAP_HALF_WROD_BYTE_SEQUENCE(rawScr[0U]); + rawScr[1U] = SWAP_HALF_WROD_BYTE_SEQUENCE(rawScr[1U]); + break; + default: + return kStatus_SDMMC_NotSupportYet; + } + memcpy(card->rawScr, rawScr, sizeof(card->rawScr)); + /* decode scr */ + SD_DecodeScr(card, rawScr); + } + + return error; +} + +static status_t SD_SelectFunction(sd_card_t *card, uint32_t group, uint32_t function) +{ + assert(card); + + uint32_t *functionStatus = g_sdmmc; + uint16_t functionGroupInfo[6U] = {0}; + uint32_t currentFunctionStatus = 0U; + + /* memset the global buffer */ + memset(g_sdmmc, 0, sizeof(g_sdmmc)); + + /* check if card support CMD6 */ + if ((card->version <= kSD_SpecificationVersion1_0) || (!(card->csd.cardCommandClass & kSDMMC_CommandClassSwitch))) + { + SDMMC_LOG("\r\nError: current card not support CMD6"); + return kStatus_SDMMC_NotSupportYet; + } + + /* Check if card support high speed mode. */ + if (kStatus_Success != SD_SwitchFunction(card, kSD_SwitchCheck, group, function, functionStatus)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* Switch function status byte sequence from card is big endian(MSB first). */ + switch (card->host.config.endianMode) + { + case kSDMMCHOST_EndianModeLittle: + /* In little endian mode, SD bus byte transferred first is the byte stored in lowest byte position in + a word which will cause 4 byte's sequence in a word is not consistent with their original sequence from + card. So the sequence of 4 bytes received in a word should be converted. */ + functionStatus[0U] = SWAP_WORD_BYTE_SEQUENCE(functionStatus[0U]); + functionStatus[1U] = SWAP_WORD_BYTE_SEQUENCE(functionStatus[1U]); + functionStatus[2U] = SWAP_WORD_BYTE_SEQUENCE(functionStatus[2U]); + functionStatus[3U] = SWAP_WORD_BYTE_SEQUENCE(functionStatus[3U]); + functionStatus[4U] = SWAP_WORD_BYTE_SEQUENCE(functionStatus[4U]); + break; + case kSDMMCHOST_EndianModeBig: + break; /* Doesn't need to switch byte sequence when decodes bytes as big endian sequence. */ + case kSDMMCHOST_EndianModeHalfWordBig: + functionStatus[0U] = SWAP_HALF_WROD_BYTE_SEQUENCE(functionStatus[0U]); + functionStatus[1U] = SWAP_HALF_WROD_BYTE_SEQUENCE(functionStatus[1U]); + functionStatus[2U] = SWAP_HALF_WROD_BYTE_SEQUENCE(functionStatus[2U]); + functionStatus[3U] = SWAP_HALF_WROD_BYTE_SEQUENCE(functionStatus[3U]); + functionStatus[4U] = SWAP_HALF_WROD_BYTE_SEQUENCE(functionStatus[4U]); + break; + default: + return kStatus_SDMMC_NotSupportYet; + } + /* -functionStatus[0U]---bit511~bit480; + -functionStatus[1U]---bit479~bit448; + -functionStatus[2U]---bit447~bit416; + -functionStatus[3U]---bit415~bit384; + -functionStatus[4U]---bit383~bit352; + According to the "switch function status[bits 511~0]" return by switch command in mode "check function": + -Check if function 1(high speed) in function group 1 is supported by checking if bit 401 is set; + -check if function 1 is ready and can be switched by checking if bits 379~376 equal value 1; + */ + functionGroupInfo[5U] = (uint16_t)functionStatus[0U]; + functionGroupInfo[4U] = (uint16_t)(functionStatus[1U] >> 16U); + functionGroupInfo[3U] = (uint16_t)(functionStatus[1U]); + functionGroupInfo[2U] = (uint16_t)(functionStatus[2U] >> 16U); + functionGroupInfo[1U] = (uint16_t)(functionStatus[2U]); + functionGroupInfo[0U] = (uint16_t)(functionStatus[3U] >> 16U); + currentFunctionStatus = ((functionStatus[3U] & 0xFFU) << 8U) | (functionStatus[4U] >> 24U); + + /* check if function is support */ + if (((functionGroupInfo[group] & (1 << function)) == 0U) || + ((currentFunctionStatus >> (group * 4U)) & 0xFU) != function) + { + SDMMC_LOG("\r\nError: current card not support function %d", function); + return kStatus_SDMMC_NotSupportYet; + } + + /* Switch to high speed mode. */ + if (kStatus_Success != SD_SwitchFunction(card, kSD_SwitchSet, group, function, functionStatus)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* Switch function status byte sequence from card is big endian(MSB first). */ + switch (card->host.config.endianMode) + { + case kSDMMCHOST_EndianModeLittle: + /* In little endian mode is little endian, SD bus byte transferred first is the byte stored in lowest byte + position in a word which will cause 4 byte's sequence in a word is not consistent with their original + sequence from card. So the sequence of 4 bytes received in a word should be converted. */ + functionStatus[3U] = SWAP_WORD_BYTE_SEQUENCE(functionStatus[3U]); + functionStatus[4U] = SWAP_WORD_BYTE_SEQUENCE(functionStatus[4U]); + break; + case kSDMMCHOST_EndianModeBig: + break; /* Doesn't need to switch byte sequence when decodes bytes as big endian sequence. */ + case kSDMMCHOST_EndianModeHalfWordBig: + functionStatus[3U] = SWAP_HALF_WROD_BYTE_SEQUENCE(functionStatus[3U]); + functionStatus[4U] = SWAP_HALF_WROD_BYTE_SEQUENCE(functionStatus[4U]); + break; + default: + return kStatus_SDMMC_NotSupportYet; + } + /* 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; + */ + currentFunctionStatus = ((functionStatus[3U] & 0xFFU) << 8U) | (functionStatus[4U] >> 24U); + + if (((currentFunctionStatus >> (group * 4U)) & 0xFU) != function) + { + SDMMC_LOG("\r\nError: switch to function %d failed", function); + return kStatus_SDMMC_SwitchFailed; + } + + return kStatus_Success; +} + +static status_t SD_SetDataBusWidth(sd_card_t *card, sd_data_bus_width_t width) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + status_t error = kStatus_Success; + + if (kStatus_Success != SD_SendApplicationCmd(card, card->relativeAddress)) + { + return kStatus_SDMMC_SendApplicationCommandFailed; + } + + command.index = kSD_ApplicationSetBusWdith; + command.responseType = kCARD_ResponseTypeR1; + switch (width) + { + case kSD_DataBusWidth1Bit: + command.argument = 0U; + break; + case kSD_DataBusWidth4Bit: + command.argument = 2U; + break; + default: + return kStatus_InvalidArgument; + } + + content.command = &command; + content.data = NULL; + error = card->host.transfer(card->host.base, &content); + if ((kStatus_Success != error) || ((command.response[0U]) & SDMMC_R1_ALL_ERROR_FLAG)) + { + SDMMC_LOG("\r\nError: send ACMD6 failed with host error %d, response %x", error, command.response[0U]); + } + + return error; +} + +static void SD_DecodeCsd(sd_card_t *card, uint32_t *rawCsd) +{ + assert(card); + assert(rawCsd); + + sd_csd_t *csd; + + csd = &(card->csd); + csd->csdStructure = (uint8_t)((rawCsd[3U] & 0xC0000000U) >> 30U); + csd->dataReadAccessTime1 = (uint8_t)((rawCsd[3U] & 0xFF0000U) >> 16U); + csd->dataReadAccessTime2 = (uint8_t)((rawCsd[3U] & 0xFF00U) >> 8U); + csd->transferSpeed = (uint8_t)(rawCsd[3U] & 0xFFU); + csd->cardCommandClass = (uint16_t)((rawCsd[2U] & 0xFFF00000U) >> 20U); + csd->readBlockLength = (uint8_t)((rawCsd[2U] & 0xF0000U) >> 16U); + if (rawCsd[2U] & 0x8000U) + { + csd->flags |= kSD_CsdReadBlockPartialFlag; + } + if (rawCsd[2U] & 0x4000U) + { + csd->flags |= kSD_CsdReadBlockPartialFlag; + } + if (rawCsd[2U] & 0x2000U) + { + csd->flags |= kSD_CsdReadBlockMisalignFlag; + } + if (rawCsd[2U] & 0x1000U) + { + csd->flags |= kSD_CsdDsrImplementedFlag; + } + switch (csd->csdStructure) + { + case 0: + csd->deviceSize = (uint32_t)((rawCsd[2U] & 0x3FFU) << 2U); + csd->deviceSize |= (uint32_t)((rawCsd[1U] & 0xC0000000U) >> 30U); + csd->readCurrentVddMin = (uint8_t)((rawCsd[1U] & 0x38000000U) >> 27U); + csd->readCurrentVddMax = (uint8_t)((rawCsd[1U] & 0x7000000U) >> 24U); + csd->writeCurrentVddMin = (uint8_t)((rawCsd[1U] & 0xE00000U) >> 20U); + csd->writeCurrentVddMax = (uint8_t)((rawCsd[1U] & 0x1C0000U) >> 18U); + csd->deviceSizeMultiplier = (uint8_t)((rawCsd[1U] & 0x38000U) >> 15U); + + /* Get card total block count and block size. */ + card->blockCount = ((csd->deviceSize + 1U) << (csd->deviceSizeMultiplier + 2U)); + card->blockSize = (1U << (csd->readBlockLength)); + if (card->blockSize != FSL_SDMMC_DEFAULT_BLOCK_SIZE) + { + card->blockCount = (card->blockCount * card->blockSize); + card->blockSize = FSL_SDMMC_DEFAULT_BLOCK_SIZE; + card->blockCount = (card->blockCount / card->blockSize); + } + break; + case 1: + card->blockSize = FSL_SDMMC_DEFAULT_BLOCK_SIZE; + + csd->deviceSize = (uint32_t)((rawCsd[2U] & 0x3FU) << 16U); + csd->deviceSize |= (uint32_t)((rawCsd[1U] & 0xFFFF0000U) >> 16U); + if (csd->deviceSize >= 0xFFFFU) + { + card->flags |= kSD_SupportSdxcFlag; + } + + card->blockCount = ((csd->deviceSize + 1U) * 1024U); + break; + default: + break; + } + if ((uint8_t)((rawCsd[1U] & 0x4000U) >> 14U)) + { + csd->flags |= kSD_CsdEraseBlockEnabledFlag; + } + csd->eraseSectorSize = (uint8_t)((rawCsd[1U] & 0x3F80U) >> 7U); + csd->writeProtectGroupSize = (uint8_t)(rawCsd[1U] & 0x7FU); + if ((uint8_t)(rawCsd[0U] & 0x80000000U)) + { + csd->flags |= kSD_CsdWriteProtectGroupEnabledFlag; + } + csd->writeSpeedFactor = (uint8_t)((rawCsd[0U] & 0x1C000000U) >> 26U); + csd->writeBlockLength = (uint8_t)((rawCsd[0U] & 0x3C00000U) >> 22U); + if ((uint8_t)((rawCsd[0U] & 0x200000U) >> 21U)) + { + csd->flags |= kSD_CsdWriteBlockPartialFlag; + } + if ((uint8_t)((rawCsd[0U] & 0x8000U) >> 15U)) + { + csd->flags |= kSD_CsdFileFormatGroupFlag; + } + if ((uint8_t)((rawCsd[0U] & 0x4000U) >> 14U)) + { + csd->flags |= kSD_CsdCopyFlag; + } + if ((uint8_t)((rawCsd[0U] & 0x2000U) >> 13U)) + { + csd->flags |= kSD_CsdPermanentWriteProtectFlag; + } + if ((uint8_t)((rawCsd[0U] & 0x1000U) >> 12U)) + { + csd->flags |= kSD_CsdTemporaryWriteProtectFlag; + } + csd->fileFormat = (uint8_t)((rawCsd[0U] & 0xC00U) >> 10U); +} + +static status_t SD_SendCsd(sd_card_t *card) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + status_t error = kStatus_Success; + + command.index = kSDMMC_SendCsd; + command.argument = (card->relativeAddress << 16U); + command.responseType = kCARD_ResponseTypeR2; + + content.command = &command; + content.data = NULL; + error = card->host.transfer(card->host.base, &content); + if (kStatus_Success == error) + { + memcpy(card->rawCsd, command.response, sizeof(card->rawCsd)); + /* The response is from bit 127:8 in R2, corrisponding to command.response[3U]:command.response[0U][31U:8]. */ + SD_DecodeCsd(card, command.response); + } + else + { + error = kStatus_SDMMC_TransferFailed; + SDMMC_LOG("\r\nError: send CMD9(get csd) failed with host error %d, response %x", error, command.response[0U]); + } + + return error; +} + +static void SD_DecodeCid(sd_card_t *card, uint32_t *rawCid) +{ + assert(card); + assert(rawCid); + + sd_cid_t *cid; + + cid = &(card->cid); + cid->manufacturerID = (uint8_t)((rawCid[3U] & 0xFF000000U) >> 24U); + cid->applicationID = (uint16_t)((rawCid[3U] & 0xFFFF00U) >> 8U); + + cid->productName[0U] = (uint8_t)((rawCid[3U] & 0xFFU)); + cid->productName[1U] = (uint8_t)((rawCid[2U] & 0xFF000000U) >> 24U); + cid->productName[2U] = (uint8_t)((rawCid[2U] & 0xFF0000U) >> 16U); + cid->productName[3U] = (uint8_t)((rawCid[2U] & 0xFF00U) >> 8U); + cid->productName[4U] = (uint8_t)((rawCid[2U] & 0xFFU)); + + cid->productVersion = (uint8_t)((rawCid[1U] & 0xFF000000U) >> 24U); + + cid->productSerialNumber = (uint32_t)((rawCid[1U] & 0xFFFFFFU) << 8U); + cid->productSerialNumber |= (uint32_t)((rawCid[0U] & 0xFF000000U) >> 24U); + + cid->manufacturerData = (uint16_t)((rawCid[0U] & 0xFFF00U) >> 8U); +} + +static status_t SD_AllSendCid(sd_card_t *card) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + + command.index = kSDMMC_AllSendCid; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR2; + + content.command = &command; + content.data = NULL; + if (kStatus_Success == card->host.transfer(card->host.base, &content)) + { + memcpy(card->rawCid, command.response, sizeof(card->rawCid)); + SD_DecodeCid(card, command.response); + + return kStatus_Success; + } + + return kStatus_SDMMC_TransferFailed; +} + +static status_t SD_ApplicationSendOperationCondition(sd_card_t *card, uint32_t argument) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + status_t error = kStatus_Fail; + uint32_t i = FSL_SDMMC_MAX_VOLTAGE_RETRIES; + + command.index = kSD_ApplicationSendOperationCondition; + command.argument = argument; + command.responseType = kCARD_ResponseTypeR3; + + while (i--) + { + if (kStatus_Success != SD_SendApplicationCmd(card, 0U)) + { + continue; + } + + content.command = &command; + content.data = NULL; + error = card->host.transfer(card->host.base, &content); + if (kStatus_Success != error) + { + SDMMC_LOG("\r\nError: send ACMD41 failed with host error %d, response %x", error, command.response[0U]); + return kStatus_SDMMC_TransferFailed; + } + + /* Wait until card exit busy state. */ + if (command.response[0U] & SDMMC_MASK(kSD_OcrPowerUpBusyFlag)) + { + /* high capacity check */ + if (command.response[0U] & SDMMC_MASK(kSD_OcrCardCapacitySupportFlag)) + { + card->flags |= kSD_SupportHighCapacityFlag; + } + /* 1.8V support */ + if (command.response[0U] & SDMMC_MASK(kSD_OcrSwitch18AcceptFlag)) + { + card->flags |= kSD_SupportVoltage180v; + } + card->ocr = command.response[0U]; + + return kStatus_Success; + } + } + + SDMMC_LOG("\r\nError: send ACMD41 timeout"); + + return error; +} + +static status_t SD_SendInterfaceCondition(sd_card_t *card) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + uint32_t i = FSL_SDMMC_MAX_CMD_RETRIES; + status_t error = kStatus_Success; + + command.index = kSD_SendInterfaceCondition; + command.argument = 0x1AAU; + command.responseType = kCARD_ResponseTypeR7; + + content.command = &command; + content.data = NULL; + do + { + error = card->host.transfer(card->host.base, &content); + if (kStatus_Success != error) + { + SDMMC_LOG("\r\nError: send CMD8 failed with host error %d, response %x", error, command.response[0U]); + } + else + { + if ((command.response[0U] & 0xFFU) != 0xAAU) + { + error = kStatus_SDMMC_CardNotSupport; + SDMMC_LOG("\r\nError: card not support CMD8"); + } + else + { + error = kStatus_Success; + } + } + } while (--i && (error != kStatus_Success)); + + return error; +} + +static status_t SD_SelectBusTiming(sd_card_t *card) +{ + assert(card); + + status_t error = kStatus_SDMMC_SwitchBusTimingFailed; + + if (card->operationVoltage != kCARD_OperationVoltage180V) + { + /* Switch the card to high speed mode */ + if (card->host.capability.flags & kSDMMCHOST_SupportHighSpeed) + { + /* group 1, function 1 ->high speed mode*/ + error = SD_SelectFunction(card, kSD_GroupTimingMode, kSD_FunctionSDR25HighSpeed); + /* 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 == kStatus_Success) + { + card->currentTiming = kSD_TimingSDR25HighSpeedMode; + card->busClock_Hz = + SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SD_CLOCK_50MHZ); + } + else if (error == kStatus_SDMMC_NotSupportYet) + { + /* if not support high speed, keep the card work at default mode */ + SDMMC_LOG("\r\nNote: High speed mode is not supported by card"); + return kStatus_Success; + } + } + else + { + /* if not support high speed, keep the card work at default mode */ + return kStatus_Success; + } + } + /* card is in UHS_I mode */ + else if ((kSDMMCHOST_SupportSDR104 != SDMMCHOST_NOT_SUPPORT) || + (kSDMMCHOST_SupportSDR50 != SDMMCHOST_NOT_SUPPORT) || (kSDMMCHOST_SupportDDR50 != SDMMCHOST_NOT_SUPPORT)) + { + switch (card->currentTiming) + { + /* if not select timing mode, sdmmc will handle it automatically*/ + case kSD_TimingSDR12DefaultMode: + case kSD_TimingSDR104Mode: + error = SD_SelectFunction(card, kSD_GroupTimingMode, kSD_FunctionSDR104); + if (error == kStatus_Success) + { + card->currentTiming = kSD_TimingSDR104Mode; + card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, + SDMMCHOST_SUPPORT_SDR104_FREQ); + break; + } + SDMMC_LOG("\r\nNote: SDR104 mode is not supported by card"); + + case kSD_TimingDDR50Mode: + error = SD_SelectFunction(card, kSD_GroupTimingMode, kSD_FunctionDDR50); + if (error == kStatus_Success) + { + card->currentTiming = kSD_TimingDDR50Mode; + card->busClock_Hz = + SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SD_CLOCK_50MHZ); + SDMMCHOST_ENABLE_DDR_MODE(card->host.base, true, 0U); + break; + } + SDMMC_LOG("\r\nNote: DDR50 mode is not supported by card"); + + case kSD_TimingSDR50Mode: + error = SD_SelectFunction(card, kSD_GroupTimingMode, kSD_FunctionSDR50); + if (error == kStatus_Success) + { + card->currentTiming = kSD_TimingSDR50Mode; + card->busClock_Hz = + SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SD_CLOCK_100MHZ); + break; + } + SDMMC_LOG("\r\nNote: SDR50 mode is not supported by card"); + + case kSD_TimingSDR25HighSpeedMode: + error = SD_SelectFunction(card, kSD_GroupTimingMode, kSD_FunctionSDR25HighSpeed); + if (error == kStatus_Success) + { + card->currentTiming = kSD_TimingSDR25HighSpeedMode; + card->busClock_Hz = + SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SD_CLOCK_50MHZ); + } + break; + + default: + SDMMC_LOG("\r\nWarning: unknown timing mode"); + break; + } + } + else + { + } + + if (error == kStatus_Success) + { + /* SDR50 and SDR104 mode need tuning */ + if ((card->currentTiming == kSD_TimingSDR50Mode) || (card->currentTiming == kSD_TimingSDR104Mode)) + { + /* config IO strength in IOMUX*/ + if (card->currentTiming == kSD_TimingSDR50Mode) + { + SDMMCHOST_CONFIG_SD_IO(CARD_BUS_FREQ_100MHZ1, CARD_BUS_STRENGTH_7); + } + else + { + SDMMCHOST_CONFIG_SD_IO(CARD_BUS_FREQ_200MHZ, CARD_BUS_STRENGTH_7); + } + /* execute tuning */ + if (SD_ExecuteTuning(card) != kStatus_Success) + { + SDMMC_LOG("\r\nError: tuning failed for mode %d", card->currentTiming); + return kStatus_SDMMC_TuningFail; + } + } + else + { + /* set default IO strength to 4 to cover card adapter driver strength difference */ + SDMMCHOST_CONFIG_SD_IO(CARD_BUS_FREQ_100MHZ1, CARD_BUS_STRENGTH_4); + } + } + + return error; +} + +static void SD_DecodeStatus(sd_card_t *card, uint32_t *src) +{ + assert(card); + assert(src); + + card->stat.busWidth = (uint8_t)((src[0U] & 0xC0000000U) >> 30U); /* 511-510 */ + card->stat.secureMode = (uint8_t)((src[0U] & 0x20000000U) >> 29U); /* 509 */ + card->stat.cardType = (uint16_t)((src[0U] & 0x0000FFFFU)); /* 495-480 */ + card->stat.protectedSize = src[1U]; /* 479-448 */ + card->stat.speedClass = (uint8_t)((src[2U] & 0xFF000000U) >> 24U); /* 447-440 */ + card->stat.performanceMove = (uint8_t)((src[2U] & 0x00FF0000U) >> 16U); /* 439-432 */ + card->stat.auSize = (uint8_t)((src[2U] & 0x0000F000U) >> 12U); /* 431-428 */ + card->stat.eraseSize = (uint16_t)(((src[2U] & 0x000000FFU) << 8U) | ((src[3U] & 0xFF000000U) >> 24U)); /* 423-408 */ + card->stat.eraseTimeout = (((uint8_t)((src[3U] & 0x00FF0000U) >> 16U)) & 0xFCU) >> 2U; /* 407-402 */ + card->stat.eraseOffset = ((uint8_t)((src[3U] & 0x00FF0000U) >> 16U)) & 0x3U; /* 401-400 */ + card->stat.uhsSpeedGrade = (((uint8_t)((src[3U] & 0x0000FF00U) >> 8U)) & 0xF0U) >> 4U; /* 399-396 */ + card->stat.uhsAuSize = ((uint8_t)((src[3U] & 0x0000FF00U) >> 8U)) & 0xFU; /* 395-392 */ +} + +status_t SD_ReadStatus(sd_card_t *card) +{ + assert(card); + + uint32_t i = 0U; + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_DATA data = {0}; + status_t error = kStatus_Success; + + memset(g_sdmmc, 0U, sizeof(g_sdmmc)); + + /* wait card status ready. */ + if (kStatus_Success != SD_WaitWriteComplete(card)) + { + return kStatus_SDMMC_WaitWriteCompleteFailed; + } + + if (kStatus_Success != SD_SendApplicationCmd(card, card->relativeAddress)) + { + return kStatus_SDMMC_SendApplicationCommandFailed; + } + + command.index = kSDMMC_SendStatus; + command.responseType = kCARD_ResponseTypeR1; + + data.blockSize = 64U; + data.blockCount = 1U; + data.rxData = &g_sdmmc[0]; + + content.command = &command; + content.data = &data; + error = card->host.transfer(card->host.base, &content); + if ((kStatus_Success != error) || ((command.response[0U]) & SDMMC_R1_ALL_ERROR_FLAG)) + { + SDMMC_LOG("\r\nError: send ACMD13 failed with host error %d, response %x", error, command.response[0U]); + + return kStatus_SDMMC_TransferFailed; + } + + switch (card->host.config.endianMode) + { + case kSDMMCHOST_EndianModeLittle: + /* In little endian mode, SD bus byte transferred first is the byte stored in lowest byte position in + a word which will cause 4 byte's sequence in a word is not consistent with their original sequence from + card. So the sequence of 4 bytes received in a word should be converted. */ + for (i = 0U; i < 16; i++) + { + g_sdmmc[i] = SWAP_WORD_BYTE_SEQUENCE(g_sdmmc[i]); + } + break; + case kSDMMCHOST_EndianModeBig: + break; /* Doesn't need to switch byte sequence when decodes bytes as big endian sequence. */ + case kSDMMCHOST_EndianModeHalfWordBig: + for (i = 0U; i < 16; i++) + { + g_sdmmc[i] = SWAP_HALF_WROD_BYTE_SEQUENCE(g_sdmmc[i]); + } + break; + default: + return kStatus_SDMMC_NotSupportYet; + } + + SD_DecodeStatus(card, g_sdmmc); + + return kStatus_Success; +} + +status_t SD_SelectCard(sd_card_t *card, bool isSelected) +{ + assert(card); + + return SDMMC_SelectCard(card->host.base, card->host.transfer, card->relativeAddress, isSelected); +} + +status_t SD_SetDriverStrength(sd_card_t *card, sd_driver_strength_t driverStrength) +{ + assert(card); + + status_t error; + uint32_t strength = driverStrength; + + error = SD_SelectFunction(card, kSD_GroupDriverStrength, strength); + + return error; +} + +status_t SD_SetMaxCurrent(sd_card_t *card, sd_max_current_t maxCurrent) +{ + assert(card); + + status_t error; + uint32_t current = maxCurrent; + + error = SD_SelectFunction(card, kSD_GroupCurrentLimit, current); + + return error; +} + +static status_t SD_Read(sd_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockSize, uint32_t blockCount) +{ + assert(card); + assert(buffer); + assert(blockCount); + assert(blockSize == FSL_SDMMC_DEFAULT_BLOCK_SIZE); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_DATA data = {0}; + + if (((card->flags & kSD_SupportHighCapacityFlag) && (blockSize != 512U)) || (blockSize > card->blockSize) || + (blockSize > card->host.capability.maxBlockLength) || (blockSize % 4)) + { + SDMMC_LOG("\r\nError: read with parameter, block size %d is not support", blockSize); + return kStatus_SDMMC_CardNotSupport; + } + + /* Wait for the card write process complete because of that card read process and write process use one buffer. */ + if (kStatus_Success != SD_WaitWriteComplete(card)) + { + return kStatus_SDMMC_WaitWriteCompleteFailed; + } + + data.blockSize = blockSize; + data.blockCount = blockCount; + data.rxData = (uint32_t *)buffer; + data.enableAutoCommand12 = true; + + command.index = (blockCount == 1U) ? kSDMMC_ReadSingleBlock : kSDMMC_ReadMultipleBlock; + command.argument = startBlock; + if (!(card->flags & kSD_SupportHighCapacityFlag)) + { + command.argument *= data.blockSize; + } + command.responseType = kCARD_ResponseTypeR1; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; + + content.command = &command; + content.data = &data; + + return SD_Transfer(card, &content, 1U); +} + +static status_t SD_Write(sd_card_t *card, + const uint8_t *buffer, + uint32_t startBlock, + uint32_t blockSize, + uint32_t blockCount, + uint32_t *writtenBlocks) +{ + assert(card); + assert(buffer); + assert(blockCount); + assert(blockSize == FSL_SDMMC_DEFAULT_BLOCK_SIZE); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + SDMMCHOST_DATA data = {0}; + status_t error; + + if (((card->flags & kSD_SupportHighCapacityFlag) && (blockSize != 512U)) || (blockSize > card->blockSize) || + (blockSize > card->host.capability.maxBlockLength) || (blockSize % 4U)) + { + SDMMC_LOG("\r\nError: write with parameter, block size %d is not support", blockSize); + return kStatus_SDMMC_CardNotSupport; + } + + /* Wait for the card write process complete because of that card read process and write process use one buffer.*/ + if (kStatus_Success != SD_WaitWriteComplete(card)) + { + return kStatus_SDMMC_WaitWriteCompleteFailed; + } + + /* Wait for the card's buffer to be not full to write to improve the write performance. */ + while ((GET_SDMMCHOST_STATUS(card->host.base) & CARD_DATA0_STATUS_MASK) != CARD_DATA0_NOT_BUSY) + { + } + + data.enableAutoCommand12 = true; + data.blockSize = blockSize; + command.responseType = kCARD_ResponseTypeR1; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; + + command.index = (blockCount == 1U) ? kSDMMC_WriteSingleBlock : kSDMMC_WriteMultipleBlock; + command.argument = startBlock; + if (!(card->flags & kSD_SupportHighCapacityFlag)) + { + command.argument *= data.blockSize; + } + + *writtenBlocks = blockCount; + data.blockCount = blockCount; + data.txData = (const uint32_t *)(buffer); + + content.command = &command; + content.data = &data; + + error = SD_Transfer(card, &content, 0U); + if (error != kStatus_Success) + { + /* check the successfully written block */ + if ((SD_SendWriteSuccessBlocks(card, writtenBlocks) == kStatus_Success)) + { + if (*writtenBlocks) + { + /* written success, but not all the blocks are written */ + error = kStatus_Success; + } + } + SDMMC_LOG("\r\nWarning: write failed with block count %d, successed %d", blockCount, *writtenBlocks); + } + + return error; +} + +static status_t SD_Erase(sd_card_t *card, uint32_t startBlock, uint32_t blockCount) +{ + assert(card); + assert(blockCount); + + uint32_t eraseBlockStart; + uint32_t eraseBlockEnd; + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + status_t error = kStatus_Success; + + /* Wait for the card write process complete because of that card read process and write process use one buffer.*/ + if (kStatus_Success != SD_WaitWriteComplete(card)) + { + return kStatus_SDMMC_WaitWriteCompleteFailed; + } + /* Wait for the card's buffer to be not full to write to improve the write performance. */ + while ((GET_SDMMCHOST_STATUS(card->host.base) & CARD_DATA0_STATUS_MASK) != CARD_DATA0_NOT_BUSY) + { + } + + eraseBlockStart = startBlock; + eraseBlockEnd = eraseBlockStart + blockCount - 1U; + if (!(card->flags & kSD_SupportHighCapacityFlag)) + { + eraseBlockStart = eraseBlockStart * FSL_SDMMC_DEFAULT_BLOCK_SIZE; + eraseBlockEnd = eraseBlockEnd * FSL_SDMMC_DEFAULT_BLOCK_SIZE; + } + + /* Send ERASE_WRITE_BLOCK_START command to set the start block number to erase. */ + command.index = kSD_EraseWriteBlockStart; + command.argument = eraseBlockStart; + command.responseType = kCARD_ResponseTypeR1; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; + + content.command = &command; + content.data = NULL; + error = SD_Transfer(card, &content, 1U); + if (kStatus_Success != error) + { + SDMMC_LOG("\r\nError: send CMD32(erase start) failed with host error %d, response %x", error, + command.response[0U]); + return kStatus_SDMMC_TransferFailed; + } + + /* Send ERASE_WRITE_BLOCK_END command to set the end block number to erase. */ + command.index = kSD_EraseWriteBlockEnd; + command.argument = eraseBlockEnd; + + content.command = &command; + content.data = NULL; + error = SD_Transfer(card, &content, 0U); + if (kStatus_Success != error) + { + SDMMC_LOG("\r\nError: send CMD33(erase end) failed with host error %d, response %x", error, + command.response[0U]); + return kStatus_SDMMC_TransferFailed; + } + + /* Send ERASE command to start erase process. */ + command.index = kSDMMC_Erase; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR1b; + command.responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG; + + content.command = &command; + content.data = NULL; + error = SD_Transfer(card, &content, 0U); + if (kStatus_Success != error) + { + SDMMC_LOG("\r\nError: send CMD38(erase) failed with host error %d, response %x", error, command.response[0U]); + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +bool SD_CheckReadOnly(sd_card_t *card) +{ + assert(card); + + return ((card->csd.flags & kSD_CsdPermanentWriteProtectFlag) || + (card->csd.flags & kSD_CsdTemporaryWriteProtectFlag)); +} + +status_t SD_ReadBlocks(sd_card_t *card, uint8_t *buffer, uint32_t startBlock, uint32_t blockCount) +{ + assert(card); + assert(buffer); + assert(blockCount); + assert((blockCount + startBlock) <= card->blockCount); + + uint32_t blockCountOneTime; + uint32_t blockLeft; + uint32_t blockDone = 0U; + uint8_t *nextBuffer = buffer; + bool dataAddrAlign = true; + + blockLeft = blockCount; + + while (blockLeft) + { + nextBuffer = (buffer + blockDone * FSL_SDMMC_DEFAULT_BLOCK_SIZE); + if (!card->noInteralAlign && (!dataAddrAlign || (((uint32_t)nextBuffer) & (sizeof(uint32_t) - 1U)))) + { + blockLeft--; + blockCountOneTime = 1U; + memset(g_sdmmc, 0U, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + dataAddrAlign = false; + } + else + { + if (blockLeft > card->host.capability.maxBlockCount) + { + blockLeft = (blockLeft - card->host.capability.maxBlockCount); + blockCountOneTime = card->host.capability.maxBlockCount; + } + else + { + blockCountOneTime = blockLeft; + blockLeft = 0U; + } + } + + if (kStatus_Success != SD_Read(card, dataAddrAlign ? nextBuffer : (uint8_t *)g_sdmmc, (startBlock + blockDone), + FSL_SDMMC_DEFAULT_BLOCK_SIZE, blockCountOneTime)) + { + return kStatus_SDMMC_TransferFailed; + } + + blockDone += blockCountOneTime; + + if (!card->noInteralAlign && (!dataAddrAlign)) + { + memcpy(nextBuffer, (uint8_t *)&g_sdmmc, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + } + } + + return kStatus_Success; +} + +status_t SD_WriteBlocks(sd_card_t *card, const uint8_t *buffer, uint32_t startBlock, uint32_t blockCount) +{ + assert(card); + assert(buffer); + assert(blockCount); + assert((blockCount + startBlock) <= card->blockCount); + + uint32_t blockCountOneTime = 0U; /* The block count can be wrote in one time sending WRITE_BLOCKS command. */ + uint32_t blockWrittenOneTime = 0U; + uint32_t blockLeft = 0U; /* Left block count to be wrote. */ + const uint8_t *nextBuffer; + bool dataAddrAlign = true; + + blockLeft = blockCount; + while (blockLeft) + { + nextBuffer = (buffer + (blockCount - blockLeft) * FSL_SDMMC_DEFAULT_BLOCK_SIZE); + if (!card->noInteralAlign && (!dataAddrAlign || (((uint32_t)nextBuffer) & (sizeof(uint32_t) - 1U)))) + { + blockCountOneTime = 1U; + memcpy((uint8_t *)&g_sdmmc, nextBuffer, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + dataAddrAlign = false; + } + else + { + if (blockLeft > card->host.capability.maxBlockCount) + { + blockCountOneTime = card->host.capability.maxBlockCount; + } + else + { + blockCountOneTime = blockLeft; + } + } + + if (kStatus_Success != SD_Write(card, dataAddrAlign ? nextBuffer : (uint8_t *)g_sdmmc, + (startBlock + blockCount - blockLeft), FSL_SDMMC_DEFAULT_BLOCK_SIZE, + blockCountOneTime, &blockWrittenOneTime)) + { + return kStatus_SDMMC_TransferFailed; + } + + blockLeft -= blockWrittenOneTime; + + if ((!card->noInteralAlign) && !dataAddrAlign) + { + memset(g_sdmmc, 0U, FSL_SDMMC_DEFAULT_BLOCK_SIZE); + } + } + + return kStatus_Success; +} + +status_t SD_EraseBlocks(sd_card_t *card, uint32_t startBlock, uint32_t blockCount) +{ + assert(card); + assert(blockCount); + assert((blockCount + startBlock) <= card->blockCount); + + uint32_t blockCountOneTime; /* The block count can be erased in one time sending ERASE_BLOCKS command. */ + uint32_t blockDone = 0U; /* The block count has been erased. */ + uint32_t blockLeft; /* Left block count to be erase. */ + status_t error; + uint32_t onetimeMaxEraseBlocks = 0U; + + /* sdsc card erasable sector is determined by CSD register */ + if (card->csd.csdStructure == 0U) + { + onetimeMaxEraseBlocks = card->csd.eraseSectorSize + 1U; + } + else + { + /* limit one time maximum erase size to 1 AU */ + if (card->stat.auSize >= SD_AU_START_VALUE) + { + onetimeMaxEraseBlocks = s_sdAuSizeMap[card->stat.auSize] / FSL_SDMMC_DEFAULT_BLOCK_SIZE; + } + } + + if (onetimeMaxEraseBlocks == 0U) + { + SDMMC_LOG( + "Warning: AU size in sd descriptor is not set properly, please check if SD_ReadStatus is called before\ + SD_EraseBlocks"); + return kStatus_SDMMC_AuSizeNotSetProperly; + } + + blockLeft = blockCount; + while (blockLeft) + { + if (blockLeft > onetimeMaxEraseBlocks) + { + blockCountOneTime = onetimeMaxEraseBlocks; + blockLeft = blockLeft - blockCountOneTime; + } + else + { + blockCountOneTime = blockLeft; + blockLeft = 0U; + } + + error = SD_Erase(card, (startBlock + blockDone), blockCountOneTime); + if (error != kStatus_Success) + { + return error; + } + + blockDone += blockCountOneTime; + } + + return kStatus_Success; +} + +status_t SD_ProbeBusVoltage(sd_card_t *card) +{ + assert(card); + + uint32_t applicationCommand41Argument = 0U; + status_t error = kStatus_Success; + + /* 3.3V voltage should be supported as default */ + applicationCommand41Argument |= + SDMMC_MASK(kSD_OcrVdd29_30Flag) | SDMMC_MASK(kSD_OcrVdd32_33Flag) | SDMMC_MASK(kSD_OcrVdd33_34Flag); + /* make sure card signal line voltage is 3.3v before initalization */ + if ((card->usrParam.cardVoltage != NULL) && (card->usrParam.cardVoltage->cardSignalLine3V3 != NULL)) + { + card->usrParam.cardVoltage->cardSignalLine3V3(); + } + else + { + SDMMCHOST_SWITCH_VOLTAGE180V(card->host.base, false); + } + card->operationVoltage = kCARD_OperationVoltage330V; + + /* allow user select the work voltage, if not select, sdmmc will handle it automatically */ + if (kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) + { + applicationCommand41Argument |= SDMMC_MASK(kSD_OcrSwitch18RequestFlag); + } + + do + { + /* card go idle */ + if (kStatus_Success != SD_GoIdle(card)) + { + error = kStatus_SDMMC_GoIdleFailed; + break; + } + + /* Check card's supported interface condition. */ + if (kStatus_Success == SD_SendInterfaceCondition(card)) + { + /* SDHC or SDXC card */ + applicationCommand41Argument |= SDMMC_MASK(kSD_OcrHostCapacitySupportFlag); + card->flags |= kSD_SupportSdhcFlag; + } + else + { + /* SDSC card */ + if (kStatus_Success != SD_GoIdle(card)) + { + error = kStatus_SDMMC_GoIdleFailed; + break; + } + } + /* Set card interface condition according to SDHC capability and card's supported interface condition. */ + if (kStatus_Success != SD_ApplicationSendOperationCondition(card, applicationCommand41Argument)) + { + error = kStatus_SDMMC_HandShakeOperationConditionFailed; + break; + } + + /* check if card support 1.8V */ +// if ((card->flags & kSD_SupportVoltage180v)) +// { +// error = SD_SwitchVoltage(card); +// if (kStatus_SDMMC_SwitchVoltageFail == error) +// { +// break; +// } + +// if (error == kStatus_SDMMC_SwitchVoltage18VFail33VSuccess) +// { +// applicationCommand41Argument &= ~SDMMC_MASK(kSD_OcrSwitch18RequestFlag); +// card->flags &= ~kSD_SupportVoltage180v; +// continue; +// } +// else +// { +// card->operationVoltage = kCARD_OperationVoltage180V; +// break; +// } +// } + + break; + } while (1U); + + return error; +} + +status_t SD_CardInit(sd_card_t *card) +{ + assert(card); + assert(card->isHostReady == true); + + /* reset variables */ + card->flags = 0U; + /* set DATA bus width */ + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH1BIT); + /*set card freq to 400KHZ*/ + card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SDMMC_CLOCK_400KHZ); + /* send card active */ + SDMMCHOST_SEND_CARD_ACTIVE(card->host.base, 100U); + /* Get host capability. */ + GET_SDMMCHOST_CAPABILITY(card->host.base, &(card->host.capability)); + + /* probe bus voltage*/ + if (SD_ProbeBusVoltage(card) == kStatus_SDMMC_SwitchVoltageFail) + { + return kStatus_SDMMC_SwitchVoltageFail; + } + + /* Initialize card if the card is SD card. */ + if (kStatus_Success != SD_AllSendCid(card)) + { + return kStatus_SDMMC_AllSendCidFailed; + } + if (kStatus_Success != SD_SendRca(card)) + { + return kStatus_SDMMC_SendRelativeAddressFailed; + } + if (kStatus_Success != SD_SendCsd(card)) + { + return kStatus_SDMMC_SendCsdFailed; + } + if (kStatus_Success != SD_SelectCard(card, true)) + { + return kStatus_SDMMC_SelectCardFailed; + } + + /* Set to max frequency in non-high speed mode. */ + card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SD_CLOCK_25MHZ); + + if (kStatus_Success != SD_SendScr(card)) + { + return kStatus_SDMMC_SendScrFailed; + } + /* Set to 4-bit data bus mode. */ + if (((card->host.capability.flags) & kSDMMCHOST_Support4BitBusWidth) && (card->flags & kSD_Support4BitWidthFlag)) + { + if (kStatus_Success != SD_SetDataBusWidth(card, kSD_DataBusWidth4Bit)) + { + return kStatus_SDMMC_SetDataBusWidthFailed; + } + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH4BIT); + } + + /* set block size */ + if (SD_SetBlockSize(card, FSL_SDMMC_DEFAULT_BLOCK_SIZE)) + { + return kStatus_SDMMC_SetCardBlockSizeFailed; + } + + /* select bus timing */ + if (kStatus_Success != SD_SelectBusTiming(card)) + { + return kStatus_SDMMC_SwitchBusTimingFailed; + } + + /* try to get card current status */ + SD_ReadStatus(card); + + return kStatus_Success; +} + +void SD_CardDeinit(sd_card_t *card) +{ + assert(card); + + SD_SelectCard(card, false); +} + +status_t SD_HostInit(sd_card_t *card) +{ + assert(card); + + if ((!card->isHostReady) && SDMMCHOST_Init(&(card->host), (void *)(&(card->usrParam))) != kStatus_Success) + { + return kStatus_Fail; + } + + /* set the host status flag, after the card re-plug in, don't need init host again */ + card->isHostReady = true; + + return kStatus_Success; +} + +void SD_HostDeinit(sd_card_t *card) +{ + assert(card); + + SDMMCHOST_Deinit(&(card->host)); + /* should re-init host */ + card->isHostReady = false; +} + +void SD_HostReset(SDMMCHOST_CONFIG *host) +{ + SDMMCHOST_Reset(host->base); +} + +void SD_PowerOnCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +{ + SDMMCHOST_PowerOnCard(base, pwr); +} + +void SD_PowerOffCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +{ + SDMMCHOST_PowerOffCard(base, pwr); +} + +status_t SD_WaitCardDetectStatus(SDMMCHOST_TYPE *hostBase, const sdmmchost_detect_card_t *cd, bool waitCardStatus) +{ + return SDMMCHOST_WaitCardDetectStatus(hostBase, cd, waitCardStatus); +} + +bool SD_IsCardPresent(sd_card_t *card) +{ + return SDMMCHOST_IsCardPresent(); +} + +status_t SD_Init(sd_card_t *card) +{ + assert(card); + + if (!card->isHostReady) + { + if (SD_HostInit(card) != kStatus_Success) + { + return kStatus_SDMMC_HostNotReady; + } + } + else + { + SD_HostReset(&(card->host)); + } + SD_PowerOffCard(card->host.base, card->usrParam.pwr); + + if (SD_WaitCardDetectStatus(card->host.base, card->usrParam.cd, true) != kStatus_Success) + { + return kStatus_SDMMC_CardDetectFailed; + } + SD_PowerOnCard(card->host.base, card->usrParam.pwr); + + return SD_CardInit(card); +} + +void SD_Deinit(sd_card_t *card) +{ + /* card deinitialize */ + SD_CardDeinit(card); + /* host deinitialize */ + SD_HostDeinit(card); +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sdio.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sdio.c new file mode 100644 index 000000000..07611e99d --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sdio.c @@ -0,0 +1,1700 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_sdio.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief define the tuple number will be read during init */ +#define SDIO_COMMON_CIS_TUPLE_NUM (3U) +/*! @brief SDIO retry times */ +#define SDIO_RETRY_TIMES (1000U) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief probe bus voltage. + * @param card Card descriptor. + */ +static status_t SDIO_ProbeBusVoltage(sdio_card_t *card); + +/*! + * @brief send card operation condition + * @param card Card descriptor. + * @param command argment + * argument = 0U , means to get the operation condition + * argument !=0 , set the operation condition register + */ +static status_t SDIO_SendOperationCondition(sdio_card_t *card, uint32_t argument); + +/*! + * @brief card Send relative address + * @param card Card descriptor. + */ +static status_t SDIO_SendRca(sdio_card_t *card); + +/*! + * @brief card select card + * @param card Card descriptor. + * @param select/diselect flag + */ +static status_t inline SDIO_SelectCard(sdio_card_t *card, bool isSelected); + +/*! + * @brief card go idle + * @param card Card descriptor. + */ +static status_t inline SDIO_GoIdle(sdio_card_t *card); + +/*! + * @brief decode CIS + * @param card Card descriptor. + * @param func number + * @param data buffer pointer + * @param tuple code + * @param tuple link + */ +static status_t SDIO_DecodeCIS( + sdio_card_t *card, sdio_func_num_t func, uint8_t *dataBuffer, uint32_t tplCode, uint32_t tplLink); + +/*! + * @brief switch to the maxium support bus width, depend on the host and card's capability. + * @param card Card descriptor. + */ +static status_t SDIO_SetMaxDataBusWidth(sdio_card_t *card); + +/*! + * @brief sdio card excute tuning. + * @param card Card descriptor. + */ + +static status_t SDIO_ExecuteTuning(sdio_card_t *card); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/* define the tuple list */ +static const uint32_t g_tupleList[SDIO_COMMON_CIS_TUPLE_NUM] = { + SDIO_TPL_CODE_MANIFID, + SDIO_TPL_CODE_FUNCID, + SDIO_TPL_CODE_FUNCE, +}; + +/* g_sdmmc statement */ +extern uint32_t g_sdmmc[SDK_SIZEALIGN(SDMMC_GLOBAL_BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)]; +/******************************************************************************* + * Code + ******************************************************************************/ +static status_t inline SDIO_SelectCard(sdio_card_t *card, bool isSelected) +{ + assert(card); + + return SDMMC_SelectCard(card->host.base, card->host.transfer, card->relativeAddress, isSelected); +} + +static status_t inline SDIO_GoIdle(sdio_card_t *card) +{ + assert(card); + + return SDMMC_GoIdle(card->host.base, card->host.transfer); +} + +static status_t SDIO_SwitchVoltage(sdio_card_t *card) +{ + assert(card); + + if ((card->usrParam.cardVoltage != NULL) && (card->usrParam.cardVoltage->cardSignalLine1V8 != NULL)) + { + return SDMMC_SwitchToVoltage(card->host.base, card->host.transfer, + card->usrParam.cardVoltage->cardSignalLine1V8); + } + + return SDMMC_SwitchToVoltage(card->host.base, card->host.transfer, NULL); +} + +static status_t SDIO_ExecuteTuning(sdio_card_t *card) +{ + assert(card); + + return SDMMC_ExecuteTuning(card->host.base, card->host.transfer, kSD_SendTuningBlock, 64U); +} + +static status_t SDIO_SendRca(sdio_card_t *card) +{ + assert(card); + + uint32_t i = FSL_SDMMC_MAX_CMD_RETRIES; + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + + command.index = kSDIO_SendRelativeAddress; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR6; + command.responseErrorFlags = kSDIO_StatusR6Error | kSDIO_StatusIllegalCmd | kSDIO_StatusCmdCRCError; + + content.command = &command; + content.data = NULL; + + while (--i) + { + if (kStatus_Success == card->host.transfer(card->host.base, &content)) + { + /* check illegal state and cmd CRC error, may be the voltage or clock not stable, retry the cmd*/ + if (command.response[0U] & (kSDIO_StatusIllegalCmd | kSDIO_StatusCmdCRCError)) + { + continue; + } + + card->relativeAddress = (command.response[0U] >> 16U); + + return kStatus_Success; + } + } + + return kStatus_SDMMC_TransferFailed; +} + +status_t SDIO_CardInActive(sdio_card_t *card) +{ + assert(card); + + return SDMMC_SetCardInactive(card->host.base, card->host.transfer); +} + +static status_t SDIO_SendOperationCondition(sdio_card_t *card, uint32_t argument) +{ + assert(card); + + SDMMCHOST_TRANSFER content = {0U}; + SDMMCHOST_COMMAND command = {0U}; + uint32_t i = SDIO_RETRY_TIMES; + + command.index = kSDIO_SendOperationCondition; + command.argument = argument; + command.responseType = kCARD_ResponseTypeR4; + + content.command = &command; + content.data = NULL; + + while (--i) + { + if (kStatus_Success != card->host.transfer(card->host.base, &content) || (command.response[0U] == 0U)) + { + continue; + } + + /* if argument equal 0, then should check and save the info */ + if (argument == 0U) + { + /* check if memory present */ + if ((command.response[0U] & SDMMC_MASK(kSDIO_OcrMemPresent)) == SDMMC_MASK(kSDIO_OcrMemPresent)) + { + card->memPresentFlag = true; + } + /* save the io number */ + card->ioTotalNumber = (command.response[0U] & SDIO_OCR_IO_NUM_MASK) >> kSDIO_OcrIONumber; + /* save the operation condition */ + card->ocr = command.response[0U] & 0xFFFFFFU; + + break; + } + /* wait the card is ready for after initialization */ + else if (command.response[0U] & SDMMC_MASK(kSDIO_OcrPowerUpBusyFlag)) + { + break; + } + } + + return ((i != 0U) ? kStatus_Success : kStatus_Fail); +} + +status_t SDIO_IO_Write_Direct(sdio_card_t *card, sdio_func_num_t func, uint32_t regAddr, uint8_t *data, bool raw) +{ + assert(card); + assert(func <= kSDIO_FunctionNum7); + + SDMMCHOST_TRANSFER content = {0U}; + SDMMCHOST_COMMAND command = {0U}; + + command.index = kSDIO_RWIODirect; + command.argument = (func << SDIO_CMD_ARGUMENT_FUNC_NUM_POS) | + ((regAddr & SDIO_CMD_ARGUMENT_REG_ADDR_MASK) << SDIO_CMD_ARGUMENT_REG_ADDR_POS) | + (1U << SDIO_CMD_ARGUMENT_RW_POS) | ((raw ? 1U : 0U) << SDIO_DIRECT_CMD_ARGUMENT_RAW_POS) | + (*data & SDIO_DIRECT_CMD_DATA_MASK); + command.responseType = kCARD_ResponseTypeR5; + command.responseErrorFlags = (kSDIO_StatusCmdCRCError | kSDIO_StatusIllegalCmd | kSDIO_StatusError | + kSDIO_StatusFunctionNumError | kSDIO_StatusOutofRange); + + content.command = &command; + content.data = NULL; + + if (kStatus_Success != card->host.transfer(card->host.base, &content)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* read data from response */ + *data = command.response[0U] & SDIO_DIRECT_CMD_DATA_MASK; + + return kStatus_Success; +} + +status_t SDIO_IO_Read_Direct(sdio_card_t *card, sdio_func_num_t func, uint32_t regAddr, uint8_t *data) +{ + assert(card); + assert(func <= kSDIO_FunctionNum7); + + SDMMCHOST_TRANSFER content = {0U}; + SDMMCHOST_COMMAND command = {0U}; + + command.index = kSDIO_RWIODirect; + command.argument = (func << SDIO_CMD_ARGUMENT_FUNC_NUM_POS) | + ((regAddr & SDIO_CMD_ARGUMENT_REG_ADDR_MASK) << SDIO_CMD_ARGUMENT_REG_ADDR_POS); + command.responseType = kCARD_ResponseTypeR5; + command.responseErrorFlags = (kSDIO_StatusCmdCRCError | kSDIO_StatusIllegalCmd | kSDIO_StatusError | + kSDIO_StatusFunctionNumError | kSDIO_StatusOutofRange); + + content.command = &command; + content.data = NULL; + + if (kStatus_Success != card->host.transfer(card->host.base, &content)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* read data from response */ + *data = command.response[0U] & SDIO_DIRECT_CMD_DATA_MASK; + + return kStatus_Success; +} + +status_t SDIO_IO_RW_Direct(sdio_card_t *card, + sdio_io_direction_t direction, + sdio_func_num_t func, + uint32_t regAddr, + uint8_t dataIn, + uint8_t *dataOut) +{ + assert(card); + assert(func <= kSDIO_FunctionNum7); + + SDMMCHOST_TRANSFER content = {0U}; + SDMMCHOST_COMMAND command = {0U}; + + command.index = kSDIO_RWIODirect; + command.argument = (func << SDIO_CMD_ARGUMENT_FUNC_NUM_POS) | + ((regAddr & SDIO_CMD_ARGUMENT_REG_ADDR_MASK) << SDIO_CMD_ARGUMENT_REG_ADDR_POS); + + if ((dataOut != NULL) && (direction == kSDIO_IOWrite)) + { + command.argument |= (1U << SDIO_CMD_ARGUMENT_RW_POS) | (1U << SDIO_DIRECT_CMD_ARGUMENT_RAW_POS); + } + + if (direction == kSDIO_IOWrite) + { + command.argument |= dataIn & SDIO_DIRECT_CMD_DATA_MASK; + } + + command.responseType = kCARD_ResponseTypeR5; + command.responseErrorFlags = (kSDIO_StatusCmdCRCError | kSDIO_StatusIllegalCmd | kSDIO_StatusError | + kSDIO_StatusFunctionNumError | kSDIO_StatusOutofRange); + + command.responseType = kCARD_ResponseTypeR5; + command.responseErrorFlags = (kSDIO_StatusCmdCRCError | kSDIO_StatusIllegalCmd | kSDIO_StatusError | + kSDIO_StatusFunctionNumError | kSDIO_StatusOutofRange); + + content.command = &command; + content.data = NULL; + + if (kStatus_Success != card->host.transfer(card->host.base, &content)) + { + return kStatus_SDMMC_TransferFailed; + } + + if (dataOut != NULL) + { + /* read data from response */ + *dataOut = command.response[0U] & SDIO_DIRECT_CMD_DATA_MASK; + } + + return kStatus_Success; +} + +status_t SDIO_IO_Write_Extended( + sdio_card_t *card, sdio_func_num_t func, uint32_t regAddr, uint8_t *buffer, uint32_t count, uint32_t flags) +{ + assert(card); + assert(buffer); + assert(func <= kSDIO_FunctionNum7); + + SDMMCHOST_TRANSFER content = {0U}; + SDMMCHOST_COMMAND command = {0U}; + SDMMCHOST_DATA data = {0U}; + bool blockMode = false; + bool opCode = false; + + /* check if card support block mode */ + if ((card->cccrflags & kSDIO_CCCRSupportMultiBlock) && (flags & SDIO_EXTEND_CMD_BLOCK_MODE_MASK)) + { + blockMode = true; + } + + if (flags & SDIO_EXTEND_CMD_OP_CODE_MASK) + { + opCode = true; + } + + /* check the byte size counter in non-block mode + * so you need read CIS for each function first,before you do read/write + */ + if (!blockMode) + { + if ((func == kSDIO_FunctionNum0) && (card->commonCIS.fn0MaxBlkSize != 0U) && + (count > card->commonCIS.fn0MaxBlkSize)) + { + return kStatus_SDMMC_SDIO_InvalidArgument; + } + else if ((func != kSDIO_FunctionNum0) && (card->funcCIS[func - 1U].ioMaxBlockSize != 0U) && + (count > card->funcCIS[func - 1U].ioMaxBlockSize)) + { + return kStatus_SDMMC_SDIO_InvalidArgument; + } + } + + command.index = kSDIO_RWIOExtended; + command.argument = (func << SDIO_CMD_ARGUMENT_FUNC_NUM_POS) | + ((regAddr & SDIO_CMD_ARGUMENT_REG_ADDR_MASK) << SDIO_CMD_ARGUMENT_REG_ADDR_POS) | + (1U << SDIO_CMD_ARGUMENT_RW_POS) | (count & SDIO_EXTEND_CMD_COUNT_MASK) | + ((blockMode ? 1 : 0) << SDIO_EXTEND_CMD_ARGUMENT_BLOCK_MODE_POS | + ((opCode ? 1 : 0) << SDIO_EXTEND_CMD_ARGUMENT_OP_CODE_POS)); + command.responseType = kCARD_ResponseTypeR5; + command.responseErrorFlags = (kSDIO_StatusCmdCRCError | kSDIO_StatusIllegalCmd | kSDIO_StatusError | + kSDIO_StatusFunctionNumError | kSDIO_StatusOutofRange); + + if (blockMode) + { + if (func == kSDIO_FunctionNum0) + { + data.blockSize = card->io0blockSize; + } + else + { + data.blockSize = card->ioFBR[func - 1U].ioBlockSize; + } + data.blockCount = count; + } + else + { + data.blockSize = count; + data.blockCount = 1U; + } + data.txData = (uint32_t *)buffer; + + content.command = &command; + content.data = &data; + + if (kStatus_Success != card->host.transfer(card->host.base, &content)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t SDIO_IO_Read_Extended( + sdio_card_t *card, sdio_func_num_t func, uint32_t regAddr, uint8_t *buffer, uint32_t count, uint32_t flags) +{ + assert(card); + assert(buffer); + assert(func <= kSDIO_FunctionNum7); + + SDMMCHOST_TRANSFER content = {0U}; + SDMMCHOST_COMMAND command = {0U}; + SDMMCHOST_DATA data = {0U}; + bool blockMode = false; + bool opCode = false; + + /* check if card support block mode */ + if ((card->cccrflags & kSDIO_CCCRSupportMultiBlock) && (flags & SDIO_EXTEND_CMD_BLOCK_MODE_MASK)) + { + blockMode = true; + } + + /* op code =0 : read/write to fixed addr + * op code =1 :read/write addr incrementing + */ + if (flags & SDIO_EXTEND_CMD_OP_CODE_MASK) + { + opCode = true; + } + + /* check the byte size counter in non-block mode + * so you need read CIS for each function first,before you do read/write + */ + if (!blockMode) + { + if ((func == kSDIO_FunctionNum0) && (card->commonCIS.fn0MaxBlkSize != 0U) && + (count > card->commonCIS.fn0MaxBlkSize)) + { + return kStatus_SDMMC_SDIO_InvalidArgument; + } + else if ((func != kSDIO_FunctionNum0) && (card->funcCIS[func - 1U].ioMaxBlockSize != 0U) && + (count > card->funcCIS[func - 1U].ioMaxBlockSize)) + { + return kStatus_SDMMC_SDIO_InvalidArgument; + } + } + + command.index = kSDIO_RWIOExtended; + command.argument = (func << SDIO_CMD_ARGUMENT_FUNC_NUM_POS) | + ((regAddr & SDIO_CMD_ARGUMENT_REG_ADDR_MASK) << SDIO_CMD_ARGUMENT_REG_ADDR_POS) | + (count & SDIO_EXTEND_CMD_COUNT_MASK) | + ((blockMode ? 1U : 0U) << SDIO_EXTEND_CMD_ARGUMENT_BLOCK_MODE_POS | + ((opCode ? 1U : 0U) << SDIO_EXTEND_CMD_ARGUMENT_OP_CODE_POS)); + command.responseType = kCARD_ResponseTypeR5; + command.responseErrorFlags = (kSDIO_StatusCmdCRCError | kSDIO_StatusIllegalCmd | kSDIO_StatusError | + kSDIO_StatusFunctionNumError | kSDIO_StatusOutofRange); + + if (blockMode) + { + if (func == kSDIO_FunctionNum0) + { + data.blockSize = card->io0blockSize; + } + else + { + data.blockSize = card->ioFBR[func - 1U].ioBlockSize; + } + data.blockCount = count; + } + else + { + data.blockSize = count; + data.blockCount = 1U; + } + data.rxData = (uint32_t *)buffer; + + content.command = &command; + content.data = &data; + + if (kStatus_Success != card->host.transfer(card->host.base, &content)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t SDIO_IO_Transfer(sdio_card_t *card, + sdio_command_t cmd, + uint32_t argument, + uint32_t blockSize, + uint8_t *txData, + uint8_t *rxData, + uint16_t dataSize, + uint32_t *response) +{ + assert(card != NULL); + + uint32_t actualSize = dataSize; + SDMMCHOST_TRANSFER content = {0U}; + SDMMCHOST_COMMAND command = {0U}; + SDMMCHOST_DATA data = {0U}; + uint32_t i = SDIO_RETRY_TIMES; + uint32_t *dataAddr = (uint32_t *)(txData == NULL ? rxData : txData); + + if ((dataSize != 0U) && (txData != NULL) && (rxData != NULL)) + { + return kStatus_InvalidArgument; + } + + command.index = cmd; + command.argument = argument; + command.responseType = kCARD_ResponseTypeR5; + command.responseErrorFlags = (kSDIO_StatusCmdCRCError | kSDIO_StatusIllegalCmd | kSDIO_StatusError | + kSDIO_StatusFunctionNumError | kSDIO_StatusOutofRange); + content.command = &command; + content.data = NULL; + + if (dataSize) + { + /* if block size bigger than 1, then use block mode */ + if (argument & SDIO_EXTEND_CMD_BLOCK_MODE_MASK) + { + if (dataSize % blockSize != 0) + { + actualSize = ((dataSize / blockSize) + 1) * blockSize; + } + + data.blockCount = actualSize / blockSize; + data.blockSize = blockSize; + } + else + { + data.blockCount = 1; + data.blockSize = dataSize; + } + /* if data buffer address can not meet host controller internal DMA requirement, sdio driver will try to use + * internal align buffer if data size is not bigger than internal buffer size, + * Align address transfer always can get a better performance, so if you want sdio driver make buffer address + * align, you should + * redefine the SDMMC_GLOBAL_BUFFER_SIZE macro to a value which is big enough for your application. + */ + if (((uint32_t)dataAddr & (SDMMCHOST_DMA_BUFFER_ADDR_ALIGN - 1U)) && + (actualSize <= (SDMMC_GLOBAL_BUFFER_SIZE * sizeof(uint32_t))) && (!card->noInternalAlign)) + { + dataAddr = (uint32_t *)g_sdmmc; + memset(g_sdmmc, 0U, actualSize); + if (txData) + { + memcpy(g_sdmmc, txData, dataSize); + } + } + + if (rxData) + { + data.rxData = dataAddr; + } + else + { + data.txData = dataAddr; + } + + content.data = &data; + } + + do + { + if (kStatus_Success == card->host.transfer(card->host.base, &content)) + { + if ((rxData != NULL) && ((uint32_t)rxData & (SDMMCHOST_DMA_BUFFER_ADDR_ALIGN - 1U)) && + (actualSize <= (SDMMC_GLOBAL_BUFFER_SIZE * sizeof(uint32_t))) && (!card->noInternalAlign)) + { + memcpy(rxData, g_sdmmc, dataSize); + } + + if (response != NULL) + { + *response = command.response[0]; + } + + return kStatus_Success; + } + + } while (i--); + + return kStatus_Fail; +} + +status_t SDIO_GetCardCapability(sdio_card_t *card, sdio_func_num_t func) +{ + assert(card); + assert(func <= kSDIO_FunctionNum7); + + uint8_t *tempBuffer = (uint8_t *)g_sdmmc; + uint32_t i = 0U; + + memset(g_sdmmc, 0U, sizeof(g_sdmmc)); + + for (i = 0U; i <= SDIO_CCCR_REG_NUMBER; i++) + { + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, SDIO_FBR_BASE(func) + i, 0U, &tempBuffer[i])) + { + return kStatus_SDMMC_TransferFailed; + } + } + + switch (func) + { + case kSDIO_FunctionNum0: + + card->sdVersion = tempBuffer[kSDIO_RegSDVersion]; + card->sdioVersion = tempBuffer[kSDIO_RegCCCRSdioVer] >> 4U; + card->cccrVersioin = tempBuffer[kSDIO_RegCCCRSdioVer] & 0xFU; + /* continuous SPI interrupt */ + if (tempBuffer[kSDIO_RegBusInterface] & 0x40U) + { + card->cccrflags |= kSDIO_CCCRSupportContinuousSPIInt; + } + /* 8bit data bus */ + if (tempBuffer[kSDIO_RegBusInterface] & 0x4U) + { + card->cccrflags |= SDIO_CCCR_SUPPORT_8BIT_BUS; + } + + /* card capability register */ + card->cccrflags |= (tempBuffer[kSDIO_RegCardCapability] & 0xDFU); + /* master power control */ + if (tempBuffer[kSDIO_RegPowerControl] & 0x01U) + { + card->cccrflags |= kSDIO_CCCRSupportMasterPowerControl; + } + /* high speed flag */ + if (tempBuffer[kSDIO_RegBusSpeed] & 0x01U) + { + card->cccrflags |= SDIO_CCCR_SUPPORT_HIGHSPEED; + } + /* uhs mode flag */ + card->cccrflags |= (tempBuffer[kSDIO_RegUHSITimingSupport] & 7U) << 11U; + /* driver type flag */ + card->cccrflags |= (tempBuffer[kSDIO_RegDriverStrength] & 7U) << 14U; + /* low speed 4bit */ + if (tempBuffer[kSDIO_RegCardCapability] & 0x80U) + { + card->cccrflags |= kSDIO_CCCRSupportLowSpeed4Bit; + } + /* common CIS pointer */ + card->commonCISPointer = tempBuffer[kSDIO_RegCommonCISPointer] | + (tempBuffer[kSDIO_RegCommonCISPointer + 1U] << 8U) | + (tempBuffer[kSDIO_RegCommonCISPointer + 2U] << 16U); + + /* check card capability of support async interrupt */ + if ((tempBuffer[kSDIO_RegInterruptExtension] & SDIO_CCCR_ASYNC_INT_MASK) == SDIO_CCCR_ASYNC_INT_MASK) + { + card->cccrflags |= SDIO_CCCR_SUPPORT_ASYNC_INT; + } + + break; + + case kSDIO_FunctionNum1: + case kSDIO_FunctionNum2: + case kSDIO_FunctionNum3: + case kSDIO_FunctionNum4: + case kSDIO_FunctionNum5: + case kSDIO_FunctionNum6: + case kSDIO_FunctionNum7: + card->ioFBR[func - 1U].ioStdFunctionCode = tempBuffer[0U] & 0x0FU; + card->ioFBR[func - 1U].ioExtFunctionCode = tempBuffer[1U]; + card->ioFBR[func - 1U].ioPointerToCIS = tempBuffer[9U] | (tempBuffer[10U] << 8U) | (tempBuffer[11U] << 16U); + card->ioFBR[func - 1U].ioPointerToCSA = + tempBuffer[12U] | (tempBuffer[13U] << 8U) | (tempBuffer[14U] << 16U); + if (tempBuffer[2U] & 0x01U) + { + card->ioFBR[func - 1U].flags |= kSDIO_FBRSupportPowerSelection; + } + if (tempBuffer[0U] & 0x40U) + { + card->ioFBR[func - 1U].flags |= kSDIO_FBRSupportCSA; + } + + break; + + default: + break; + } + + return kStatus_Success; +} + +status_t SDIO_SetBlockSize(sdio_card_t *card, sdio_func_num_t func, uint32_t blockSize) +{ + assert(card); + assert(func <= kSDIO_FunctionNum7); + assert(blockSize <= SDIO_MAX_BLOCK_SIZE); + + uint8_t temp = 0U; + + /* check the block size for block mode + * so you need read CIS for each function first,before you do read/write + */ + if ((func == kSDIO_FunctionNum0) && (card->commonCIS.fn0MaxBlkSize != 0U) && + (blockSize > card->commonCIS.fn0MaxBlkSize)) + { + return kStatus_SDMMC_SDIO_InvalidArgument; + } + else if ((func != kSDIO_FunctionNum0) && (card->funcCIS[func - 1U].ioMaxBlockSize != 0U) && + (blockSize > card->funcCIS[func - 1U].ioMaxBlockSize)) + { + return kStatus_SDMMC_SDIO_InvalidArgument; + } + + temp = blockSize & 0xFFU; + + if (kStatus_Success != SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, + SDIO_FBR_BASE(func) + kSDIO_RegFN0BlockSizeLow, temp, &temp)) + { + return kStatus_SDMMC_SetCardBlockSizeFailed; + } + + temp = (blockSize >> 8U) & 0xFFU; + + if (kStatus_Success != SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, + SDIO_FBR_BASE(func) + kSDIO_RegFN0BlockSizeHigh, temp, &temp)) + { + return kStatus_SDMMC_SetCardBlockSizeFailed; + } + + /* record the current block size */ + if (func == kSDIO_FunctionNum0) + { + card->io0blockSize = blockSize; + } + else + { + card->ioFBR[func - 1U].ioBlockSize = blockSize; + } + + return kStatus_Success; +} + +status_t SDIO_CardReset(sdio_card_t *card) +{ + return SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegIOAbort, 0x08U, NULL); +} + +status_t SDIO_SetDataBusWidth(sdio_card_t *card, sdio_bus_width_t busWidth) +{ + assert(card); + + uint8_t regBusInterface = 0U; + + if (((busWidth == kSDIO_DataBus4Bit) && ((card->cccrflags & kSDIO_CCCRSupportHighSpeed) == 0U) && + ((card->cccrflags & kSDIO_CCCRSupportLowSpeed4Bit) == 0U)) || + (((SDMMCHOST_NOT_SUPPORT == kSDMMCHOST_Support8BitBusWidth) || + ((card->cccrflags & SDIO_CCCR_SUPPORT_8BIT_BUS) == 0U)) && + (busWidth == kSDIO_DataBus8Bit))) + { + return kStatus_SDMMC_SDIO_InvalidArgument; + } + + /* load bus interface register */ + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegBusInterface, 0U, ®BusInterface)) + { + return kStatus_SDMMC_TransferFailed; + } + /* set bus width */ + regBusInterface &= 0xFCU; + regBusInterface |= busWidth; + + /* write to register */ + if (kStatus_Success != SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegBusInterface, + regBusInterface, ®BusInterface)) + { + return kStatus_SDMMC_TransferFailed; + } + + if (busWidth == kSDIO_DataBus8Bit) + { + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH8BIT); + } + else if (busWidth == kSDIO_DataBus4Bit) + { + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH4BIT); + } + else + { + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH1BIT); + } + + return kStatus_Success; +} + +static status_t SDIO_SetMaxDataBusWidth(sdio_card_t *card) +{ + sdio_bus_width_t busWidth = kSDIO_DataBus1Bit; + + if ((SDMMCHOST_NOT_SUPPORT != kSDMMCHOST_Support8BitBusWidth) && + ((card->cccrflags & SDIO_CCCR_SUPPORT_8BIT_BUS) != 0U)) + { + busWidth = kSDIO_DataBus8Bit; + } + + /* switch data bus width */ + if (((card->cccrflags & kSDIO_CCCRSupportHighSpeed) || ((card->cccrflags & kSDIO_CCCRSupportLowSpeed4Bit) != 0U)) && + (busWidth == kSDIO_DataBus1Bit)) + { + busWidth = kSDIO_DataBus4Bit; + } + + return SDIO_SetDataBusWidth(card, busWidth); +} + +status_t SDIO_SwitchToHighSpeed(sdio_card_t *card) +{ + assert(card); + + uint8_t temp = 0U; + uint32_t retryTimes = SDIO_RETRY_TIMES; + status_t status = kStatus_SDMMC_SDIO_SwitchHighSpeedFail; + + if (card->cccrflags & SDIO_CCCR_SUPPORT_HIGHSPEED) + { + if (kStatus_Success != SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegBusSpeed, 0U, &temp)) + { + return kStatus_SDMMC_TransferFailed; + } + + temp &= ~SDIO_CCCR_BUS_SPEED_MASK; + temp |= SDIO_CCCR_ENABLE_HIGHSPEED_MODE; + + do + { + retryTimes--; + /* enable high speed mode */ + + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegBusSpeed, temp, &temp)) + { + continue; + } + /* either EHS=0 and SHS=0 ,the card is still in default mode */ + if ((temp & 0x03U) == 0x03U) + { + /* high speed mode , set freq to 50MHZ */ + card->busClock_Hz = + SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SD_CLOCK_50MHZ); + status = kStatus_Success; + break; + } + else + { + continue; + } + + } while (retryTimes); + } + else + { + /* default mode 25MHZ */ + card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SD_CLOCK_25MHZ); + status = kStatus_Success; + } + + return status; +} + +static status_t SDIO_SelectBusTiming(sdio_card_t *card) +{ + assert(card); + + uint32_t targetBusFreq = SD_CLOCK_25MHZ; + uint32_t targetTiming = 0U; + uint8_t temp = 0U; + uint32_t supportModeFlag = 0U; + + do + { + switch (card->currentTiming) + { + /* if not select timing mode, sdmmc will handle it automatically*/ + case kSD_TimingSDR12DefaultMode: + case kSD_TimingSDR104Mode: + if ((kSDMMCHOST_SupportSDR104 != SDMMCHOST_NOT_SUPPORT) && + ((card->cccrflags & SDIO_CCCR_SUPPORT_SDR104) == SDIO_CCCR_SUPPORT_SDR104)) + { + card->currentTiming = kSD_TimingSDR104Mode; + targetTiming = SDIO_CCCR_ENABLE_SDR104_MODE; + targetBusFreq = SDMMCHOST_SUPPORT_SDR104_FREQ; + supportModeFlag = SDIO_CCCR_SUPPORT_SDR104; + break; + } + + case kSD_TimingDDR50Mode: + if ((kSDMMCHOST_SupportDDR50 != SDMMCHOST_NOT_SUPPORT) && + ((card->cccrflags & SDIO_CCCR_SUPPORT_DDR50) == SDIO_CCCR_SUPPORT_DDR50)) + { + card->currentTiming = kSD_TimingDDR50Mode; + targetTiming = SDIO_CCCR_ENABLE_DDR50_MODE; + targetBusFreq = SD_CLOCK_50MHZ; + supportModeFlag = SDIO_CCCR_SUPPORT_DDR50; + break; + } + + case kSD_TimingSDR50Mode: + if ((kSDMMCHOST_SupportSDR50 != SDMMCHOST_NOT_SUPPORT) && + ((card->cccrflags & SDIO_CCCR_SUPPORT_SDR50) == SDIO_CCCR_SUPPORT_SDR50)) + { + card->currentTiming = kSD_TimingSDR50Mode; + targetTiming = SDIO_CCCR_ENABLE_SDR50_MODE; + targetBusFreq = SD_CLOCK_100MHZ; + supportModeFlag = SDIO_CCCR_SUPPORT_SDR50; + break; + } + + case kSD_TimingSDR25HighSpeedMode: + if ((card->host.capability.flags & kSDMMCHOST_SupportHighSpeed) && + (card->cccrflags & SDIO_CCCR_SUPPORT_HIGHSPEED) == SDIO_CCCR_SUPPORT_HIGHSPEED) + { + card->currentTiming = kSD_TimingSDR25HighSpeedMode; + targetTiming = SDIO_CCCR_ENABLE_HIGHSPEED_MODE; + targetBusFreq = SD_CLOCK_50MHZ; + supportModeFlag = SDIO_CCCR_SUPPORT_HIGHSPEED; + break; + } + + default: + /* default timing mode */ + card->currentTiming = kSD_TimingSDR12DefaultMode; + return kStatus_Success; + } + + if (kStatus_Success != SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegBusSpeed, 0U, &temp)) + { + return kStatus_SDMMC_TransferFailed; + } + + temp &= ~SDIO_CCCR_BUS_SPEED_MASK; + temp |= targetTiming; + + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegBusSpeed, temp, &temp)) + { + return kStatus_SDMMC_TransferFailed; + } + /* if cannot switch target timing, it will switch continuously until find a valid timing. */ + if ((temp & targetTiming) != targetTiming) + { + /* need add error log here */ + card->cccrflags &= ~supportModeFlag; + continue; + } + + break; + } while (1); + + card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, targetBusFreq); + + /* enable DDR mode if it is the target mode */ + if (card->currentTiming == kSD_TimingDDR50Mode) + { + SDMMCHOST_ENABLE_DDR_MODE(card->host.base, true, 0U); + } + + /* SDR50 and SDR104 mode need tuning */ + if ((card->currentTiming == kSD_TimingSDR50Mode) || (card->currentTiming == kSD_TimingSDR104Mode)) + { + /* config IO strength in IOMUX*/ + if (card->currentTiming == kSD_TimingSDR50Mode) + { + SDMMCHOST_CONFIG_SD_IO(CARD_BUS_FREQ_100MHZ1, CARD_BUS_STRENGTH_7); + } + else + { + SDMMCHOST_CONFIG_SD_IO(CARD_BUS_FREQ_200MHZ, CARD_BUS_STRENGTH_7); + } + /* execute tuning */ + if (SDIO_ExecuteTuning(card) != kStatus_Success) + { + return kStatus_SDMMC_TuningFail; + } + } + else + { + /* set default IO strength to 4 to cover card adapter driver strength difference */ + SDMMCHOST_CONFIG_SD_IO(CARD_BUS_FREQ_100MHZ1, CARD_BUS_STRENGTH_4); + } + + return kStatus_Success; +} + +status_t SDIO_SetDriverStrength(sdio_card_t *card, sd_driver_strength_t driverStrength) +{ + uint8_t strength = 0U, temp = 0U; + + switch (driverStrength) + { + case kSD_DriverStrengthTypeA: + strength = SDIO_CCCR_ENABLE_DRIVER_TYPE_A; + break; + case kSD_DriverStrengthTypeC: + strength = SDIO_CCCR_ENABLE_DRIVER_TYPE_C; + break; + case kSD_DriverStrengthTypeD: + strength = SDIO_CCCR_ENABLE_DRIVER_TYPE_D; + break; + default: + strength = SDIO_CCCR_ENABLE_DRIVER_TYPE_B; + break; + } + + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegDriverStrength, 0U, &temp)) + { + return kStatus_SDMMC_TransferFailed; + } + + temp &= ~SDIO_CCCR_DRIVER_TYPE_MASK; + temp |= strength; + + return SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegDriverStrength, temp, &temp); +} + +status_t SDIO_EnableAsyncInterrupt(sdio_card_t *card, bool enable) +{ + assert(card); + + uint8_t eai = 0U; + + if ((card->cccrflags & SDIO_CCCR_SUPPORT_ASYNC_INT) == 0U) + { + return kStatus_SDMMC_NotSupportYet; + } + + /* load interrupt enable register */ + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegInterruptExtension, 0U, &eai)) + { + return kStatus_SDMMC_TransferFailed; + } + /* if already enable/disable , do not need enable/disable again */ + if (((eai)&SDIO_CCCR_ENABLE_AYNC_INT) == (enable ? SDIO_CCCR_ENABLE_AYNC_INT : 0U)) + { + return kStatus_Success; + } + + /* enable the eai */ + if (enable) + { + eai |= SDIO_CCCR_ENABLE_AYNC_INT; + } + else + { + eai &= ~(SDIO_CCCR_ENABLE_AYNC_INT); + } + + /* write to register */ + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegInterruptExtension, eai, &eai)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +static status_t SDIO_DecodeCIS( + sdio_card_t *card, sdio_func_num_t func, uint8_t *dataBuffer, uint32_t tplCode, uint32_t tplLink) +{ + assert(card); + assert(func <= kSDIO_FunctionNum7); + + if (func == kSDIO_FunctionNum0) + { + /* only decode MANIFID,FUNCID,FUNCE here */ + if (tplCode == SDIO_TPL_CODE_MANIFID) + { + card->commonCIS.mID = dataBuffer[0U] | (dataBuffer[1U] << 8U); + card->commonCIS.mInfo = dataBuffer[2U] | (dataBuffer[3U] << 8U); + } + else if (tplCode == SDIO_TPL_CODE_FUNCID) + { + card->commonCIS.funcID = dataBuffer[0U]; + } + else if (tplCode == SDIO_TPL_CODE_FUNCE) + { + /* max transfer block size and data size */ + card->commonCIS.fn0MaxBlkSize = dataBuffer[1U] | (dataBuffer[2U] << 8U); + /* max transfer speed */ + card->commonCIS.maxTransSpeed = dataBuffer[3U]; + } + else + { + /* reserved here */ + return kStatus_Fail; + } + } + else + { + /* only decode FUNCID,FUNCE here */ + if (tplCode == SDIO_TPL_CODE_FUNCID) + { + card->funcCIS[func].funcID = dataBuffer[0U]; + } + else if (tplCode == SDIO_TPL_CODE_FUNCE) + { + if (tplLink == 0x2A) + { + card->funcCIS[func - 1U].funcInfo = dataBuffer[1U]; + card->funcCIS[func - 1U].ioVersion = dataBuffer[2U]; + card->funcCIS[func - 1U].cardPSN = + dataBuffer[3U] | (dataBuffer[4U] << 8U) | (dataBuffer[5U] << 16U) | (dataBuffer[6U] << 24U); + card->funcCIS[func - 1U].ioCSASize = + dataBuffer[7U] | (dataBuffer[8U] << 8U) | (dataBuffer[9U] << 16U) | (dataBuffer[10U] << 24U); + card->funcCIS[func - 1U].ioCSAProperty = dataBuffer[11U]; + card->funcCIS[func - 1U].ioMaxBlockSize = dataBuffer[12U] | (dataBuffer[13U] << 8U); + card->funcCIS[func - 1U].ioOCR = + dataBuffer[14U] | (dataBuffer[15U] << 8U) | (dataBuffer[16U] << 16U) | (dataBuffer[17U] << 24U); + card->funcCIS[func - 1U].ioOPMinPwr = dataBuffer[18U]; + card->funcCIS[func - 1U].ioOPAvgPwr = dataBuffer[19U]; + card->funcCIS[func - 1U].ioOPMaxPwr = dataBuffer[20U]; + card->funcCIS[func - 1U].ioSBMinPwr = dataBuffer[21U]; + card->funcCIS[func - 1U].ioSBAvgPwr = dataBuffer[22U]; + card->funcCIS[func - 1U].ioSBMaxPwr = dataBuffer[23U]; + card->funcCIS[func - 1U].ioMinBandWidth = dataBuffer[24U] | (dataBuffer[25U] << 8U); + card->funcCIS[func - 1U].ioOptimumBandWidth = dataBuffer[26U] | (dataBuffer[27U] << 8U); + card->funcCIS[func - 1U].ioReadyTimeout = dataBuffer[28U] | (dataBuffer[29U] << 8U); + + card->funcCIS[func - 1U].ioHighCurrentAvgCurrent = dataBuffer[34U] | (dataBuffer[35U] << 8U); + card->funcCIS[func - 1U].ioHighCurrentMaxCurrent = dataBuffer[36U] | (dataBuffer[37U] << 8U); + card->funcCIS[func - 1U].ioLowCurrentAvgCurrent = dataBuffer[38U] | (dataBuffer[39U] << 8U); + card->funcCIS[func - 1U].ioLowCurrentMaxCurrent = dataBuffer[40U] | (dataBuffer[41U] << 8U); + } + else + { + return kStatus_Fail; + } + } + else + { + return kStatus_Fail; + } + } + + return kStatus_Success; +} + +status_t SDIO_ReadCIS(sdio_card_t *card, sdio_func_num_t func, const uint32_t *tupleList, uint32_t tupleNum) +{ + assert(card); + assert(func <= kSDIO_FunctionNum7); + assert(tupleList); + + uint8_t tplCode = 0U; + uint8_t tplLink = 0U; + uint32_t cisPtr = 0U; + uint32_t i = 0U, num = 0U; + bool tupleMatch = false; + + uint8_t dataBuffer[255U] = {0U}; + + /* get the CIS pointer for each function */ + if (func == kSDIO_FunctionNum0) + { + cisPtr = card->commonCISPointer; + } + else + { + cisPtr = card->ioFBR[func - 1U].ioPointerToCIS; + } + + if (0U == cisPtr) + { + return kStatus_SDMMC_SDIO_ReadCISFail; + } + + do + { + if (kStatus_Success != SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, cisPtr++, 0U, &tplCode)) + { + return kStatus_SDMMC_TransferFailed; + } + /* end of chain tuple */ + if (tplCode == 0xFFU) + { + break; + } + + if (tplCode == 0U) + { + continue; + } + + for (i = 0; i < tupleNum; i++) + { + if (tplCode == tupleList[i]) + { + tupleMatch = true; + break; + } + } + + if (kStatus_Success != SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, cisPtr++, 0U, &tplLink)) + { + return kStatus_SDMMC_TransferFailed; + } + /* end of chain tuple */ + if (tplLink == 0xFFU) + { + break; + } + + if (tupleMatch) + { + memset(dataBuffer, 0U, 255U); + for (i = 0; i < tplLink; i++) + { + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, cisPtr++, 0U, &dataBuffer[i])) + { + return kStatus_SDMMC_TransferFailed; + } + } + tupleMatch = false; + /* pharse the data */ + SDIO_DecodeCIS(card, func, dataBuffer, tplCode, tplLink); + /* read finish then return */ + if (++num == tupleNum) + { + break; + } + } + else + { + /* move pointer */ + cisPtr += tplLink; + /* tuple code not match,continue read tuple code */ + continue; + } + } while (1); + return kStatus_Success; +} + +static status_t SDIO_ProbeBusVoltage(sdio_card_t *card) +{ + assert(card); + + uint32_t ocr = 0U; + status_t error = kStatus_Success; + + /* application able to set the supported voltage window */ + if ((card->ocr & SDIO_OCR_VOLTAGE_WINDOW_MASK) != 0U) + { + ocr = card->ocr & SDIO_OCR_VOLTAGE_WINDOW_MASK; + } + else + { + /* 3.3V voltage should be supported as default */ + ocr |= SDMMC_MASK(kSD_OcrVdd29_30Flag) | SDMMC_MASK(kSD_OcrVdd32_33Flag) | SDMMC_MASK(kSD_OcrVdd33_34Flag); + } + + /* allow user select the work voltage, if not select, sdmmc will handle it automatically */ + if (kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) + { + ocr |= SDMMC_MASK(kSD_OcrSwitch18RequestFlag); + } + + do + { + /* card go idle */ + if (kStatus_Success != SDIO_GoIdle(card)) + { + return kStatus_SDMMC_GoIdleFailed; + } + + /* Get IO OCR-CMD5 with arg0 ,set new voltage if needed*/ + if (kStatus_Success != SDIO_SendOperationCondition(card, 0U)) + { + return kStatus_SDMMC_HandShakeOperationConditionFailed; + } + + if (kStatus_Success != SDIO_SendOperationCondition(card, ocr)) + { + return kStatus_SDMMC_InvalidVoltage; + } + + /* check if card support 1.8V */ + if ((card->ocr & SDMMC_MASK(kSD_OcrSwitch18AcceptFlag)) != 0U) + { + error = SDIO_SwitchVoltage(card); + if (kStatus_SDMMC_SwitchVoltageFail == error) + { + break; + } + + if (error == kStatus_SDMMC_SwitchVoltage18VFail33VSuccess) + { + ocr &= ~SDMMC_MASK(kSD_OcrSwitch18RequestFlag); + error = kStatus_Success; + continue; + } + else + { + card->operationVoltage = kCARD_OperationVoltage180V; + break; + } + } + + break; + } while (1U); + + return error; +} + +status_t SDIO_CardInit(sdio_card_t *card) +{ + assert(card); + + if (!card->isHostReady) + { + return kStatus_SDMMC_HostNotReady; + } + /* Identify mode ,set clock to 400KHZ. */ + card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, SDMMC_CLOCK_400KHZ); + SDMMCHOST_SET_CARD_BUS_WIDTH(card->host.base, kSDMMCHOST_DATABUSWIDTH1BIT); + SDMMCHOST_SEND_CARD_ACTIVE(card->host.base, 100U); + + /* get host capability */ + GET_SDMMCHOST_CAPABILITY(card->host.base, &(card->host.capability)); + + if (SDIO_ProbeBusVoltage(card) != kStatus_Success) + { + return kStatus_SDMMC_SwitchVoltageFail; + } + + /* there is a memonly card */ + if ((card->ioTotalNumber == 0U) && (card->memPresentFlag)) + { + return kStatus_SDMMC_SDIO_InvalidCard; + } + + /* send relative address ,cmd3*/ + if (kStatus_Success != SDIO_SendRca(card)) + { + return kStatus_SDMMC_SendRelativeAddressFailed; + } + /* select card cmd7 */ + if (kStatus_Success != SDIO_SelectCard(card, true)) + { + return kStatus_SDMMC_SelectCardFailed; + } + + /* get card capability */ + if (kStatus_Success != SDIO_GetCardCapability(card, kSDIO_FunctionNum0)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* read common CIS here */ + if (SDIO_ReadCIS(card, kSDIO_FunctionNum0, g_tupleList, SDIO_COMMON_CIS_TUPLE_NUM)) + { + return kStatus_SDMMC_SDIO_ReadCISFail; + } + + /* switch data bus width */ + if (kStatus_Success != SDIO_SetMaxDataBusWidth(card)) + { + return kStatus_SDMMC_SetDataBusWidthFailed; + } + + /* trying switch to card support timing mode. */ + if (kStatus_Success != SDIO_SelectBusTiming(card)) + { + return kStatus_SDMMC_SDIO_SwitchHighSpeedFail; + } + + return kStatus_Success; +} + +void SDIO_CardDeinit(sdio_card_t *card) +{ + assert(card); + + SDIO_CardReset(card); + SDIO_SelectCard(card, false); +} + +status_t SDIO_HostInit(sdio_card_t *card) +{ + assert(card); + + if ((!card->isHostReady) && SDMMCHOST_Init(&(card->host), (void *)(&(card->usrParam))) != kStatus_Success) + { + return kStatus_Fail; + } + + /* set the host status flag, after the card re-plug in, don't need init host again */ + card->isHostReady = true; + + SDMMCHOST_ENABLE_SDIO_INT(card->host.base); + + return kStatus_Success; +} + +void SDIO_HostDeinit(sdio_card_t *card) +{ + assert(card); + + SDMMCHOST_Deinit(&(card->host)); + + /* should re-init host */ + card->isHostReady = false; +} + +void SDIO_HostReset(SDMMCHOST_CONFIG *host) +{ + SDMMCHOST_Reset(host->base); +} + +status_t SDIO_WaitCardDetectStatus(SDMMCHOST_TYPE *hostBase, const sdmmchost_detect_card_t *cd, bool waitCardStatus) +{ + return SDMMCHOST_WaitCardDetectStatus(hostBase, cd, waitCardStatus); +} + +bool SDIO_IsCardPresent(sdio_card_t *card) +{ + return SDMMCHOST_IsCardPresent(); +} + +void SDIO_PowerOnCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +{ + SDMMCHOST_PowerOnCard(base, pwr); +} + +void SDIO_PowerOffCard(SDMMCHOST_TYPE *base, const sdmmchost_pwr_card_t *pwr) +{ + SDMMCHOST_PowerOffCard(base, pwr); +} + +status_t SDIO_Init(sdio_card_t *card) +{ + assert(card); + assert(card->host.base); + + if (!card->isHostReady) + { + if (SDIO_HostInit(card) != kStatus_Success) + { + return kStatus_SDMMC_HostNotReady; + } + } + else + { + /* reset the host */ + SDIO_HostReset(&(card->host)); + } + /* power off card */ + SDIO_PowerOffCard(card->host.base, card->usrParam.pwr); + /* card detect */ + if (SDIO_WaitCardDetectStatus(card->host.base, card->usrParam.cd, true) != kStatus_Success) + { + return kStatus_SDMMC_CardDetectFailed; + } + /* power on card */ + SDIO_PowerOnCard(card->host.base, card->usrParam.pwr); + + return SDIO_CardInit(card); +} + +void SDIO_Deinit(sdio_card_t *card) +{ + assert(card); + + SDIO_CardDeinit(card); + SDIO_HostDeinit(card); +} + +status_t SDIO_EnableIOInterrupt(sdio_card_t *card, sdio_func_num_t func, bool enable) +{ + assert(card); + assert(func <= kSDIO_FunctionNum7); + + uint8_t intEn = 0U; + + /* load io interrupt enable register */ + if (kStatus_Success != SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegIOIntEnable, 0U, &intEn)) + { + return kStatus_SDMMC_TransferFailed; + } + + if (enable) + { + /* if already enable , do not need enable again */ + if ((((intEn >> func) & 0x01U) == 0x01U) && (intEn & 0x01U)) + { + return kStatus_Success; + } + + /* enable the interrupt and interrupt master */ + intEn |= (1U << func) | 0x01U; + card->ioIntNums++; + } + else + { + /* if already disable , do not need enable again */ + if (((intEn >> func) & 0x01U) == 0x00U) + { + return kStatus_Success; + } + + /* disable the interrupt, don't disable the interrupt master here */ + intEn &= ~(1U << func); + if (card->ioIntNums) + { + card->ioIntNums--; + } + } + + /* write to register */ + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegIOIntEnable, intEn, &intEn)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t SDIO_GetPendingInterrupt(sdio_card_t *card, uint8_t *pendingInt) +{ + assert(card); + + /* load io interrupt enable register */ + + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegIOIntPending, 0U, pendingInt)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t SDIO_EnableIO(sdio_card_t *card, sdio_func_num_t func, bool enable) +{ + assert(card); + assert(func <= kSDIO_FunctionNum7); + assert(func != kSDIO_FunctionNum0); + + uint8_t ioEn = 0U, ioReady = 0U; + volatile uint32_t i = SDIO_RETRY_TIMES; + uint32_t ioReadyTimeoutMS = card->funcCIS[func - 1U].ioReadyTimeout * SDIO_IO_READY_TIMEOUT_UNIT; + + if (ioReadyTimeoutMS != 0U) + { + /* do not poll the IO ready status, but use IO ready timeout */ + i = 1U; + } + + /* load io enable register */ + if (kStatus_Success != SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegIOEnable, 0U, &ioEn)) + { + return kStatus_SDMMC_TransferFailed; + } + /* if already enable/disable , do not need enable/disable again */ + if (((ioEn >> func) & 0x01U) == (enable ? 1U : 0U)) + { + return kStatus_Success; + } + + /* enable the io */ + if (enable) + { + ioEn |= (1U << func); + } + else + { + ioEn &= ~(1U << func); + } + + /* write to register */ + if (kStatus_Success != SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegIOEnable, ioEn, &ioEn)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* if enable io, need check the IO ready status */ + if (enable) + { + do + { + SDMMCHOST_Delay(ioReadyTimeoutMS); + /* wait IO ready */ + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IORead, kSDIO_FunctionNum0, kSDIO_RegIOReady, 0U, &ioReady)) + { + return kStatus_SDMMC_TransferFailed; + } + /* check if IO ready */ + if ((ioReady & (1 << func)) != 0U) + { + return kStatus_Success; + } + + i--; + } while (i); + + return kStatus_Fail; + } + + return kStatus_Success; +} + +status_t SDIO_SelectIO(sdio_card_t *card, sdio_func_num_t func) +{ + assert(card); + assert(func <= kSDIO_FunctionMemory); + + uint8_t ioSel = func; + + /* write to register */ + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegFunctionSelect, ioSel, &ioSel)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t SDIO_AbortIO(sdio_card_t *card, sdio_func_num_t func) +{ + assert(card); + assert(func <= kSDIO_FunctionNum7); + + uint8_t ioAbort = func; + + /* write to register */ + if (kStatus_Success != + SDIO_IO_RW_Direct(card, kSDIO_IOWrite, kSDIO_FunctionNum0, kSDIO_RegIOAbort, ioAbort, &ioAbort)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +void SDIO_SetIOIRQHandler(sdio_card_t *card, sdio_func_num_t func, sdio_io_irq_handler_t handler) +{ + assert(card); + assert((func <= kSDIO_FunctionNum7) && (func != kSDIO_FunctionNum0)); + + card->ioIRQHandler[func - 1] = handler; + card->ioIntIndex = func; +} + +status_t SDIO_HandlePendingIOInterrupt(sdio_card_t *card) +{ + assert(card); + + uint8_t i = 0, pendingInt = 0; + + /* call IRQ handler directly if one IRQ handler only */ + if (card->ioIntNums == 1U) + { + if (card->ioIRQHandler[card->ioIntIndex - 1]) + { + (card->ioIRQHandler[card->ioIntIndex - 1])(card, card->ioIntIndex); + } + } + else + { + /* get pending int firstly */ + if (SDIO_GetPendingInterrupt(card, &pendingInt) != kStatus_Success) + { + return kStatus_SDMMC_TransferFailed; + } + + for (i = 1; i <= FSL_SDIO_MAX_IO_NUMS; i++) + { + if (pendingInt & (1 << i)) + { + if (card->ioIRQHandler[i - 1]) + { + (card->ioIRQHandler[i - 1])(card, i); + } + } + } + } + + return kStatus_Success; +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sdmmc_common.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sdmmc_common.c new file mode 100644 index 000000000..9a0926557 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sdmmc_common.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_sdmmc_common.h" +/******************************************************************************* + * Variables + ******************************************************************************/ +SDK_ALIGN(uint32_t g_sdmmc[SDK_SIZEALIGN(SDMMC_GLOBAL_BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)], + MAX(SDMMC_DATA_BUFFER_ALIGN_CACHE, SDMMCHOST_DMA_BUFFER_ADDR_ALIGN)); +/******************************************************************************* + * Code + ******************************************************************************/ +status_t SDMMC_SelectCard(SDMMCHOST_TYPE *base, + SDMMCHOST_TRANSFER_FUNCTION transfer, + uint32_t relativeAddress, + bool isSelected) +{ + assert(transfer); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + + command.index = kSDMMC_SelectCard; + if (isSelected) + { + command.argument = relativeAddress << 16U; + command.responseType = kCARD_ResponseTypeR1; + } + else + { + command.argument = 0U; + command.responseType = kCARD_ResponseTypeNone; + } + + content.command = &command; + content.data = NULL; + if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG)) + { + return kStatus_SDMMC_TransferFailed; + } + + /* Wait until card to transfer state */ + return kStatus_Success; +} + +status_t SDMMC_SendApplicationCommand(SDMMCHOST_TYPE *base, + SDMMCHOST_TRANSFER_FUNCTION transfer, + uint32_t relativeAddress) +{ + assert(transfer); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + + command.index = kSDMMC_ApplicationCommand; + command.argument = (relativeAddress << 16U); + command.responseType = kCARD_ResponseTypeR1; + + content.command = &command; + content.data = 0U; + if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG)) + { + return kStatus_SDMMC_TransferFailed; + } + + if (!(command.response[0U] & SDMMC_MASK(kSDMMC_R1ApplicationCommandFlag))) + { + return kStatus_SDMMC_CardNotSupport; + } + + return kStatus_Success; +} + +status_t SDMMC_SetBlockCount(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer, uint32_t blockCount) +{ + assert(transfer); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + + command.index = kSDMMC_SetBlockCount; + command.argument = blockCount; + command.responseType = kCARD_ResponseTypeR1; + + content.command = &command; + content.data = 0U; + if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t SDMMC_GoIdle(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer) +{ + assert(transfer); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + + command.index = kSDMMC_GoIdleState; + + content.command = &command; + content.data = 0U; + if (kStatus_Success != transfer(base, &content)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t SDMMC_SetBlockSize(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer, uint32_t blockSize) +{ + assert(transfer); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + + command.index = kSDMMC_SetBlockLength; + command.argument = blockSize; + command.responseType = kCARD_ResponseTypeR1; + + content.command = &command; + content.data = 0U; + if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & SDMMC_R1_ALL_ERROR_FLAG)) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t SDMMC_SetCardInactive(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer) +{ + assert(transfer); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + + command.index = kSDMMC_GoInactiveState; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeNone; + + content.command = &command; + content.data = 0U; + if ((kStatus_Success != transfer(base, &content))) + { + return kStatus_SDMMC_TransferFailed; + } + + return kStatus_Success; +} + +status_t SDMMC_SwitchVoltage(SDMMCHOST_TYPE *base, SDMMCHOST_TRANSFER_FUNCTION transfer) +{ + assert(transfer); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + status_t error = kStatus_Success; + + if (kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) + { + command.index = kSD_VoltageSwitch; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR1; + + content.command = &command; + content.data = NULL; + if (kStatus_Success != transfer(base, &content)) + { + return kStatus_SDMMC_TransferFailed; + } + /* disable card clock */ + SDMMCHOST_ENABLE_CARD_CLOCK(base, false); + + /* check data line and cmd line status */ + if ((GET_SDMMCHOST_STATUS(base) & + (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY)) != 0U) + { + return kStatus_SDMMC_SwitchVoltageFail; + } + + /* host switch to 1.8V */ + SDMMCHOST_SWITCH_VOLTAGE180V(base, true); + + SDMMCHOST_Delay(100U); + + /*enable sd clock*/ + SDMMCHOST_ENABLE_CARD_CLOCK(base, true); + /*enable force clock on*/ + SDMMCHOST_FORCE_SDCLOCK_ON(base, true); + /* dealy 1ms,not exactly correct when use while */ + SDMMCHOST_Delay(10U); + /*disable force clock on*/ + SDMMCHOST_FORCE_SDCLOCK_ON(base, false); + + /* check data line and cmd line status */ + if ((GET_SDMMCHOST_STATUS(base) & + (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY)) == 0U) + { + error = kStatus_SDMMC_SwitchVoltageFail; + /* power reset the card */ + SDMMCHOST_ENABLE_SD_POWER(false); + SDMMCHOST_Delay(10U); + SDMMCHOST_ENABLE_SD_POWER(true); + SDMMCHOST_Delay(10U); + /* re-check the data line status */ + if ((GET_SDMMCHOST_STATUS(base) & + (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY))) + { + error = kStatus_SDMMC_SwitchVoltage18VFail33VSuccess; + SDMMC_LOG( + "\r\nNote: Current card support 1.8V, but board don't support, so sdmmc switch back to 3.3V."); + } + else + { + SDMMC_LOG( + "\r\nError: Current card support 1.8V, but board don't support, sdmmc tried to switch back\ + to 3.3V, but failed, please check board setting."); + } + } + + return error; + } + else + { + return kStatus_SDMMC_HostNotSupport; + } +} + +status_t SDMMC_SwitchToVoltage(SDMMCHOST_TYPE *base, + SDMMCHOST_TRANSFER_FUNCTION transfer, + sdmmchost_card_switch_voltage_t switchVoltageFunc) +{ + assert(transfer); + + SDMMCHOST_TRANSFER content = {0}; + SDMMCHOST_COMMAND command = {0}; + status_t error = kStatus_Success; + + if (kSDMMCHOST_SupportV180 != SDMMCHOST_NOT_SUPPORT) + { + command.index = kSD_VoltageSwitch; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR1; + + content.command = &command; + content.data = NULL; + if (kStatus_Success != transfer(base, &content)) + { + return kStatus_SDMMC_TransferFailed; + } + /* disable card clock */ + SDMMCHOST_ENABLE_CARD_CLOCK(base, false); + + /* check data line and cmd line status */ + if ((GET_SDMMCHOST_STATUS(base) & + (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY)) != 0U) + { + return kStatus_SDMMC_SwitchVoltageFail; + } + + if (switchVoltageFunc != NULL) + { + switchVoltageFunc(); + } + else + { + /* host switch to 1.8V */ + SDMMCHOST_SWITCH_VOLTAGE180V(base, true); + } + + SDMMCHOST_Delay(100U); + + /*enable sd clock*/ + SDMMCHOST_ENABLE_CARD_CLOCK(base, true); + /*enable force clock on*/ + SDMMCHOST_FORCE_SDCLOCK_ON(base, true); + /* dealy 1ms,not exactly correct when use while */ + SDMMCHOST_Delay(10U); + /*disable force clock on*/ + SDMMCHOST_FORCE_SDCLOCK_ON(base, false); + + /* check data line and cmd line status */ + if ((GET_SDMMCHOST_STATUS(base) & + (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY)) == 0U) + { + error = kStatus_SDMMC_SwitchVoltageFail; + /* power reset the card */ + SDMMCHOST_ENABLE_SD_POWER(false); + SDMMCHOST_Delay(10U); + SDMMCHOST_ENABLE_SD_POWER(true); + SDMMCHOST_Delay(10U); + /* re-check the data line status */ + if ((GET_SDMMCHOST_STATUS(base) & + (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY))) + { + error = kStatus_SDMMC_SwitchVoltage18VFail33VSuccess; + SDMMC_LOG( + "\r\nNote: Current card support 1.8V, but board don't support, so sdmmc switch back to 3.3V."); + } + else + { + SDMMC_LOG( + "\r\nError: Current card support 1.8V, but board don't support, sdmmc tried to switch back\ + to 3.3V, but failed, please check board setting."); + } + } + + return error; + } + else + { + return kStatus_SDMMC_HostNotSupport; + } +} + +status_t SDMMC_ExecuteTuning(SDMMCHOST_TYPE *base, + SDMMCHOST_TRANSFER_FUNCTION transfer, + uint32_t tuningCmd, + uint32_t blockSize) +{ + SDMMCHOST_TRANSFER content = {0U}; + SDMMCHOST_COMMAND command = {0U}; + SDMMCHOST_DATA data = {0U}; + uint32_t buffer[32U] = {0U}; + bool tuningError = true; + + command.index = tuningCmd; + command.argument = 0U; + command.responseType = kCARD_ResponseTypeR1; + + data.blockSize = blockSize; + data.blockCount = 1U; + data.rxData = buffer; + /* add this macro for adpter to different driver */ + SDMMCHOST_ENABLE_TUNING_FLAG(data); + + content.command = &command; + content.data = &data; + + /* enable the standard tuning */ + SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, true); + + while (true) + { + /* send tuning block */ + if ((kStatus_Success != transfer(base, &content))) + { + return kStatus_SDMMC_TransferFailed; + } + SDMMCHOST_Delay(1U); + + /*wait excute tuning bit clear*/ + if ((SDMMCHOST_EXECUTE_STANDARD_TUNING_STATUS(base) != 0U)) + { + continue; + } + + /* if tuning error , re-tuning again */ + if ((SDMMCHOST_CHECK_TUNING_ERROR(base) != 0U) && tuningError) + { + tuningError = false; + /* enable the standard tuning */ + SDMMCHOST_EXECUTE_STANDARD_TUNING_ENABLE(base, true); + SDMMCHOST_ADJUST_TUNING_DELAY(base, SDMMCHOST_STANDARD_TUNING_START); + } + else + { + break; + } + } + + /* check tuning result*/ + if (SDMMCHOST_EXECUTE_STANDARD_TUNING_RESULT(base) == 0U) + { + return kStatus_SDMMC_TuningFail; + } + +#if !SDMMC_ENABLE_SOFTWARE_TUNING + SDMMCHOST_AUTO_TUNING_ENABLE(base, true); +#endif + + return kStatus_Success; +} diff --git a/Ubiquitous/XiUOS/path_kernel.mk b/Ubiquitous/XiUOS/path_kernel.mk index a618d3ad3..58dc83c47 100755 --- a/Ubiquitous/XiUOS/path_kernel.mk +++ b/Ubiquitous/XiUOS/path_kernel.mk @@ -174,6 +174,8 @@ KERNELPATHS :=-I$(BSP_ROOT) \ -I$(KERNEL_ROOT)/arch/arm/cortex-m7 \ -I$(BSP_ROOT)/third_party_driver \ -I$(BSP_ROOT)/third_party_driver/include \ + -I$(BSP_ROOT)/third_party_driver/sdio/sdmmc/inc \ + -I$(BSP_ROOT)/third_party_driver/sdio/sdmmc/port \ -I$(BSP_ROOT)/third_party_driver/ethernet \ -I$(BSP_ROOT)/third_party_driver/ethernet/ksz8081 \ -I$(BSP_ROOT)/third_party_driver/MIMXRT1052 \