From 7b32e213ce2d424225ad0af56f0d67f5605da063 Mon Sep 17 00:00:00 2001 From: Liu_Weichao Date: Wed, 26 Jan 2022 17:14:43 +0800 Subject: [PATCH 1/5] add sd card driver part for ok1052-c board --- .../Applications/app_test/test_adc.c | 4 +- Ubiquitous/XiUOS/board/ok1052-c/board.c | 31 +- .../board/ok1052-c/third_party_driver/Kconfig | 11 +- .../ok1052-c/third_party_driver/Makefile | 4 + .../third_party_driver/common/Makefile | 4 + .../third_party_driver/common/pin_mux.c | 114 + .../third_party_driver/include/connect_sdio.h | 41 + .../third_party_driver/include/fsl_common.h | 12 - .../{semc => include}/fsl_semc.h | 0 .../ok1052-c/third_party_driver/sdio/Kconfig | 13 + .../ok1052-c/third_party_driver/sdio/Makefile | 5 + .../third_party_driver/sdio/connect_sdio.c | 409 +++ .../third_party_driver/sdio/sdmmc/Makefile | 3 + .../sdio/sdmmc/inc/fsl_mmc.h | 321 ++ .../sdio/sdmmc/inc/fsl_sd.h | 315 ++ .../sdio/sdmmc/inc/fsl_sdio.h | 507 ++++ .../sdio/sdmmc/inc/fsl_sdmmc_common.h | 258 ++ .../sdio/sdmmc/inc/fsl_sdmmc_host.h | 780 +++++ .../sdio/sdmmc/inc/fsl_sdmmc_spec.h | 1215 ++++++++ .../sdio/sdmmc/port/Makefile | 3 + .../sdio/sdmmc/port/fsl_sdmmc_event.h | 87 + .../sdio/sdmmc/port/usdhc/Makefile | 3 + .../sdio/sdmmc/port/usdhc/interrupt/Makefile | 3 + .../port/usdhc/interrupt/fsl_sdmmc_event.c | 151 + .../port/usdhc/interrupt/fsl_sdmmc_host.c | 437 +++ .../sdio/sdmmc/port/usdhc/polling/Makefile | 3 + .../port/usdhc/polling/fsl_sdmmc_event.c | 154 + .../sdmmc/port/usdhc/polling/fsl_sdmmc_host.c | 290 ++ .../sdio/sdmmc/src/Makefile | 3 + .../sdio/sdmmc/src/fsl_mmc.c | 2671 +++++++++++++++++ .../sdio/sdmmc/src/fsl_sd.c | 1982 ++++++++++++ .../sdio/sdmmc/src/fsl_sdio.c | 1700 +++++++++++ .../sdio/sdmmc/src/fsl_sdmmc_common.c | 393 +++ Ubiquitous/XiUOS/path_kernel.mk | 2 + 34 files changed, 11901 insertions(+), 28 deletions(-) create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_sdio.h rename Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/{semc => include}/fsl_semc.h (100%) create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/Kconfig create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/connect_sdio.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_mmc.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sd.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdio.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdmmc_common.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdmmc_host.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/inc/fsl_sdmmc_spec.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/fsl_sdmmc_event.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/fsl_sdmmc_event.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/interrupt/fsl_sdmmc_host.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/fsl_sdmmc_event.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/port/usdhc/polling/fsl_sdmmc_host.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_mmc.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sd.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sdio.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/sdio/sdmmc/src/fsl_sdmmc_common.c 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 \ From d7507bcd6e03452ac87ac95017e9fa4aa73bb41a Mon Sep 17 00:00:00 2001 From: Liu_Weichao Date: Tue, 8 Feb 2022 16:53:47 +0800 Subject: [PATCH 2/5] feat support sdio read/write/configure function --- Ubiquitous/XiUOS/board/ok1052-c/Kconfig | 7 + Ubiquitous/XiUOS/board/ok1052-c/board.c | 24 +- .../third_party_driver/common/fsl_usdhc.c | 2016 +++++++++++++++++ .../third_party_driver/include/fsl_usdhc.h | 1493 ++++++++++++ .../third_party_driver/sdio/connect_sdio.c | 84 +- 5 files changed, 3557 insertions(+), 67 deletions(-) create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_usdhc.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_usdhc.h diff --git a/Ubiquitous/XiUOS/board/ok1052-c/Kconfig b/Ubiquitous/XiUOS/board/ok1052-c/Kconfig index 392b37362..751c27a47 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/Kconfig +++ b/Ubiquitous/XiUOS/board/ok1052-c/Kconfig @@ -40,6 +40,13 @@ menu "ok1052-c feature" int "stack size for interrupt" default 4096 + menu "config board peripheral" + config MOUNT_SDCARD + bool "mount cd card" + default n + select BSP_USING_SDIO + endmenu + endmenu diff --git a/Ubiquitous/XiUOS/board/ok1052-c/board.c b/Ubiquitous/XiUOS/board/ok1052-c/board.c index 52d410412..bea4a887c 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/board.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/board.c @@ -40,6 +40,24 @@ extern int ExtSramInit(void); #endif #endif +#if defined(FS_VFS) && defined(MOUNT_SDCARD) +#include + +/** + * @description: Mount SD card + * @return 0 + */ +int MountSDCard(void) +{ + if (MountFilesystem(SDIO_BUS_NAME, SDIO_DEVICE_NAME, SDIO_DRIVER_NAME, FSTYPE_FATFS, "/") == 0) + KPrintf("sd card mount to '/'"); + else + KPrintf("sd card mount to '/' failed!"); + + return 0; +} +#endif + #if defined(SDK_I2C_BASED_COMPONENT_USED) && SDK_I2C_BASED_COMPONENT_USED #include "fsl_lpi2c.h" #endif /* SDK_I2C_BASED_COMPONENT_USED */ @@ -624,13 +642,11 @@ void InitBoardHardware() CLOCK_SetMux(kCLOCK_SemcMux, 1); CLOCK_SetDiv(kCLOCK_SemcDiv, 1); - if (BOARD_InitSEMC() != kStatus_Success) - { + if (BOARD_InitSEMC() != kStatus_Success) { KPrintf("\r\n SEMC Init Failed\r\n"); } #ifdef MEM_EXTERN_SRAM - else - { + else { ExtSramInit(); } #endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_usdhc.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_usdhc.c new file mode 100644 index 000000000..191b7d104 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_usdhc.c @@ -0,0 +1,2016 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_usdhc.h" +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL +#include "fsl_cache.h" +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.usdhc" +#endif + +/*! @brief Clock setting */ +/* Max SD clock divisor from base clock */ +#define USDHC_MAX_DVS ((USDHC_SYS_CTRL_DVS_MASK >> USDHC_SYS_CTRL_DVS_SHIFT) + 1U) +#define USDHC_MAX_CLKFS ((USDHC_SYS_CTRL_SDCLKFS_MASK >> USDHC_SYS_CTRL_SDCLKFS_SHIFT) + 1U) +#define USDHC_PREV_DVS(x) ((x) -= 1U) +#define USDHC_PREV_CLKFS(x, y) ((x) >>= (y)) +/*! @brief USDHC ADMA table address align size */ +#define USDHC_ADMA_TABLE_ADDRESS_ALIGN (4U) + +/* Typedef for interrupt handler. */ +typedef void (*usdhc_isr_t)(USDHC_Type *base, usdhc_handle_t *handle); +/*! @brief Dummy data buffer for mmc boot mode */ +AT_NONCACHEABLE_SECTION_ALIGN(uint32_t s_usdhcBootDummy, USDHC_ADMA2_ADDRESS_ALIGN); +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief Get the instance. + * + * @param base USDHC peripheral base address. + * @return Instance number. + */ +static uint32_t USDHC_GetInstance(USDHC_Type *base); + +/*! + * @brief Set transfer interrupt. + * + * @param base USDHC peripheral base address. + * @param usingInterruptSignal True to use IRQ signal. + */ +static void USDHC_SetTransferInterrupt(USDHC_Type *base, bool usingInterruptSignal); + +/*! + * @brief Start transfer according to current transfer state + * + * @param base USDHC peripheral base address. + * @param data Data to be transferred. + * @param flag data present flag + * @param enDMA DMA enable flag + */ +static status_t USDHC_SetDataTransferConfig(USDHC_Type *base, + usdhc_data_t *data, + uint32_t *dataPresentFlag, + bool enDMA); + +/*! + * @brief Receive command response + * + * @param base USDHC peripheral base address. + * @param command Command to be sent. + */ +static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command); + +/*! + * @brief Read DATAPORT when buffer enable bit is set. + * + * @param base USDHC peripheral base address. + * @param data Data to be read. + * @param transferredWords The number of data words have been transferred last time transaction. + * @return The number of total data words have been transferred after this time transaction. + */ +static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords); + +/*! + * @brief Read data by using DATAPORT polling way. + * + * @param base USDHC peripheral base address. + * @param data Data to be read. + * @retval kStatus_Fail Read DATAPORT failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data); + +/*! + * @brief Write DATAPORT when buffer enable bit is set. + * + * @param base USDHC peripheral base address. + * @param data Data to be read. + * @param transferredWords The number of data words have been transferred last time. + * @return The number of total data words have been transferred after this time transaction. + */ +static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords); + +/*! + * @brief Write data by using DATAPORT polling way. + * + * @param base USDHC peripheral base address. + * @param data Data to be transferred. + * @retval kStatus_Fail Write DATAPORT failed. + * @retval kStatus_Success Operate successfully. + */ +static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data); + +/*! + * @brief Transfer data by polling way. + * + * @param base USDHC peripheral base address. + * @param data Data to be transferred. + * @param use DMA flag. + * @retval kStatus_Fail Transfer data failed. + * @retval kStatus_InvalidArgument Argument is invalid. + * @retval kStatus_Success Operate successfully. + */ +static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA); + +/*! + * @brief Handle card detect interrupt. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle. + * @param interruptFlags Card detect related interrupt flags. + */ +static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags); + +/*! + * @brief Handle command interrupt. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle. + * @param interruptFlags Command related interrupt flags. + */ +static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags); + +/*! + * @brief Handle data interrupt. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle. + * @param interruptFlags Data related interrupt flags. + */ +static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags); + +/*! + * @brief Handle SDIO card interrupt signal. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle. + */ +static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle); + +/*! + * @brief Handle SDIO block gap event. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle. + */ +static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle); + +/*! + * @brief Handle retuning + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle. + * @param interrupt flags + */ +static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags); + +/*! + * @brief wait command done + * + * @param base USDHC peripheral base address. + * @param command configuration + * @param pollingCmdDone polling command done flag + */ +static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief USDHC base pointer array */ +static USDHC_Type *const s_usdhcBase[] = USDHC_BASE_PTRS; + +/*! @brief USDHC internal handle pointer array */ +static usdhc_handle_t *s_usdhcHandle[ARRAY_SIZE(s_usdhcBase)] = {NULL}; + +/*! @brief USDHC IRQ name array */ +static const IRQn_Type s_usdhcIRQ[] = USDHC_IRQS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief USDHC clock array name */ +static const clock_ip_name_t s_usdhcClock[] = USDHC_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/* USDHC ISR for transactional APIs. */ +static usdhc_isr_t s_usdhcIsr; + +/******************************************************************************* + * Code + ******************************************************************************/ +static uint32_t USDHC_GetInstance(USDHC_Type *base) +{ + uint8_t instance = 0; + + while ((instance < ARRAY_SIZE(s_usdhcBase)) && (s_usdhcBase[instance] != base)) + { + instance++; + } + + assert(instance < ARRAY_SIZE(s_usdhcBase)); + + return instance; +} + +static void USDHC_SetTransferInterrupt(USDHC_Type *base, bool usingInterruptSignal) +{ + uint32_t interruptEnabled; /* The Interrupt status flags to be enabled */ + + /* Disable all interrupts */ + USDHC_DisableInterruptStatus(base, (uint32_t)kUSDHC_AllInterruptFlags); + USDHC_DisableInterruptSignal(base, (uint32_t)kUSDHC_AllInterruptFlags); + DisableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]); + + interruptEnabled = (kUSDHC_CommandFlag | kUSDHC_CardInsertionFlag | kUSDHC_DataFlag | kUSDHC_CardRemovalFlag | + kUSDHC_SDR104TuningFlag | kUSDHC_BlockGapEventFlag); + + USDHC_EnableInterruptStatus(base, interruptEnabled); + + if (usingInterruptSignal) + { + USDHC_EnableInterruptSignal(base, interruptEnabled); + } +} + +static status_t USDHC_SetDataTransferConfig(USDHC_Type *base, usdhc_data_t *data, uint32_t *dataPresentFlag, bool enDMA) +{ + uint32_t mixCtrl = base->MIX_CTRL; + + if (data != NULL) + { + /* if transfer boot continous, only need set the CREQ bit, leave others as it is */ + if (data->dataType == kUSDHC_TransferDataBootcontinous) + { + /* clear stop at block gap request */ + base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK; + /* continous transfer data */ + base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK; + return kStatus_Success; + } + + /* check data inhibit flag */ + if (base->PRES_STATE & kUSDHC_DataInhibitFlag) + { + return kStatus_USDHC_BusyTransferring; + } + /* check transfer block count */ + if ((data->blockCount > USDHC_MAX_BLOCK_COUNT) || ((data->txData == NULL) && (data->rxData == NULL))) + { + return kStatus_InvalidArgument; + } + + /* config mix parameter */ + mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK | + USDHC_MIX_CTRL_AC12EN_MASK); + + if (data->rxData) + { + mixCtrl |= USDHC_MIX_CTRL_DTDSEL_MASK; + } + if (data->blockCount > 1U) + { + mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK; + /* auto command 12 */ + if (data->enableAutoCommand12) + { + mixCtrl |= USDHC_MIX_CTRL_AC12EN_MASK; + } + } + + /* auto command 23, auto send set block count cmd before multiple read/write */ + if ((data->enableAutoCommand23)) + { + mixCtrl |= USDHC_MIX_CTRL_AC23EN_MASK; + base->VEND_SPEC2 |= USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK; + /* config the block count to DS_ADDR */ + base->DS_ADDR = data->blockCount; + } + else + { + mixCtrl &= ~USDHC_MIX_CTRL_AC23EN_MASK; + base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK; + } + + /* if transfer boot data, leave the block count to USDHC_SetMmcBootConfig function */ + if (data->dataType != kUSDHC_TransferDataBoot) + { + /* config data block size/block count */ + base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) | + (USDHC_BLK_ATT_BLKSIZE(data->blockSize) | USDHC_BLK_ATT_BLKCNT(data->blockCount))); + } + else + { + mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK; + base->PROT_CTRL |= USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK; + } + + /* data present flag */ + *dataPresentFlag |= kUSDHC_DataPresentFlag; + /* Disable useless interrupt */ + if (enDMA) + { + base->INT_SIGNAL_EN &= ~(kUSDHC_BufferWriteReadyFlag | kUSDHC_BufferReadReadyFlag | kUSDHC_DmaCompleteFlag); + base->INT_STATUS_EN &= ~(kUSDHC_BufferWriteReadyFlag | kUSDHC_BufferReadReadyFlag | kUSDHC_DmaCompleteFlag); + } + else + { + base->INT_SIGNAL_EN |= kUSDHC_BufferWriteReadyFlag | kUSDHC_BufferReadReadyFlag; + base->INT_STATUS_EN |= kUSDHC_BufferWriteReadyFlag | kUSDHC_BufferReadReadyFlag; + } + } + else + { + /* clear data flags */ + mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK | + USDHC_MIX_CTRL_AC12EN_MASK | USDHC_MIX_CTRL_AC23EN_MASK); + + if (base->PRES_STATE & kUSDHC_CommandInhibitFlag) + { + return kStatus_USDHC_BusyTransferring; + } + } + + /* config the mix parameter */ + base->MIX_CTRL = mixCtrl; + + return kStatus_Success; +} + +static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command) +{ + assert(command != NULL); + + if (command->responseType != kCARD_ResponseTypeNone) + { + command->response[0U] = base->CMD_RSP0; + if (command->responseType == kCARD_ResponseTypeR2) + { + /* R3-R2-R1-R0(lowest 8 bit is invalid bit) has the same format as R2 format in SD specification document + after removed internal CRC7 and end bit. */ + command->response[0U] <<= 8U; + command->response[1U] = (base->CMD_RSP1 << 8U) | ((base->CMD_RSP0 & 0xFF000000U) >> 24U); + command->response[2U] = (base->CMD_RSP2 << 8U) | ((base->CMD_RSP1 & 0xFF000000U) >> 24U); + command->response[3U] = (base->CMD_RSP3 << 8U) | ((base->CMD_RSP2 & 0xFF000000U) >> 24U); + } + } + + /* check response error flag */ + if ((command->responseErrorFlags != 0U) && + ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR1b) || + (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR5))) + { + if (((command->responseErrorFlags) & (command->response[0U])) != 0U) + { + return kStatus_USDHC_SendCommandFailed; + } + } + + return kStatus_Success; +} + +static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords) +{ + uint32_t i; + uint32_t totalWords; + uint32_t wordsCanBeRead; /* The words can be read at this time. */ + uint32_t readWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_RD_WML_MASK) >> USDHC_WTMK_LVL_RD_WML_SHIFT); + + /* If DMA is enable, do not need to polling data port */ + if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U) + { + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (data->blockSize % sizeof(uint32_t) != 0U) + { + data->blockSize += + sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */ + } + + totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t)); + + /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */ + if (readWatermark >= totalWords) + { + wordsCanBeRead = totalWords; + } + /* If watermark level is less than totalWords and left words to be sent is equal or bigger than readWatermark, + transfers watermark level words. */ + else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark)) + { + wordsCanBeRead = readWatermark; + } + /* If watermark level is less than totalWords and left words to be sent is less than readWatermark, transfers + left + words. */ + else + { + wordsCanBeRead = (totalWords - transferredWords); + } + + i = 0U; + while (i < wordsCanBeRead) + { + data->rxData[transferredWords++] = USDHC_ReadData(base); + i++; + } + } + + return transferredWords; +} + +static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data) +{ + uint32_t totalWords; + uint32_t transferredWords = 0U, interruptStatus = 0U; + status_t error = kStatus_Success; + + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (data->blockSize % sizeof(uint32_t) != 0U) + { + data->blockSize += + sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */ + } + + totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t)); + + while ((error == kStatus_Success) && (transferredWords < totalWords)) + { + while (!(interruptStatus & (kUSDHC_BufferReadReadyFlag | kUSDHC_DataErrorFlag | kUSDHC_TuningErrorFlag))) + { + interruptStatus = USDHC_GetInterruptStatusFlags(base); + } + + /* during std tuning process, software do not need to read data, but wait BRR is enough */ + if ((data->dataType == kUSDHC_TransferDataTuning) && (interruptStatus & kUSDHC_BufferReadReadyFlag)) + { + USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag | kUSDHC_TuningPassFlag); + + return kStatus_Success; + } + else if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U) + { + USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag); + /* if tuning error occur ,return directly */ + error = kStatus_USDHC_TuningError; + } + else if ((interruptStatus & kUSDHC_DataErrorFlag) != 0U) + { + if (!(data->enableIgnoreError)) + { + error = kStatus_Fail; + } + /* clear data error flag */ + USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag); + } + else + { + } + + if (error == kStatus_Success) + { + transferredWords = USDHC_ReadDataPort(base, data, transferredWords); + /* clear buffer read ready */ + USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag); + interruptStatus = 0U; + } + } + + /* Clear data complete flag after the last read operation. */ + USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataCompleteFlag); + + return error; +} + +static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords) +{ + uint32_t i; + uint32_t totalWords; + uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */ + uint32_t writeWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_WR_WML_MASK) >> USDHC_WTMK_LVL_WR_WML_SHIFT); + + /* If DMA is enable, do not need to polling data port */ + if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U) + { + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (data->blockSize % sizeof(uint32_t) != 0U) + { + data->blockSize += + sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */ + } + + totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t)); + + /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/ + if (writeWatermark >= totalWords) + { + wordsCanBeWrote = totalWords; + } + /* If watermark level is less than totalWords and left words to be sent is equal or bigger than watermark, + transfers watermark level words. */ + else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark)) + { + wordsCanBeWrote = writeWatermark; + } + /* If watermark level is less than totalWords and left words to be sent is less than watermark, transfers left + words. */ + else + { + wordsCanBeWrote = (totalWords - transferredWords); + } + + i = 0U; + while (i < wordsCanBeWrote) + { + USDHC_WriteData(base, data->txData[transferredWords++]); + i++; + } + } + + return transferredWords; +} + +static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data) +{ + uint32_t totalWords; + + uint32_t transferredWords = 0U, interruptStatus = 0U; + status_t error = kStatus_Success; + + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (data->blockSize % sizeof(uint32_t) != 0U) + { + data->blockSize += + sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */ + } + + totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t); + + while ((error == kStatus_Success) && (transferredWords < totalWords)) + { + while (!(interruptStatus & (kUSDHC_BufferWriteReadyFlag | kUSDHC_DataErrorFlag | kUSDHC_TuningErrorFlag))) + { + interruptStatus = USDHC_GetInterruptStatusFlags(base); + } + + if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U) + { + USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag); + /* if tuning error occur ,return directly */ + return kStatus_USDHC_TuningError; + } + else if ((interruptStatus & kUSDHC_DataErrorFlag) != 0U) + { + if (!(data->enableIgnoreError)) + { + error = kStatus_Fail; + } + /* clear data error flag */ + USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag); + } + else + { + } + + if (error == kStatus_Success) + { + transferredWords = USDHC_WriteDataPort(base, data, transferredWords); + /* clear buffer write ready */ + USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferWriteReadyFlag); + interruptStatus = 0U; + } + } + + /* Wait write data complete or data transfer error after the last writing operation. */ + while (!(interruptStatus & (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag))) + { + interruptStatus = USDHC_GetInterruptStatusFlags(base); + } + + if ((interruptStatus & kUSDHC_DataErrorFlag) != 0U) + { + if (!(data->enableIgnoreError)) + { + error = kStatus_Fail; + } + } + USDHC_ClearInterruptStatusFlags(base, (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag)); + + return error; +} + +/*! + * brief send command function + * + * param base USDHC peripheral base address. + * param command configuration + */ +void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command) +{ + assert(NULL != command); + + uint32_t xferType = base->CMD_XFR_TYP, flags = command->flags; + + if (((base->PRES_STATE & kUSDHC_CommandInhibitFlag) == 0U) && (command->type != kCARD_CommandTypeEmpty)) + { + /* Define the flag corresponding to each response type. */ + switch (command->responseType) + { + case kCARD_ResponseTypeNone: + break; + case kCARD_ResponseTypeR1: /* Response 1 */ + case kCARD_ResponseTypeR5: /* Response 5 */ + case kCARD_ResponseTypeR6: /* Response 6 */ + case kCARD_ResponseTypeR7: /* Response 7 */ + flags |= (kUSDHC_ResponseLength48Flag | kUSDHC_EnableCrcCheckFlag | kUSDHC_EnableIndexCheckFlag); + break; + + case kCARD_ResponseTypeR1b: /* Response 1 with busy */ + case kCARD_ResponseTypeR5b: /* Response 5 with busy */ + flags |= (kUSDHC_ResponseLength48BusyFlag | kUSDHC_EnableCrcCheckFlag | kUSDHC_EnableIndexCheckFlag); + break; + + case kCARD_ResponseTypeR2: /* Response 2 */ + flags |= (kUSDHC_ResponseLength136Flag | kUSDHC_EnableCrcCheckFlag); + break; + + case kCARD_ResponseTypeR3: /* Response 3 */ + case kCARD_ResponseTypeR4: /* Response 4 */ + flags |= (kUSDHC_ResponseLength48Flag); + break; + + default: + break; + } + + if (command->type == kCARD_CommandTypeAbort) + { + flags |= kUSDHC_CommandTypeAbortFlag; + } + + /* config cmd index */ + xferType &= ~(USDHC_CMD_XFR_TYP_CMDINX_MASK | USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK | + USDHC_CMD_XFR_TYP_CCCEN_MASK | USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK); + + xferType |= + (((command->index << USDHC_CMD_XFR_TYP_CMDINX_SHIFT) & USDHC_CMD_XFR_TYP_CMDINX_MASK) | + ((flags) & (USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK | USDHC_CMD_XFR_TYP_CCCEN_MASK | + USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK))); + + /* config the command xfertype and argument */ + base->CMD_ARG = command->argument; + base->CMD_XFR_TYP = xferType; + } + + if (command->type == kCARD_CommandTypeEmpty) + { + /* disable CMD done interrupt for empty command */ + base->INT_SIGNAL_EN &= ~USDHC_INT_SIGNAL_EN_CCIEN_MASK; + } +} + +static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone) +{ + assert(NULL != command); + + status_t error = kStatus_Success; + uint32_t interruptStatus = 0U; + /* check if need polling command done or not */ + if (pollingCmdDone) + { + /* Wait command complete or USDHC encounters error. */ + while (!(interruptStatus & (kUSDHC_CommandCompleteFlag | kUSDHC_CommandErrorFlag))) + { + interruptStatus = USDHC_GetInterruptStatusFlags(base); + } + + if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U) + { + error = kStatus_USDHC_TuningError; + } + else if ((interruptStatus & kUSDHC_CommandErrorFlag) != 0U) + { + error = kStatus_Fail; + } + else + { + } + /* Receive response when command completes successfully. */ + if (error == kStatus_Success) + { + error = USDHC_ReceiveCommandResponse(base, command); + } + + USDHC_ClearInterruptStatusFlags( + base, (kUSDHC_CommandCompleteFlag | kUSDHC_CommandErrorFlag | kUSDHC_TuningErrorFlag)); + } + + return error; +} + +static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA) +{ + status_t error = kStatus_Success; + uint32_t interruptStatus = 0U; + + if (enDMA) + { + /* Wait data complete or USDHC encounters error. */ + while (!((interruptStatus & + (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag | kUSDHC_TuningErrorFlag)))) + { + interruptStatus = USDHC_GetInterruptStatusFlags(base); + } + + if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U) + { + error = kStatus_USDHC_TuningError; + } + else if (((interruptStatus & (kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag)) != 0U)) + { + if ((!(data->enableIgnoreError)) || (interruptStatus & kUSDHC_DataTimeoutFlag)) + { + error = kStatus_Fail; + } + } + else + { + } + /* load dummy data */ + if ((data->dataType == kUSDHC_TransferDataBootcontinous) && (error == kStatus_Success)) + { + *(data->rxData) = s_usdhcBootDummy; + } + + USDHC_ClearInterruptStatusFlags(base, (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag | + kUSDHC_TuningPassFlag | kUSDHC_TuningErrorFlag)); + } + else + { + if (data->rxData) + { + error = USDHC_ReadByDataPortBlocking(base, data); + } + else + { + error = USDHC_WriteByDataPortBlocking(base, data); + } + } + + return error; +} + +/*! + * brief USDHC module initialization function. + * + * Configures the USDHC according to the user configuration. + * + * Example: + code + usdhc_config_t config; + config.cardDetectDat3 = false; + config.endianMode = kUSDHC_EndianModeLittle; + config.dmaMode = kUSDHC_DmaModeAdma2; + config.readWatermarkLevel = 128U; + config.writeWatermarkLevel = 128U; + USDHC_Init(USDHC, &config); + endcode + * + * param base USDHC peripheral base address. + * param config USDHC configuration information. + * retval kStatus_Success Operate successfully. + */ +void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config) +{ + assert(config); + assert((config->writeWatermarkLevel >= 1U) && (config->writeWatermarkLevel <= 128U)); + assert((config->readWatermarkLevel >= 1U) && (config->readWatermarkLevel <= 128U)); + assert(config->writeBurstLen <= 16U); + + uint32_t proctl, sysctl, wml; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Enable USDHC clock. */ + CLOCK_EnableClock(s_usdhcClock[USDHC_GetInstance(base)]); +#endif + + /* Reset USDHC. */ + USDHC_Reset(base, kUSDHC_ResetAll, 100U); + + proctl = base->PROT_CTRL; + wml = base->WTMK_LVL; + sysctl = base->SYS_CTRL; + + proctl &= ~(USDHC_PROT_CTRL_EMODE_MASK | USDHC_PROT_CTRL_DMASEL_MASK); + /* Endian mode*/ + proctl |= USDHC_PROT_CTRL_EMODE(config->endianMode); + + /* Watermark level */ + wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK | USDHC_WTMK_LVL_RD_BRST_LEN_MASK | + USDHC_WTMK_LVL_WR_BRST_LEN_MASK); + wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel) | + USDHC_WTMK_LVL_RD_BRST_LEN(config->readBurstLen) | USDHC_WTMK_LVL_WR_BRST_LEN(config->writeBurstLen)); + + /* config the data timeout value */ + sysctl &= ~USDHC_SYS_CTRL_DTOCV_MASK; + sysctl |= USDHC_SYS_CTRL_DTOCV(config->dataTimeout); + + base->SYS_CTRL = sysctl; + base->WTMK_LVL = wml; + base->PROT_CTRL = proctl; + +#if FSL_FEATURE_USDHC_HAS_EXT_DMA + /* disable external DMA */ + base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK; +#endif + /* disable internal DMA and DDR mode */ + base->MIX_CTRL &= ~(USDHC_MIX_CTRL_DMAEN_MASK | USDHC_MIX_CTRL_DDR_EN_MASK); + /* Enable interrupt status but doesn't enable interrupt signal. */ + USDHC_SetTransferInterrupt(base, false); +} + +/*! + * brief Deinitializes the USDHC. + * + * param base USDHC peripheral base address. + */ +void USDHC_Deinit(USDHC_Type *base) +{ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disable clock. */ + CLOCK_DisableClock(s_usdhcClock[USDHC_GetInstance(base)]); +#endif +} + +/*! + * brief Resets the USDHC. + * + * param base USDHC peripheral base address. + * param mask The reset type mask(_usdhc_reset). + * param timeout Timeout for reset. + * retval true Reset successfully. + * retval false Reset failed. + */ +bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout) +{ + base->SYS_CTRL |= (mask & (USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK)); + /* Delay some time to wait reset success. */ + while ((base->SYS_CTRL & mask) != 0U) + { + if (timeout == 0U) + { + break; + } + timeout--; + } + + return ((!timeout) ? false : true); +} + +/*! + * brief Gets the capability information. + * + * param base USDHC peripheral base address. + * param capability Structure to save capability information. + */ +void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability) +{ + assert(capability); + + uint32_t htCapability; + uint32_t maxBlockLength; + + htCapability = base->HOST_CTRL_CAP; + + /* Get the capability of USDHC. */ + maxBlockLength = ((htCapability & USDHC_HOST_CTRL_CAP_MBL_MASK) >> USDHC_HOST_CTRL_CAP_MBL_SHIFT); + capability->maxBlockLength = (512U << maxBlockLength); + /* Other attributes not in HTCAPBLT register. */ + capability->maxBlockCount = USDHC_MAX_BLOCK_COUNT; + capability->flags = (htCapability & (kUSDHC_SupportAdmaFlag | kUSDHC_SupportHighSpeedFlag | kUSDHC_SupportDmaFlag | + kUSDHC_SupportSuspendResumeFlag | kUSDHC_SupportV330Flag)); + capability->flags |= (htCapability & kUSDHC_SupportV300Flag); + capability->flags |= (htCapability & kUSDHC_SupportV180Flag); + capability->flags |= + (htCapability & (kUSDHC_SupportDDR50Flag | kUSDHC_SupportSDR104Flag | kUSDHC_SupportSDR50Flag)); + /* USDHC support 4/8 bit data bus width. */ + capability->flags |= (kUSDHC_Support4BitFlag | kUSDHC_Support8BitFlag); +} + +/*! + * brief Sets the SD bus clock frequency. + * + * param base USDHC peripheral base address. + * param srcClock_Hz USDHC source clock frequency united in Hz. + * param busClock_Hz SD bus clock frequency united in Hz. + * + * return The nearest frequency of busClock_Hz configured to SD bus. + */ +uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz) +{ + assert(srcClock_Hz != 0U); + assert((busClock_Hz != 0U) && (busClock_Hz <= srcClock_Hz)); + + uint32_t totalDiv = 0U; + uint32_t divisor = 0U; + uint32_t prescaler = 0U; + uint32_t sysctl = 0U; + uint32_t nearestFrequency = 0U; + + /* calucate total divisor first */ + if ((totalDiv = srcClock_Hz / busClock_Hz) > (USDHC_MAX_CLKFS * USDHC_MAX_DVS)) + { + return 0U; + } + + if (totalDiv != 0U) + { + /* calucate the divisor (srcClock_Hz / divisor) <= busClock_Hz */ + if ((srcClock_Hz / totalDiv) > busClock_Hz) + { + totalDiv++; + } + + /* divide the total divisor to div and prescaler */ + if (totalDiv > USDHC_MAX_DVS) + { + prescaler = totalDiv / USDHC_MAX_DVS; + /* prescaler must be a value which equal 2^n and smaller than SDHC_MAX_CLKFS */ + while (((USDHC_MAX_CLKFS % prescaler) != 0U) || (prescaler == 1U)) + { + prescaler++; + } + /* calucate the divisor */ + divisor = totalDiv / prescaler; + /* fine tuning the divisor until divisor * prescaler >= totalDiv */ + while ((divisor * prescaler) < totalDiv) + { + divisor++; + if (divisor > USDHC_MAX_DVS) + { + if ((prescaler <<= 1U) > USDHC_MAX_CLKFS) + { + return 0; + } + divisor = totalDiv / prescaler; + } + } + } + else + { + /* in this situation , divsior and SDCLKFS can generate same clock + use SDCLKFS*/ + if (((totalDiv % 2U) != 0U) & (totalDiv != 1U)) + { + divisor = totalDiv; + prescaler = 1U; + } + else + { + divisor = 1U; + prescaler = totalDiv; + } + } + nearestFrequency = srcClock_Hz / (divisor == 0U ? 1U : divisor) / prescaler; + } + /* in this condition , srcClock_Hz = busClock_Hz, */ + else + { + /* in DDR mode , set SDCLKFS to 0, divisor = 0, actually the + totoal divider = 2U */ + divisor = 0U; + prescaler = 0U; + nearestFrequency = srcClock_Hz; + } + + /* calucate the value write to register */ + if (divisor != 0U) + { + USDHC_PREV_DVS(divisor); + } + /* calucate the value write to register */ + if (prescaler != 0U) + { + USDHC_PREV_CLKFS(prescaler, 1U); + } + + /* Set the SD clock frequency divisor, SD clock frequency select, data timeout counter value. */ + sysctl = base->SYS_CTRL; + sysctl &= ~(USDHC_SYS_CTRL_DVS_MASK | USDHC_SYS_CTRL_SDCLKFS_MASK); + sysctl |= (USDHC_SYS_CTRL_DVS(divisor) | USDHC_SYS_CTRL_SDCLKFS(prescaler)); + base->SYS_CTRL = sysctl; + + /* Wait until the SD clock is stable. */ + while (!(base->PRES_STATE & USDHC_PRES_STATE_SDSTB_MASK)) + { + } + + return nearestFrequency; +} + +/*! + * brief Sends 80 clocks to the card to set it to the active state. + * + * This function must be called each time the card is inserted to ensure that the card can receive the command + * correctly. + * + * param base USDHC peripheral base address. + * param timeout Timeout to initialize card. + * retval true Set card active successfully. + * retval false Set card active failed. + */ +bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout) +{ + base->SYS_CTRL |= USDHC_SYS_CTRL_INITA_MASK; + /* Delay some time to wait card become active state. */ + while ((base->SYS_CTRL & USDHC_SYS_CTRL_INITA_MASK) == USDHC_SYS_CTRL_INITA_MASK) + { + if (!timeout) + { + break; + } + timeout--; + } + + return ((!timeout) ? false : true); +} + +/*! + * brief the enable/disable DDR mode + * + * param base USDHC peripheral base address. + * param enable/disable flag + * param nibble position + */ +void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos) +{ + uint32_t prescaler = (base->SYS_CTRL & USDHC_SYS_CTRL_SDCLKFS_MASK) >> USDHC_SYS_CTRL_SDCLKFS_SHIFT; + + if (enable) + { + base->MIX_CTRL &= ~USDHC_MIX_CTRL_NIBBLE_POS_MASK; + base->MIX_CTRL |= (USDHC_MIX_CTRL_DDR_EN_MASK | USDHC_MIX_CTRL_NIBBLE_POS(nibblePos)); + prescaler >>= 1U; + } + else + { + base->MIX_CTRL &= ~USDHC_MIX_CTRL_DDR_EN_MASK; + + if (prescaler == 0U) + { + prescaler += 1U; + } + else + { + prescaler <<= 1U; + } + } + + base->SYS_CTRL = (base->SYS_CTRL & (~USDHC_SYS_CTRL_SDCLKFS_MASK)) | USDHC_SYS_CTRL_SDCLKFS(prescaler); +} + +/*! + * brief Configures the MMC boot feature. + * + * Example: + code + usdhc_boot_config_t config; + config.ackTimeoutCount = 4; + config.bootMode = kUSDHC_BootModeNormal; + config.blockCount = 5; + config.enableBootAck = true; + config.enableBoot = true; + config.enableAutoStopAtBlockGap = true; + USDHC_SetMmcBootConfig(USDHC, &config); + endcode + * + * param base USDHC peripheral base address. + * param config The MMC boot configuration information. + */ +void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config) +{ + assert(config); + assert(config->ackTimeoutCount <= (USDHC_MMC_BOOT_DTOCV_ACK_MASK >> USDHC_MMC_BOOT_DTOCV_ACK_SHIFT)); + assert(config->blockCount <= (USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK >> USDHC_MMC_BOOT_BOOT_BLK_CNT_SHIFT)); + + uint32_t mmcboot = base->MMC_BOOT; + + mmcboot &= ~(USDHC_MMC_BOOT_DTOCV_ACK_MASK | USDHC_MMC_BOOT_BOOT_MODE_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK); + mmcboot |= USDHC_MMC_BOOT_DTOCV_ACK(config->ackTimeoutCount) | USDHC_MMC_BOOT_BOOT_MODE(config->bootMode); + + if (config->enableBootAck) + { + mmcboot |= USDHC_MMC_BOOT_BOOT_ACK_MASK; + } + if (config->enableAutoStopAtBlockGap) + { + mmcboot |= + USDHC_MMC_BOOT_AUTO_SABG_EN_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT(USDHC_MAX_BLOCK_COUNT - config->blockCount); + /* always set the block count to USDHC_MAX_BLOCK_COUNT to use auto stop at block gap feature */ + base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) | + (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(USDHC_MAX_BLOCK_COUNT))); + } + else + { + base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) | + (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(config->blockCount))); + } + + base->MMC_BOOT = mmcboot; +} + +/*! + * brief Sets the ADMA1 descriptor table configuration. + * + * param admaTable Adma table address. + * param admaTableWords Adma table length. + * param dataBufferAddr Data buffer address. + * param dataBytes Data length. + * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * reference _usdhc_adma_flag. + * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * retval kStatus_Success Operate successfully. + */ +status_t USDHC_SetADMA1Descriptor( + uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags) +{ + assert(NULL != admaTable); + assert(NULL != dataBufferAddr); + + uint32_t miniEntries, startEntries = 0U, + maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma1_descriptor_t); + usdhc_adma1_descriptor_t *adma1EntryAddress = (usdhc_adma1_descriptor_t *)(admaTable); + uint32_t i, dmaBufferLen = 0U; + const uint32_t *data = dataBufferAddr; + + if (((uint32_t)data % USDHC_ADMA1_ADDRESS_ALIGN) != 0U) + { + return kStatus_USDHC_DMADataAddrNotAlign; + } + + if (flags == kUSDHC_AdmaDescriptorMultipleFlag) + { + return kStatus_USDHC_NotSupport; + } + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (dataBytes % sizeof(uint32_t) != 0U) + { + /* make the data length as word-aligned */ + dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); + } + + /* Check if ADMA descriptor's number is enough. */ + if ((dataBytes % USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0U) + { + miniEntries = dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY; + } + else + { + miniEntries = ((dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U); + } + + /* ADMA1 needs two descriptors to finish a transfer */ + miniEntries <<= 1U; + + if (miniEntries + startEntries > maxEntries) + { + return kStatus_OutOfRange; + } + + for (i = startEntries; i < (miniEntries + startEntries); i += 2U) + { + if (dataBytes > USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + { + dmaBufferLen = USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY; + } + else + { + dmaBufferLen = dataBytes; + } + + adma1EntryAddress[i] = (dmaBufferLen << USDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT); + adma1EntryAddress[i] |= kUSDHC_Adma1DescriptorTypeSetLength; + adma1EntryAddress[i + 1U] = (uint32_t)(data); + adma1EntryAddress[i + 1U] |= kUSDHC_Adma1DescriptorTypeTransfer; + data += dmaBufferLen / sizeof(uint32_t); + dataBytes -= dmaBufferLen; + } + /* the end of the descriptor */ + adma1EntryAddress[i - 1U] |= kUSDHC_Adma1DescriptorEndFlag; + + return kStatus_Success; +} + +/*! + * brief Sets the ADMA2 descriptor table configuration. + * + * param admaTable Adma table address. + * param admaTableWords Adma table length. + * param dataBufferAddr Data buffer address. + * param dataBytes Data Data length. + * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * reference _usdhc_adma_flag. + * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * retval kStatus_Success Operate successfully. + */ +status_t USDHC_SetADMA2Descriptor( + uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags) +{ + assert(NULL != admaTable); + assert(NULL != dataBufferAddr); + + uint32_t miniEntries, startEntries = 0U, + maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma2_descriptor_t); + usdhc_adma2_descriptor_t *adma2EntryAddress = (usdhc_adma2_descriptor_t *)(admaTable); + uint32_t i, dmaBufferLen = 0U; + const uint32_t *data = dataBufferAddr; + + if (((uint32_t)data % USDHC_ADMA2_ADDRESS_ALIGN) != 0U) + { + return kStatus_USDHC_DMADataAddrNotAlign; + } + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (dataBytes % sizeof(uint32_t) != 0U) + { + /* make the data length as word-aligned */ + dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); + } + + /* Check if ADMA descriptor's number is enough. */ + if ((dataBytes % USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0U) + { + miniEntries = dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY; + } + else + { + miniEntries = ((dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U); + } + /* calucate the start entry for multiple descriptor mode, ADMA engine is not stop, so update the descriptor + data adress and data size is enough */ + if (flags == kUSDHC_AdmaDescriptorMultipleFlag) + { + for (i = 0U; i < maxEntries; i++) + { + if ((adma2EntryAddress[i].attribute & kUSDHC_Adma2DescriptorValidFlag) == 0U) + { + break; + } + } + startEntries = i; + /* add one entry for dummy entry */ + miniEntries += 1U; + } + + if ((miniEntries + startEntries) > maxEntries) + { + return kStatus_OutOfRange; + } + + for (i = startEntries; i < (miniEntries + startEntries); i++) + { + if (dataBytes > USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + { + dmaBufferLen = USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY; + } + else + { + dmaBufferLen = (dataBytes == 0U ? sizeof(uint32_t) : + dataBytes); /* adma don't support 0 data length transfer descriptor */ + } + + /* Each descriptor for ADMA2 is 64-bit in length */ + adma2EntryAddress[i].address = (dataBytes == 0U) ? &s_usdhcBootDummy : data; + adma2EntryAddress[i].attribute = (dmaBufferLen << USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT); + adma2EntryAddress[i].attribute |= + (dataBytes == 0U) ? 0U : (kUSDHC_Adma2DescriptorTypeTransfer | kUSDHC_Adma2DescriptorInterruptFlag); + data += (dmaBufferLen / sizeof(uint32_t)); + + if (dataBytes != 0U) + { + dataBytes -= dmaBufferLen; + } + } + + /* add a dummy valid ADMA descriptor for multiple descriptor mode, this is useful when transfer boot data, the ADMA + engine + will not stop at block gap */ + if (flags == kUSDHC_AdmaDescriptorMultipleFlag) + { + adma2EntryAddress[startEntries + 1U].attribute |= kUSDHC_Adma2DescriptorTypeTransfer; + } + else + { + /* set the end bit */ + adma2EntryAddress[i - 1U].attribute |= kUSDHC_Adma2DescriptorEndFlag; + } + + return kStatus_Success; +} + +/*! + * brief Internal DMA configuration. + * This function is used to config the USDHC DMA related registers. + * param base USDHC peripheral base address. + * param adma configuration + * param dataAddr transfer data address, a simple DMA parameter, if ADMA is used, leave it to NULL. + * param enAutoCmd23 flag to indicate Auto CMD23 is enable or not, a simple DMA parameter,if ADMA is used, leave it to + * false. + * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * retval kStatus_Success Operate successfully. + */ +status_t USDHC_SetInternalDmaConfig(USDHC_Type *base, + usdhc_adma_config_t *dmaConfig, + const uint32_t *dataAddr, + bool enAutoCmd23) +{ + assert(dmaConfig); + assert(dataAddr); + assert((NULL != dmaConfig->admaTable) && + (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0U)); + +#if FSL_FEATURE_USDHC_HAS_EXT_DMA + /* disable the external DMA if support */ + base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK; +#endif + + if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple) + { + /* check DMA data buffer address align or not */ + if (((uint32_t)dataAddr % USDHC_ADMA2_ADDRESS_ALIGN) != 0U) + { + return kStatus_USDHC_DMADataAddrNotAlign; + } + /* in simple DMA mode if use auto CMD23, address should load to ADMA addr, + and block count should load to DS_ADDR*/ + if (enAutoCmd23) + { + base->ADMA_SYS_ADDR = (uint32_t)dataAddr; + } + else + { + base->DS_ADDR = (uint32_t)dataAddr; + } + } + else + { + /* When use ADMA, disable simple DMA */ + base->DS_ADDR = 0U; + base->ADMA_SYS_ADDR = (uint32_t)(dmaConfig->admaTable); + } + + /* select DMA mode and config the burst length */ + base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK | USDHC_PROT_CTRL_BURST_LEN_EN_MASK); + base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode) | USDHC_PROT_CTRL_BURST_LEN_EN(dmaConfig->burstLen); + /* enable DMA */ + base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK; + + return kStatus_Success; +} + +/*! + * brief Sets the DMA descriptor table configuration. + * A high level DMA descriptor configuration function. + * param base USDHC peripheral base address. + * param adma configuration + * param data Data descriptor + * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * reference _usdhc_adma_flag + * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * retval kStatus_Success Operate successfully. + */ +status_t USDHC_SetAdmaTableConfig(USDHC_Type *base, + usdhc_adma_config_t *dmaConfig, + usdhc_data_t *dataConfig, + uint32_t flags) +{ + assert(NULL != dmaConfig); + assert((NULL != dmaConfig->admaTable) && + (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0U)); + assert(NULL != dataConfig); + + status_t error = kStatus_Fail; + uint32_t bootDummyOffset = dataConfig->dataType == kUSDHC_TransferDataBootcontinous ? sizeof(uint32_t) : 0U; + const uint32_t *data = + (const uint32_t *)((uint32_t)((dataConfig->rxData == NULL) ? dataConfig->txData : dataConfig->rxData) + + bootDummyOffset); + uint32_t blockSize = dataConfig->blockSize * dataConfig->blockCount - bootDummyOffset; + + switch (dmaConfig->dmaMode) + { +#if FSL_FEATURE_USDHC_HAS_EXT_DMA + case kUSDHC_ExternalDMA: + /* enable the external DMA */ + base->VEND_SPEC |= USDHC_VEND_SPEC_EXT_DMA_EN_MASK; + break; +#endif + case kUSDHC_DmaModeSimple: + error = kStatus_Success; + break; + + case kUSDHC_DmaModeAdma1: + error = USDHC_SetADMA1Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags); + break; + + case kUSDHC_DmaModeAdma2: + error = USDHC_SetADMA2Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags); + break; + default: + return kStatus_USDHC_PrepareAdmaDescriptorFailed; + } + + /* for internal dma, internal DMA configurations should not update the configurations when continous transfer the + * boot data, only the DMA descriptor need update */ + if ((dmaConfig->dmaMode != kUSDHC_ExternalDMA) && (error == kStatus_Success) && + (dataConfig->dataType != kUSDHC_TransferDataBootcontinous)) + { + error = USDHC_SetInternalDmaConfig(base, dmaConfig, data, dataConfig->enableAutoCommand23); + } + + return error; +} + +/*! + * brief Transfers the command/data using a blocking method. + * + * This function waits until the command response/data is received or the USDHC encounters an error by polling the + * status + * flag. + * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support + * the re-entry mechanism. + * + * note There is no need to call the API 'USDHC_TransferCreateHandle' when calling this API. + * + * param base USDHC peripheral base address. + * param adma configuration + * param transfer Transfer content. + * retval kStatus_InvalidArgument Argument is invalid. + * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. + * retval kStatus_USDHC_SendCommandFailed Send command failed. + * retval kStatus_USDHC_TransferDataFailed Transfer data failed. + * retval kStatus_Success Operate successfully. + */ +status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer) +{ + assert(transfer); + + status_t error = kStatus_Fail; + usdhc_command_t *command = transfer->command; + usdhc_data_t *data = transfer->data; + bool enDMA = true; + bool executeTuning = ((data == NULL) ? false : data->dataType == kUSDHC_TransferDataTuning); + + /*check re-tuning request*/ + if ((USDHC_GetInterruptStatusFlags(base) & kUSDHC_ReTuningEventFlag) != 0U) + { + USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag); + return kStatus_USDHC_ReTuningRequest; + } + + /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/ + if ((data != NULL) && (dmaConfig != NULL) && (!executeTuning)) + { + error = + USDHC_SetAdmaTableConfig(base, dmaConfig, data, + (data->dataType & kUSDHC_TransferDataBoot) ? kUSDHC_AdmaDescriptorMultipleFlag : + kUSDHC_AdmaDescriptorSingleFlag); + } + + /* if the DMA desciptor configure fail or not needed , disable it */ + if (error != kStatus_Success) + { + enDMA = false; + /* disable DMA, using polling mode in this situation */ + USDHC_EnableInternalDMA(base, false); + } +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + else + { + if (data->txData != NULL) + { + /* clear the DCACHE */ + DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount)); + } + else + { + /* clear the DCACHE */ + DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount)); + } + } +#endif + + /* config the data transfer parameter */ + error = USDHC_SetDataTransferConfig(base, data, &(command->flags), enDMA); + if (kStatus_Success != error) + { + return error; + } + /* send command first */ + USDHC_SendCommand(base, command); + /* wait command done */ + error = USDHC_WaitCommandDone(base, command, (data == NULL) || (data->dataType == kUSDHC_TransferDataNormal)); + + /* wait transfer data finsih */ + if ((data != NULL) && (error == kStatus_Success)) + { + return USDHC_TransferDataBlocking(base, data, enDMA); + } + + return error; +} + +/*! + * brief Transfers the command/data using an interrupt and an asynchronous method. + * + * This function sends a command and data and returns immediately. It doesn't wait the transfer complete or encounter an + * error. + * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support + * the re-entry mechanism. + * + * note Call the API 'USDHC_TransferCreateHandle' when calling this API. + * + * param base USDHC peripheral base address. + * param handle USDHC handle. + * param adma configuration. + * param transfer Transfer content. + * retval kStatus_InvalidArgument Argument is invalid. + * retval kStatus_USDHC_BusyTransferring Busy transferring. + * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. + * retval kStatus_Success Operate successfully. + */ +status_t USDHC_TransferNonBlocking(USDHC_Type *base, + usdhc_handle_t *handle, + usdhc_adma_config_t *dmaConfig, + usdhc_transfer_t *transfer) +{ + assert(handle); + assert(transfer); + + status_t error = kStatus_Fail; + usdhc_command_t *command = transfer->command; + usdhc_data_t *data = transfer->data; + bool executeTuning = ((data == NULL) ? false : data->dataType == kUSDHC_TransferDataTuning); + bool enDMA = true; + + /*check re-tuning request*/ + if ((USDHC_GetInterruptStatusFlags(base) & (kUSDHC_ReTuningEventFlag)) != 0U) + { + USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag); + return kStatus_USDHC_ReTuningRequest; + } + + /* Save command and data into handle before transferring. */ + + handle->command = command; + handle->data = data; + /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */ + handle->transferredWords = 0U; + + /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/ + if ((data != NULL) && (dmaConfig != NULL) && (!executeTuning)) + { + error = + USDHC_SetAdmaTableConfig(base, dmaConfig, data, + (data->dataType & kUSDHC_TransferDataBoot) ? kUSDHC_AdmaDescriptorMultipleFlag : + kUSDHC_AdmaDescriptorSingleFlag); + } + + /* if the DMA desciptor configure fail or not needed , disable it */ + if (error != kStatus_Success) + { + /* disable DMA, using polling mode in this situation */ + USDHC_EnableInternalDMA(base, false); + enDMA = false; + } +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + else + { + if (data->txData != NULL) + { + /* clear the DCACHE */ + DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount)); + } + else + { + /* clear the DCACHE */ + DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount)); + } + } +#endif + + error = USDHC_SetDataTransferConfig(base, data, &(command->flags), enDMA); + if (kStatus_Success != error) + { + return error; + } + + /* send command first */ + USDHC_SendCommand(base, command); + + return kStatus_Success; +} + +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) +/*! + * brief manual tuning trigger or abort + * User should handle the tuning cmd and find the boundary of the delay + * then calucate a average value which will be config to the CLK_TUNE_CTRL_STATUS + * This function should called before USDHC_AdjustDelayforSDR104 function + * param base USDHC peripheral base address. + * param tuning enable flag + */ +void USDHC_EnableManualTuning(USDHC_Type *base, bool enable) +{ + if (enable) + { + /* make sure std_tun_en bit is clear */ + base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK; + /* disable auto tuning here */ + base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK; + /* execute tuning for SDR104 mode */ + base->MIX_CTRL |= + USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK | USDHC_MIX_CTRL_FBCLK_SEL_MASK; + } + else + { /* abort the tuning */ + base->MIX_CTRL &= ~(USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK); + } +} + +/*! + * brief the SDR104 mode delay setting adjust + * This function should called after USDHC_ManualTuningForSDR104 + * param base USDHC peripheral base address. + * param delay setting configuration + * retval kStatus_Fail config the delay setting fail + * retval kStatus_Success config the delay setting success + */ +status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay) +{ + uint32_t clkTuneCtrl = 0U; + + clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS; + + clkTuneCtrl &= ~USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK; + + clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(delay); + + /* load the delay setting */ + base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl; + /* check delat setting error */ + if (base->CLK_TUNE_CTRL_STATUS & + (USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK)) + { + return kStatus_Fail; + } + + return kStatus_Success; +} + +/*! + * brief the enable standard tuning function + * The standard tuning window and tuning counter use the default config + * tuning cmd is send by the software, user need to check the tuning result + * can be used for SDR50,SDR104,HS200 mode tuning + * param base USDHC peripheral base address. + * param tuning start tap + * param tuning step + * param enable/disable flag + */ +void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable) +{ + uint32_t tuningCtrl = 0U; + + if (enable) + { + /* feedback clock */ + base->MIX_CTRL |= USDHC_MIX_CTRL_FBCLK_SEL_MASK; + /* config tuning start and step */ + tuningCtrl = base->TUNING_CTRL; + tuningCtrl &= ~(USDHC_TUNING_CTRL_TUNING_START_TAP_MASK | USDHC_TUNING_CTRL_TUNING_STEP_MASK); + tuningCtrl |= (USDHC_TUNING_CTRL_TUNING_START_TAP(tuningStartTap) | USDHC_TUNING_CTRL_TUNING_STEP(step) | + USDHC_TUNING_CTRL_STD_TUNING_EN_MASK); + base->TUNING_CTRL = tuningCtrl; + + /* excute tuning */ + base->AUTOCMD12_ERR_STATUS |= + (USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK); + } + else + { + /* disable the standard tuning */ + base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK; + /* clear excute tuning */ + base->AUTOCMD12_ERR_STATUS &= + ~(USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK); + } +} + +/*! + * brief the auto tuning enbale for CMD/DATA line + * + * param base USDHC peripheral base address. + */ +void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base) +{ + uint32_t busWidth = 0U; + + base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_CMD_EN_MASK; + busWidth = (base->PROT_CTRL & USDHC_PROT_CTRL_DTW_MASK) >> USDHC_PROT_CTRL_DTW_SHIFT; + if (busWidth == kUSDHC_DataBusWidth1Bit) + { + base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK; + base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK; + } + else if (busWidth == kUSDHC_DataBusWidth4Bit) + { + base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK; + base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK; + } + else if (busWidth == kUSDHC_DataBusWidth8Bit) + { + base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK; + base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK; + } + else + { + } +} +#endif /* FSL_FEATURE_USDHC_HAS_SDR50_MODE */ + +static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags) +{ + if (interruptFlags & kUSDHC_CardInsertionFlag) + { + if (handle->callback.CardInserted) + { + handle->callback.CardInserted(base, handle->userData); + } + } + else + { + if (handle->callback.CardRemoved) + { + handle->callback.CardRemoved(base, handle->userData); + } + } +} + +static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags) +{ + assert(handle->command); + + if (interruptFlags & kUSDHC_CommandErrorFlag) + { + if (handle->callback.TransferComplete) + { + handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData); + } + } + else + { + /* Receive response */ + if (kStatus_Success != USDHC_ReceiveCommandResponse(base, handle->command)) + { + if (handle->callback.TransferComplete) + { + handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData); + } + } + else if ((!(handle->data)) && (handle->callback.TransferComplete)) + { + if (handle->callback.TransferComplete) + { + handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData); + } + } + else + { + } + } +} + +static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags) +{ + assert(handle->data); + + if ((!(handle->data->enableIgnoreError)) && ((interruptFlags & (kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag)))) + { + if (handle->callback.TransferComplete) + { + handle->callback.TransferComplete(base, handle, kStatus_USDHC_TransferDataFailed, handle->userData); + } + } + else + { + if (interruptFlags & kUSDHC_BufferReadReadyFlag) + { + /* std tuning process only need to wait BRR */ + if (handle->data->dataType == kUSDHC_TransferDataTuning) + { + if (handle->callback.TransferComplete) + { + handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData); + } + } + else + { + handle->transferredWords = USDHC_ReadDataPort(base, handle->data, handle->transferredWords); + } + } + else if (interruptFlags & kUSDHC_BufferWriteReadyFlag) + { + handle->transferredWords = USDHC_WriteDataPort(base, handle->data, handle->transferredWords); + } + else + { + if ((interruptFlags & kUSDHC_DmaCompleteFlag) && + (handle->data->dataType == kUSDHC_TransferDataBootcontinous)) + { + *(handle->data->rxData) = s_usdhcBootDummy; + } + + if ((handle->callback.TransferComplete) && (interruptFlags & kUSDHC_DataCompleteFlag)) + { + handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData); + } + } + } +} + +static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle) +{ + if (handle->callback.SdioInterrupt) + { + handle->callback.SdioInterrupt(base, handle->userData); + } +} + +static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags) +{ + assert(handle->callback.ReTuning); + /* retuning request */ + if ((interruptFlags & kUSDHC_TuningErrorFlag) == kUSDHC_TuningErrorFlag) + { + handle->callback.ReTuning(base, handle->userData); /* retuning fail */ + } +} + +static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle) +{ + if (handle->callback.BlockGap) + { + handle->callback.BlockGap(base, handle->userData); + } +} + +/*! + * brief Creates the USDHC handle. + * + * param base USDHC peripheral base address. + * param handle USDHC handle pointer. + * param callback Structure pointer to contain all callback functions. + * param userData Callback function parameter. + */ +void USDHC_TransferCreateHandle(USDHC_Type *base, + usdhc_handle_t *handle, + const usdhc_transfer_callback_t *callback, + void *userData) +{ + assert(handle); + assert(callback); + + /* Zero the handle. */ + memset(handle, 0, sizeof(*handle)); + + /* Set the callback. */ + handle->callback.CardInserted = callback->CardInserted; + handle->callback.CardRemoved = callback->CardRemoved; + handle->callback.SdioInterrupt = callback->SdioInterrupt; + handle->callback.BlockGap = callback->BlockGap; + handle->callback.TransferComplete = callback->TransferComplete; + handle->callback.ReTuning = callback->ReTuning; + handle->userData = userData; + + /* Save the handle in global variables to support the double weak mechanism. */ + s_usdhcHandle[USDHC_GetInstance(base)] = handle; + + /* Enable interrupt in NVIC. */ + USDHC_SetTransferInterrupt(base, true); + /* save IRQ handler */ + s_usdhcIsr = USDHC_TransferHandleIRQ; + + EnableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]); +} + +/*! + * brief IRQ handler for the USDHC. + * + * This function deals with the IRQs on the given host controller. + * + * param base USDHC peripheral base address. + * param handle USDHC handle. + */ +void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle) +{ + assert(handle); + + uint32_t interruptFlags; + + interruptFlags = USDHC_GetEnabledInterruptStatusFlags(base); + + if (interruptFlags & kUSDHC_CardDetectFlag) + { + USDHC_TransferHandleCardDetect(base, handle, (interruptFlags & kUSDHC_CardDetectFlag)); + } + if (interruptFlags & kUSDHC_CommandFlag) + { + USDHC_TransferHandleCommand(base, handle, (interruptFlags & kUSDHC_CommandFlag)); + } + if (interruptFlags & kUSDHC_DataFlag) + { + USDHC_TransferHandleData(base, handle, (interruptFlags & kUSDHC_DataFlag)); + } + if (interruptFlags & kUSDHC_CardInterruptFlag) + { + USDHC_TransferHandleSdioInterrupt(base, handle); + } + if (interruptFlags & kUSDHC_BlockGapEventFlag) + { + USDHC_TransferHandleBlockGap(base, handle); + } + if (interruptFlags & kUSDHC_SDR104TuningFlag) + { + USDHC_TransferHandleReTuning(base, handle, (interruptFlags & kUSDHC_SDR104TuningFlag)); + } + USDHC_ClearInterruptStatusFlags(base, interruptFlags); +} + +#ifdef USDHC0 +void USDHC0_DriverIRQHandler(void) +{ + s_usdhcIsr(s_usdhcBase[0U], s_usdhcHandle[0U]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif + +#ifdef USDHC1 +void USDHC1_DriverIRQHandler(void) +{ + s_usdhcIsr(s_usdhcBase[1U], s_usdhcHandle[1U]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif + +#ifdef USDHC2 +void USDHC2_DriverIRQHandler(void) +{ + s_usdhcIsr(s_usdhcBase[2U], s_usdhcHandle[2U]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +#endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_usdhc.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_usdhc.h new file mode 100644 index 000000000..24476f36c --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_usdhc.h @@ -0,0 +1,1493 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_USDHC_H_ +#define _FSL_USDHC_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup usdhc + * @{ + */ + +/****************************************************************************** + * Definitions. + *****************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief Driver version 2.2.8. */ +#define FSL_USDHC_DRIVER_VERSION (MAKE_VERSION(2U, 2U, 8U)) +/*@}*/ + +/*! @brief Maximum block count can be set one time */ +#define USDHC_MAX_BLOCK_COUNT (USDHC_BLK_ATT_BLKCNT_MASK >> USDHC_BLK_ATT_BLKCNT_SHIFT) + +/*! @brief USDHC status */ +enum _usdhc_status +{ + kStatus_USDHC_BusyTransferring = MAKE_STATUS(kStatusGroup_USDHC, 0U), /*!< Transfer is on-going */ + kStatus_USDHC_PrepareAdmaDescriptorFailed = MAKE_STATUS(kStatusGroup_USDHC, 1U), /*!< Set DMA descriptor failed */ + kStatus_USDHC_SendCommandFailed = MAKE_STATUS(kStatusGroup_USDHC, 2U), /*!< Send command failed */ + kStatus_USDHC_TransferDataFailed = MAKE_STATUS(kStatusGroup_USDHC, 3U), /*!< Transfer data failed */ + kStatus_USDHC_DMADataAddrNotAlign = MAKE_STATUS(kStatusGroup_USDHC, 4U), /*!< data address not align */ + kStatus_USDHC_ReTuningRequest = MAKE_STATUS(kStatusGroup_USDHC, 5U), /*!< re-tuning request */ + kStatus_USDHC_TuningError = MAKE_STATUS(kStatusGroup_USDHC, 6U), /*!< tuning error */ + kStatus_USDHC_NotSupport = MAKE_STATUS(kStatusGroup_USDHC, 7U), /*!< not support */ +}; + +/*! @brief Host controller capabilities flag mask */ +enum _usdhc_capability_flag +{ + kUSDHC_SupportAdmaFlag = USDHC_HOST_CTRL_CAP_ADMAS_MASK, /*!< Support ADMA */ + kUSDHC_SupportHighSpeedFlag = USDHC_HOST_CTRL_CAP_HSS_MASK, /*!< Support high-speed */ + kUSDHC_SupportDmaFlag = USDHC_HOST_CTRL_CAP_DMAS_MASK, /*!< Support DMA */ + kUSDHC_SupportSuspendResumeFlag = USDHC_HOST_CTRL_CAP_SRS_MASK, /*!< Support suspend/resume */ + kUSDHC_SupportV330Flag = USDHC_HOST_CTRL_CAP_VS33_MASK, /*!< Support voltage 3.3V */ + kUSDHC_SupportV300Flag = USDHC_HOST_CTRL_CAP_VS30_MASK, /*!< Support voltage 3.0V */ + kUSDHC_SupportV180Flag = USDHC_HOST_CTRL_CAP_VS18_MASK, /*!< Support voltage 1.8V */ + /* Put additional two flags in HTCAPBLT_MBL's position. */ + kUSDHC_Support4BitFlag = (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0U), /*!< Support 4 bit mode */ + kUSDHC_Support8BitFlag = (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1U), /*!< Support 8 bit mode */ + /* sd version 3.0 new feature */ + kUSDHC_SupportDDR50Flag = USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK, /*!< support DDR50 mode */ + +#if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR104_MODE) + kUSDHC_SupportSDR104Flag = 0, /*!< not support SDR104 mode */ +#else + kUSDHC_SupportSDR104Flag = USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK, /*!< support SDR104 mode */ +#endif +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) + kUSDHC_SupportSDR50Flag = 0U, /*!< not support SDR50 mode */ +#else + kUSDHC_SupportSDR50Flag = USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK, /*!< support SDR50 mode */ +#endif +}; + +/*! @brief Wakeup event mask */ +enum _usdhc_wakeup_event +{ + kUSDHC_WakeupEventOnCardInt = USDHC_PROT_CTRL_WECINT_MASK, /*!< Wakeup on card interrupt */ + kUSDHC_WakeupEventOnCardInsert = USDHC_PROT_CTRL_WECINS_MASK, /*!< Wakeup on card insertion */ + kUSDHC_WakeupEventOnCardRemove = USDHC_PROT_CTRL_WECRM_MASK, /*!< Wakeup on card removal */ + + kUSDHC_WakeupEventsAll = (kUSDHC_WakeupEventOnCardInt | kUSDHC_WakeupEventOnCardInsert | + kUSDHC_WakeupEventOnCardRemove), /*!< All wakeup events */ +}; + +/*! @brief Reset type mask */ +enum _usdhc_reset +{ + kUSDHC_ResetAll = USDHC_SYS_CTRL_RSTA_MASK, /*!< Reset all except card detection */ + kUSDHC_ResetCommand = USDHC_SYS_CTRL_RSTC_MASK, /*!< Reset command line */ + kUSDHC_ResetData = USDHC_SYS_CTRL_RSTD_MASK, /*!< Reset data line */ + +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) + kUSDHC_ResetTuning = 0U, /*!< no reset tuning circuit bit */ +#else + kUSDHC_ResetTuning = USDHC_SYS_CTRL_RSTT_MASK, /*!< reset tuning circuit */ +#endif + + kUSDHC_ResetsAll = + (kUSDHC_ResetAll | kUSDHC_ResetCommand | kUSDHC_ResetData | kUSDHC_ResetTuning), /*!< All reset types */ +}; + +/*! @brief Transfer flag mask */ +enum _usdhc_transfer_flag +{ + kUSDHC_EnableDmaFlag = USDHC_MIX_CTRL_DMAEN_MASK, /*!< Enable DMA */ + + kUSDHC_CommandTypeSuspendFlag = (USDHC_CMD_XFR_TYP_CMDTYP(1U)), /*!< Suspend command */ + kUSDHC_CommandTypeResumeFlag = (USDHC_CMD_XFR_TYP_CMDTYP(2U)), /*!< Resume command */ + kUSDHC_CommandTypeAbortFlag = (USDHC_CMD_XFR_TYP_CMDTYP(3U)), /*!< Abort command */ + + kUSDHC_EnableBlockCountFlag = USDHC_MIX_CTRL_BCEN_MASK, /*!< Enable block count */ + kUSDHC_EnableAutoCommand12Flag = USDHC_MIX_CTRL_AC12EN_MASK, /*!< Enable auto CMD12 */ + kUSDHC_DataReadFlag = USDHC_MIX_CTRL_DTDSEL_MASK, /*!< Enable data read */ + kUSDHC_MultipleBlockFlag = USDHC_MIX_CTRL_MSBSEL_MASK, /*!< Multiple block data read/write */ + kUSDHC_EnableAutoCommand23Flag = USDHC_MIX_CTRL_AC23EN_MASK, /*!< Enable auto CMD23 */ + + kUSDHC_ResponseLength136Flag = USDHC_CMD_XFR_TYP_RSPTYP(1U), /*!< 136 bit response length */ + kUSDHC_ResponseLength48Flag = USDHC_CMD_XFR_TYP_RSPTYP(2U), /*!< 48 bit response length */ + kUSDHC_ResponseLength48BusyFlag = USDHC_CMD_XFR_TYP_RSPTYP(3U), /*!< 48 bit response length with busy status */ + + kUSDHC_EnableCrcCheckFlag = USDHC_CMD_XFR_TYP_CCCEN_MASK, /*!< Enable CRC check */ + kUSDHC_EnableIndexCheckFlag = USDHC_CMD_XFR_TYP_CICEN_MASK, /*!< Enable index check */ + kUSDHC_DataPresentFlag = USDHC_CMD_XFR_TYP_DPSEL_MASK, /*!< Data present flag */ +}; + +/*! @brief Present status flag mask */ +enum _usdhc_present_status_flag +{ + kUSDHC_CommandInhibitFlag = USDHC_PRES_STATE_CIHB_MASK, /*!< Command inhibit */ + kUSDHC_DataInhibitFlag = USDHC_PRES_STATE_CDIHB_MASK, /*!< Data inhibit */ + kUSDHC_DataLineActiveFlag = USDHC_PRES_STATE_DLA_MASK, /*!< Data line active */ + kUSDHC_SdClockStableFlag = USDHC_PRES_STATE_SDSTB_MASK, /*!< SD bus clock stable */ + kUSDHC_WriteTransferActiveFlag = USDHC_PRES_STATE_WTA_MASK, /*!< Write transfer active */ + kUSDHC_ReadTransferActiveFlag = USDHC_PRES_STATE_RTA_MASK, /*!< Read transfer active */ + kUSDHC_BufferWriteEnableFlag = USDHC_PRES_STATE_BWEN_MASK, /*!< Buffer write enable */ + kUSDHC_BufferReadEnableFlag = USDHC_PRES_STATE_BREN_MASK, /*!< Buffer read enable */ + +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) + kUSDHC_DelaySettingFinishedFlag = 0U, /*!< not support */ + kUSDHC_ReTuningRequestFlag = 0U, /*!< not support */ +#else + kUSDHC_ReTuningRequestFlag = USDHC_PRES_STATE_RTR_MASK, /*!< re-tuning request flag ,only used for SDR104 mode */ + kUSDHC_DelaySettingFinishedFlag = USDHC_PRES_STATE_TSCD_MASK, /*!< delay setting finished flag */ +#endif + + kUSDHC_CardInsertedFlag = USDHC_PRES_STATE_CINST_MASK, /*!< Card inserted */ + kUSDHC_CommandLineLevelFlag = USDHC_PRES_STATE_CLSL_MASK, /*!< Command line signal level */ + + kUSDHC_Data0LineLevelFlag = 1U << USDHC_PRES_STATE_DLSL_SHIFT, /*!< Data0 line signal level */ + kUSDHC_Data1LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 1U), /*!< Data1 line signal level */ + kUSDHC_Data2LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 2U), /*!< Data2 line signal level */ + kUSDHC_Data3LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 3U), /*!< Data3 line signal level */ + kUSDHC_Data4LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 4U), /*!< Data4 line signal level */ + kUSDHC_Data5LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 5U), /*!< Data5 line signal level */ + kUSDHC_Data6LineLevelFlag = 1U << (USDHC_PRES_STATE_DLSL_SHIFT + 6U), /*!< Data6 line signal level */ + kUSDHC_Data7LineLevelFlag = (int)(1U << (USDHC_PRES_STATE_DLSL_SHIFT + 7U)), /*!< Data7 line signal level */ +}; + +/*! @brief Interrupt status flag mask */ +enum _usdhc_interrupt_status_flag +{ + kUSDHC_CommandCompleteFlag = USDHC_INT_STATUS_CC_MASK, /*!< Command complete */ + kUSDHC_DataCompleteFlag = USDHC_INT_STATUS_TC_MASK, /*!< Data complete */ + kUSDHC_BlockGapEventFlag = USDHC_INT_STATUS_BGE_MASK, /*!< Block gap event */ + kUSDHC_DmaCompleteFlag = USDHC_INT_STATUS_DINT_MASK, /*!< DMA interrupt */ + kUSDHC_BufferWriteReadyFlag = USDHC_INT_STATUS_BWR_MASK, /*!< Buffer write ready */ + kUSDHC_BufferReadReadyFlag = USDHC_INT_STATUS_BRR_MASK, /*!< Buffer read ready */ + kUSDHC_CardInsertionFlag = USDHC_INT_STATUS_CINS_MASK, /*!< Card inserted */ + kUSDHC_CardRemovalFlag = USDHC_INT_STATUS_CRM_MASK, /*!< Card removed */ + kUSDHC_CardInterruptFlag = USDHC_INT_STATUS_CINT_MASK, /*!< Card interrupt */ + +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) + kUSDHC_ReTuningEventFlag = 0U, /*!< Re-Tuning event,only for SD3.0 SDR104 mode */ + kUSDHC_TuningPassFlag = 0U, /*!< SDR104 mode tuning pass flag */ + kUSDHC_TuningErrorFlag = 0U, /*!< SDR104 tuning error flag */ +#else + kUSDHC_ReTuningEventFlag = USDHC_INT_STATUS_RTE_MASK, /*!< Re-Tuning event,only for SD3.0 SDR104 mode */ + kUSDHC_TuningPassFlag = USDHC_INT_STATUS_TP_MASK, /*!< SDR104 mode tuning pass flag */ + kUSDHC_TuningErrorFlag = USDHC_INT_STATUS_TNE_MASK, /*!< SDR104 tuning error flag */ +#endif + + kUSDHC_CommandTimeoutFlag = USDHC_INT_STATUS_CTOE_MASK, /*!< Command timeout error */ + kUSDHC_CommandCrcErrorFlag = USDHC_INT_STATUS_CCE_MASK, /*!< Command CRC error */ + kUSDHC_CommandEndBitErrorFlag = USDHC_INT_STATUS_CEBE_MASK, /*!< Command end bit error */ + kUSDHC_CommandIndexErrorFlag = USDHC_INT_STATUS_CIE_MASK, /*!< Command index error */ + kUSDHC_DataTimeoutFlag = USDHC_INT_STATUS_DTOE_MASK, /*!< Data timeout error */ + kUSDHC_DataCrcErrorFlag = USDHC_INT_STATUS_DCE_MASK, /*!< Data CRC error */ + kUSDHC_DataEndBitErrorFlag = USDHC_INT_STATUS_DEBE_MASK, /*!< Data end bit error */ + kUSDHC_AutoCommand12ErrorFlag = USDHC_INT_STATUS_AC12E_MASK, /*!< Auto CMD12 error */ + kUSDHC_DmaErrorFlag = USDHC_INT_STATUS_DMAE_MASK, /*!< DMA error */ + + kUSDHC_CommandErrorFlag = (kUSDHC_CommandTimeoutFlag | kUSDHC_CommandCrcErrorFlag | kUSDHC_CommandEndBitErrorFlag | + kUSDHC_CommandIndexErrorFlag), /*!< Command error */ + kUSDHC_DataErrorFlag = (kUSDHC_DataTimeoutFlag | kUSDHC_DataCrcErrorFlag | kUSDHC_DataEndBitErrorFlag | + kUSDHC_AutoCommand12ErrorFlag), /*!< Data error */ + kUSDHC_ErrorFlag = (kUSDHC_CommandErrorFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag), /*!< All error */ + kUSDHC_DataFlag = (kUSDHC_DataCompleteFlag | kUSDHC_DmaCompleteFlag | kUSDHC_BufferWriteReadyFlag | + kUSDHC_BufferReadReadyFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag), /*!< Data interrupts */ + kUSDHC_CommandFlag = (kUSDHC_CommandErrorFlag | kUSDHC_CommandCompleteFlag), /*!< Command interrupts */ + kUSDHC_CardDetectFlag = (kUSDHC_CardInsertionFlag | kUSDHC_CardRemovalFlag), /*!< Card detection interrupts */ + kUSDHC_SDR104TuningFlag = (kUSDHC_TuningErrorFlag | kUSDHC_TuningPassFlag | kUSDHC_ReTuningEventFlag), + + kUSDHC_AllInterruptFlags = (kUSDHC_BlockGapEventFlag | kUSDHC_CardInterruptFlag | kUSDHC_CommandFlag | + kUSDHC_DataFlag | kUSDHC_ErrorFlag | kUSDHC_SDR104TuningFlag), /*!< All flags mask */ +}; + +/*! @brief Auto CMD12 error status flag mask */ +enum _usdhc_auto_command12_error_status_flag +{ + kUSDHC_AutoCommand12NotExecutedFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12NE_MASK, /*!< Not executed error */ + kUSDHC_AutoCommand12TimeoutFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12TOE_MASK, /*!< Timeout error */ + kUSDHC_AutoCommand12EndBitErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12EBE_MASK, /*!< End bit error */ + kUSDHC_AutoCommand12CrcErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12CE_MASK, /*!< CRC error */ + kUSDHC_AutoCommand12IndexErrorFlag = USDHC_AUTOCMD12_ERR_STATUS_AC12IE_MASK, /*!< Index error */ + kUSDHC_AutoCommand12NotIssuedFlag = USDHC_AUTOCMD12_ERR_STATUS_CNIBAC12E_MASK, /*!< Not issued error */ +}; + +/*! @brief standard tuning flag */ +enum _usdhc_standard_tuning +{ +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) + kUSDHC_ExecuteTuning = 0U, /*!< not support */ + kUSDHC_TuningSampleClockSel = 0U, /*!< not support */ +#else + kUSDHC_ExecuteTuning = USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK, /*!< used to start tuning procedure */ + kUSDHC_TuningSampleClockSel = USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK, /*!< when std_tuning_en bit is set, this + bit is used select sampleing clock */ +#endif +}; + +/*! @brief ADMA error status flag mask */ +enum _usdhc_adma_error_status_flag +{ + kUSDHC_AdmaLenghMismatchFlag = USDHC_ADMA_ERR_STATUS_ADMALME_MASK, /*!< Length mismatch error */ + kUSDHC_AdmaDescriptorErrorFlag = USDHC_ADMA_ERR_STATUS_ADMADCE_MASK, /*!< Descriptor error */ +}; + +/*! + * @brief ADMA error state + * + * This state is the detail state when ADMA error has occurred. + */ +enum _usdhc_adma_error_state +{ + kUSDHC_AdmaErrorStateStopDma = + 0x00U, /*!< Stop DMA, previous location set in the ADMA system address is error address */ + kUSDHC_AdmaErrorStateFetchDescriptor = + 0x01U, /*!< Fetch descriptor, current location set in the ADMA system address is error address */ + kUSDHC_AdmaErrorStateChangeAddress = 0x02U, /*!< Change address, no DMA error is occurred */ + kUSDHC_AdmaErrorStateTransferData = + 0x03U, /*!< Transfer data, previous location set in the ADMA system address is error address */ + kUSDHC_AdmaErrorStateInvalidLength = 0x04U, /*!< Invalid length in ADMA descriptor */ + kUSDHC_AdmaErrorStateInvalidDescriptor = 0x08U, /*!< Invalid descriptor fetched by ADMA */ + + kUSDHC_AdmaErrorState = kUSDHC_AdmaErrorStateInvalidLength | kUSDHC_AdmaErrorStateInvalidDescriptor | + kUSDHC_AdmaErrorStateFetchDescriptor, /*!< ADMA error state */ +}; + +/*! @brief Force event bit position */ +enum _usdhc_force_event +{ + kUSDHC_ForceEventAutoCommand12NotExecuted = USDHC_FORCE_EVENT_FEVTAC12NE_MASK, /*!< Auto CMD12 not executed error */ + kUSDHC_ForceEventAutoCommand12Timeout = USDHC_FORCE_EVENT_FEVTAC12TOE_MASK, /*!< Auto CMD12 timeout error */ + kUSDHC_ForceEventAutoCommand12CrcError = USDHC_FORCE_EVENT_FEVTAC12CE_MASK, /*!< Auto CMD12 CRC error */ + kUSDHC_ForceEventEndBitError = USDHC_FORCE_EVENT_FEVTAC12EBE_MASK, /*!< Auto CMD12 end bit error */ + kUSDHC_ForceEventAutoCommand12IndexError = USDHC_FORCE_EVENT_FEVTAC12IE_MASK, /*!< Auto CMD12 index error */ + kUSDHC_ForceEventAutoCommand12NotIssued = USDHC_FORCE_EVENT_FEVTCNIBAC12E_MASK, /*!< Auto CMD12 not issued error */ + kUSDHC_ForceEventCommandTimeout = USDHC_FORCE_EVENT_FEVTCTOE_MASK, /*!< Command timeout error */ + kUSDHC_ForceEventCommandCrcError = USDHC_FORCE_EVENT_FEVTCCE_MASK, /*!< Command CRC error */ + kUSDHC_ForceEventCommandEndBitError = USDHC_FORCE_EVENT_FEVTCEBE_MASK, /*!< Command end bit error */ + kUSDHC_ForceEventCommandIndexError = USDHC_FORCE_EVENT_FEVTCIE_MASK, /*!< Command index error */ + kUSDHC_ForceEventDataTimeout = USDHC_FORCE_EVENT_FEVTDTOE_MASK, /*!< Data timeout error */ + kUSDHC_ForceEventDataCrcError = USDHC_FORCE_EVENT_FEVTDCE_MASK, /*!< Data CRC error */ + kUSDHC_ForceEventDataEndBitError = USDHC_FORCE_EVENT_FEVTDEBE_MASK, /*!< Data end bit error */ + kUSDHC_ForceEventAutoCommand12Error = USDHC_FORCE_EVENT_FEVTAC12E_MASK, /*!< Auto CMD12 error */ + kUSDHC_ForceEventCardInt = (int)USDHC_FORCE_EVENT_FEVTCINT_MASK, /*!< Card interrupt */ + kUSDHC_ForceEventDmaError = USDHC_FORCE_EVENT_FEVTDMAE_MASK, /*!< Dma error */ +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (!FSL_FEATURE_USDHC_HAS_SDR50_MODE) + kUSDHC_ForceEventTuningError = 0U, /*!< not support */ +#else + kUSDHC_ForceEventTuningError = USDHC_FORCE_EVENT_FEVTTNE_MASK, /*!< Tuning error */ +#endif + + kUSDHC_ForceEventsAll = + (int)(USDHC_FORCE_EVENT_FEVTAC12NE_MASK | USDHC_FORCE_EVENT_FEVTAC12TOE_MASK | + USDHC_FORCE_EVENT_FEVTAC12CE_MASK | USDHC_FORCE_EVENT_FEVTAC12EBE_MASK | + USDHC_FORCE_EVENT_FEVTAC12IE_MASK | USDHC_FORCE_EVENT_FEVTCNIBAC12E_MASK | + USDHC_FORCE_EVENT_FEVTCTOE_MASK | USDHC_FORCE_EVENT_FEVTCCE_MASK | USDHC_FORCE_EVENT_FEVTCEBE_MASK | + USDHC_FORCE_EVENT_FEVTCIE_MASK | USDHC_FORCE_EVENT_FEVTDTOE_MASK | USDHC_FORCE_EVENT_FEVTDCE_MASK | + USDHC_FORCE_EVENT_FEVTDEBE_MASK | USDHC_FORCE_EVENT_FEVTAC12E_MASK | USDHC_FORCE_EVENT_FEVTCINT_MASK | + USDHC_FORCE_EVENT_FEVTDMAE_MASK | kUSDHC_ForceEventTuningError), /*!< All force event flags mask */ +}; + +/*! @brief Data transfer width */ +typedef enum _usdhc_data_bus_width +{ + kUSDHC_DataBusWidth1Bit = 0U, /*!< 1-bit mode */ + kUSDHC_DataBusWidth4Bit = 1U, /*!< 4-bit mode */ + kUSDHC_DataBusWidth8Bit = 2U, /*!< 8-bit mode */ +} usdhc_data_bus_width_t; + +/*! @brief Endian mode */ +typedef enum _usdhc_endian_mode +{ + kUSDHC_EndianModeBig = 0U, /*!< Big endian mode */ + kUSDHC_EndianModeHalfWordBig = 1U, /*!< Half word big endian mode */ + kUSDHC_EndianModeLittle = 2U, /*!< Little endian mode */ +} usdhc_endian_mode_t; + +/*! @brief DMA mode */ +typedef enum _usdhc_dma_mode +{ + kUSDHC_DmaModeSimple = 0U, /*!< external DMA */ + kUSDHC_DmaModeAdma1 = 1U, /*!< ADMA1 is selected */ + kUSDHC_DmaModeAdma2 = 2U, /*!< ADMA2 is selected */ + kUSDHC_ExternalDMA = 3U, /*!< external dma mode select */ +} usdhc_dma_mode_t; + +/*! @brief SDIO control flag mask */ +enum _usdhc_sdio_control_flag +{ + kUSDHC_StopAtBlockGapFlag = USDHC_PROT_CTRL_SABGREQ_MASK, /*!< Stop at block gap */ + kUSDHC_ReadWaitControlFlag = USDHC_PROT_CTRL_RWCTL_MASK, /*!< Read wait control */ + kUSDHC_InterruptAtBlockGapFlag = USDHC_PROT_CTRL_IABG_MASK, /*!< Interrupt at block gap */ + kUSDHC_ReadDoneNo8CLK = USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK, /*!< read done without 8 clk for block gap */ + kUSDHC_ExactBlockNumberReadFlag = USDHC_PROT_CTRL_NON_EXACT_BLK_RD_MASK, /*!< Exact block number read */ +}; + +/*! @brief MMC card boot mode */ +typedef enum _usdhc_boot_mode +{ + kUSDHC_BootModeNormal = 0U, /*!< Normal boot */ + kUSDHC_BootModeAlternative = 1U, /*!< Alternative boot */ +} usdhc_boot_mode_t; + +/*! @brief The command type */ +typedef enum _usdhc_card_command_type +{ + kCARD_CommandTypeNormal = 0U, /*!< Normal command */ + kCARD_CommandTypeSuspend = 1U, /*!< Suspend command */ + kCARD_CommandTypeResume = 2U, /*!< Resume command */ + kCARD_CommandTypeAbort = 3U, /*!< Abort command */ + kCARD_CommandTypeEmpty = 4U, /*!< Empty command */ +} usdhc_card_command_type_t; + +/*! + * @brief The command response type. + * + * Define the command response type from card to host controller. + */ +typedef enum _usdhc_card_response_type +{ + kCARD_ResponseTypeNone = 0U, /*!< Response type: none */ + kCARD_ResponseTypeR1 = 1U, /*!< Response type: R1 */ + kCARD_ResponseTypeR1b = 2U, /*!< Response type: R1b */ + kCARD_ResponseTypeR2 = 3U, /*!< Response type: R2 */ + kCARD_ResponseTypeR3 = 4U, /*!< Response type: R3 */ + kCARD_ResponseTypeR4 = 5U, /*!< Response type: R4 */ + kCARD_ResponseTypeR5 = 6U, /*!< Response type: R5 */ + kCARD_ResponseTypeR5b = 7U, /*!< Response type: R5b */ + kCARD_ResponseTypeR6 = 8U, /*!< Response type: R6 */ + kCARD_ResponseTypeR7 = 9U, /*!< Response type: R7 */ +} usdhc_card_response_type_t; + +/*! @brief The alignment size for ADDRESS filed in ADMA1's descriptor */ +#define USDHC_ADMA1_ADDRESS_ALIGN (4096U) +/*! @brief The alignment size for LENGTH field in ADMA1's descriptor */ +#define USDHC_ADMA1_LENGTH_ALIGN (4096U) +/*! @brief The alignment size for ADDRESS field in ADMA2's descriptor */ +#define USDHC_ADMA2_ADDRESS_ALIGN (4U) +/*! @brief The alignment size for LENGTH filed in ADMA2's descriptor */ +#define USDHC_ADMA2_LENGTH_ALIGN (4U) + +/* ADMA1 descriptor table + * |------------------------|---------|--------------------------| + * | Address/page field |Reserved | Attribute | + * |------------------------|---------|--------------------------| + * |31 12|11 6|05 |04 |03|02 |01 |00 | + * |------------------------|---------|----|----|--|---|---|-----| + * | address or data length | 000000 |Act2|Act1| 0|Int|End|Valid| + * |------------------------|---------|----|----|--|---|---|-----| + * + * + * |------|------|-----------------|-------|-------------| + * | Act2 | Act1 | Comment | 31-28 | 27 - 12 | + * |------|------|-----------------|---------------------| + * | 0 | 0 | No op | Don't care | + * |------|------|-----------------|-------|-------------| + * | 0 | 1 | Set data length | 0000 | Data Length | + * |------|------|-----------------|-------|-------------| + * | 1 | 0 | Transfer data | Data address | + * |------|------|-----------------|---------------------| + * | 1 | 1 | Link descriptor | Descriptor address | + * |------|------|-----------------|---------------------| + */ +/*! @brief The bit shift for ADDRESS filed in ADMA1's descriptor */ +#define USDHC_ADMA1_DESCRIPTOR_ADDRESS_SHIFT (12U) +/*! @brief The bit mask for ADDRESS field in ADMA1's descriptor */ +#define USDHC_ADMA1_DESCRIPTOR_ADDRESS_MASK (0xFFFFFU) +/*! @brief The bit shift for LENGTH filed in ADMA1's descriptor */ +#define USDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT (12U) +/*! @brief The mask for LENGTH field in ADMA1's descriptor */ +#define USDHC_ADMA1_DESCRIPTOR_LENGTH_MASK (0xFFFFU) +/*! @brief The maximum value of LENGTH filed in ADMA1's descriptor + * Since the ADMA1 support max transfer size is 65535 which is not divisible by + * 4096, so to make sure a large data load transfer(>64KB) continuously(require the data + * address should be alwawys align with 4096), software will set the maximum data length + * for ADMA1 to (64 - 4)KB. + */ +#define USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY (USDHC_ADMA1_DESCRIPTOR_LENGTH_MASK + 1U - 4096U) + +/*! @brief The mask for the control/status field in ADMA1 descriptor */ +enum _usdhc_adma1_descriptor_flag +{ + kUSDHC_Adma1DescriptorValidFlag = (1U << 0U), /*!< Valid flag */ + kUSDHC_Adma1DescriptorEndFlag = (1U << 1U), /*!< End flag */ + kUSDHC_Adma1DescriptorInterrupFlag = (1U << 2U), /*!< Interrupt flag */ + kUSDHC_Adma1DescriptorActivity1Flag = (1U << 4U), /*!< Activity 1 flag */ + kUSDHC_Adma1DescriptorActivity2Flag = (1U << 5U), /*!< Activity 2 flag */ + kUSDHC_Adma1DescriptorTypeNop = (kUSDHC_Adma1DescriptorValidFlag), /*!< No operation */ + kUSDHC_Adma1DescriptorTypeTransfer = + (kUSDHC_Adma1DescriptorActivity2Flag | kUSDHC_Adma1DescriptorValidFlag), /*!< Transfer data */ + kUSDHC_Adma1DescriptorTypeLink = (kUSDHC_Adma1DescriptorActivity1Flag | kUSDHC_Adma1DescriptorActivity2Flag | + kUSDHC_Adma1DescriptorValidFlag), /*!< Link descriptor */ + kUSDHC_Adma1DescriptorTypeSetLength = + (kUSDHC_Adma1DescriptorActivity1Flag | kUSDHC_Adma1DescriptorValidFlag), /*!< Set data length */ +}; + +/* ADMA2 descriptor table + * |----------------|---------------|-------------|--------------------------| + * | Address field | Length | Reserved | Attribute | + * |----------------|---------------|-------------|--------------------------| + * |63 32|31 16|15 06|05 |04 |03|02 |01 |00 | + * |----------------|---------------|-------------|----|----|--|---|---|-----| + * | 32-bit address | 16-bit length | 0000000000 |Act2|Act1| 0|Int|End|Valid| + * |----------------|---------------|-------------|----|----|--|---|---|-----| + * + * + * | Act2 | Act1 | Comment | Operation | + * |------|------|-----------------|-------------------------------------------------------------------| + * | 0 | 0 | No op | Don't care | + * |------|------|-----------------|-------------------------------------------------------------------| + * | 0 | 1 | Reserved | Read this line and go to next one | + * |------|------|-----------------|-------------------------------------------------------------------| + * | 1 | 0 | Transfer data | Transfer data with address and length set in this descriptor line | + * |------|------|-----------------|-------------------------------------------------------------------| + * | 1 | 1 | Link descriptor | Link to another descriptor | + * |------|------|-----------------|-------------------------------------------------------------------| + */ +/*! @brief The bit shift for LENGTH field in ADMA2's descriptor */ +#define USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT (16U) +/*! @brief The bit mask for LENGTH field in ADMA2's descriptor */ +#define USDHC_ADMA2_DESCRIPTOR_LENGTH_MASK (0xFFFFU) +/*! @brief The maximum value of LENGTH field in ADMA2's descriptor */ +#define USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY (USDHC_ADMA2_DESCRIPTOR_LENGTH_MASK - 3U) + +/*! @brief ADMA1 descriptor control and status mask */ +enum _usdhc_adma2_descriptor_flag +{ + kUSDHC_Adma2DescriptorValidFlag = (1U << 0U), /*!< Valid flag */ + kUSDHC_Adma2DescriptorEndFlag = (1U << 1U), /*!< End flag */ + kUSDHC_Adma2DescriptorInterruptFlag = (1U << 2U), /*!< Interrupt flag */ + kUSDHC_Adma2DescriptorActivity1Flag = (1U << 4U), /*!< Activity 1 mask */ + kUSDHC_Adma2DescriptorActivity2Flag = (1U << 5U), /*!< Activity 2 mask */ + + kUSDHC_Adma2DescriptorTypeNop = (kUSDHC_Adma2DescriptorValidFlag), /*!< No operation */ + kUSDHC_Adma2DescriptorTypeReserved = + (kUSDHC_Adma2DescriptorActivity1Flag | kUSDHC_Adma2DescriptorValidFlag), /*!< Reserved */ + kUSDHC_Adma2DescriptorTypeTransfer = + (kUSDHC_Adma2DescriptorActivity2Flag | kUSDHC_Adma2DescriptorValidFlag), /*!< Transfer type */ + kUSDHC_Adma2DescriptorTypeLink = (kUSDHC_Adma2DescriptorActivity1Flag | kUSDHC_Adma2DescriptorActivity2Flag | + kUSDHC_Adma2DescriptorValidFlag), /*!< Link type */ +}; + +/*! @brief ADMA descriptor configuration flag */ +enum _usdhc_adma_flag +{ + kUSDHC_AdmaDescriptorSingleFlag = + 0U, /*!< try to finish the transfer in a single ADMA descriptor, if transfer size is bigger than one + ADMA descriptor's ability, new another descriptor for data transfer */ + kUSDHC_AdmaDescriptorMultipleFlag = 1U, /*!< create multiple ADMA descriptor within the ADMA table, this is used for + mmc boot mode specifically, which need + to modify the ADMA descriptor on the fly, so the flag should be used + combine with stop at block gap feature */ +}; + +/*! @brief dma transfer burst len config. */ +typedef enum _usdhc_burst_len +{ + kUSDHC_EnBurstLenForINCR = 0x01U, /*!< enable burst len for INCR */ + kUSDHC_EnBurstLenForINCR4816 = 0x02U, /*!< enable burst len for INCR4/INCR8/INCR16 */ + kUSDHC_EnBurstLenForINCR4816WRAP = 0x04U, /*!< enable burst len for INCR4/8/16 WRAP */ +} usdhc_burst_len_t; + +/*! @brief transfer data type definition. */ +enum _usdhc_transfer_data_type +{ + kUSDHC_TransferDataNormal = 0U, /*!< transfer normal read/write data */ + kUSDHC_TransferDataTuning = 1U, /*!< transfer tuning data */ + kUSDHC_TransferDataBoot = 2U, /*!< transfer boot data */ + kUSDHC_TransferDataBootcontinous = 3U, /*!< transfer boot data continous */ +}; + +/*! @brief Defines the adma1 descriptor structure. */ +typedef uint32_t usdhc_adma1_descriptor_t; + +/*! @brief Defines the ADMA2 descriptor structure. */ +typedef struct _usdhc_adma2_descriptor +{ + uint32_t attribute; /*!< The control and status field */ + const uint32_t *address; /*!< The address field */ +} usdhc_adma2_descriptor_t; + +/*! + * @brief USDHC capability information. + * + * Defines a structure to save the capability information of USDHC. + */ +typedef struct _usdhc_capability +{ + uint32_t sdVersion; /*!< support SD card/sdio version */ + uint32_t mmcVersion; /*!< support emmc card version */ + uint32_t maxBlockLength; /*!< Maximum block length united as byte */ + uint32_t maxBlockCount; /*!< Maximum block count can be set one time */ + uint32_t flags; /*!< Capability flags to indicate the support information(_usdhc_capability_flag) */ +} usdhc_capability_t; + +/*! @brief Data structure to configure the MMC boot feature */ +typedef struct _usdhc_boot_config +{ + uint32_t ackTimeoutCount; /*!< Timeout value for the boot ACK. The available range is 0 ~ 15. */ + usdhc_boot_mode_t bootMode; /*!< Boot mode selection. */ + uint32_t blockCount; /*!< Stop at block gap value of automatic mode. Available range is 0 ~ 65535. */ + size_t blockSize; /*!< Block size */ + bool enableBootAck; /*!< Enable or disable boot ACK */ + bool enableAutoStopAtBlockGap; /*!< Enable or disable auto stop at block gap function in boot period */ +} usdhc_boot_config_t; + +/*! @brief Data structure to initialize the USDHC */ +typedef struct _usdhc_config +{ + uint32_t dataTimeout; /*!< Data timeout value */ + usdhc_endian_mode_t endianMode; /*!< Endian mode */ + uint8_t readWatermarkLevel; /*!< Watermark level for DMA read operation. Available range is 1 ~ 128. */ + uint8_t writeWatermarkLevel; /*!< Watermark level for DMA write operation. Available range is 1 ~ 128. */ + uint8_t readBurstLen; /*!< Read burst len */ + uint8_t writeBurstLen; /*!< Write burst len */ +} usdhc_config_t; + +/*! + * @brief Card data descriptor + * + * Defines a structure to contain data-related attribute. 'enableIgnoreError' is used for the case that upper card + * driver + * want to ignore the error event to read/write all the data not to stop read/write immediately when error event + * happen for example bus testing procedure for MMC card. + */ +typedef struct _usdhc_data +{ + bool enableAutoCommand12; /*!< Enable auto CMD12 */ + bool enableAutoCommand23; /*!< Enable auto CMD23 */ + bool enableIgnoreError; /*!< Enable to ignore error event to read/write all the data */ + uint8_t dataType; /*!< this is used to distinguish the normal/tuning/boot data */ + size_t blockSize; /*!< Block size */ + uint32_t blockCount; /*!< Block count */ + uint32_t *rxData; /*!< Buffer to save data read */ + const uint32_t *txData; /*!< Data buffer to write */ +} usdhc_data_t; + +/*! + * @brief Card command descriptor + * + * Define card command-related attribute. + */ +typedef struct _usdhc_command +{ + uint32_t index; /*!< Command index */ + uint32_t argument; /*!< Command argument */ + usdhc_card_command_type_t type; /*!< Command type */ + usdhc_card_response_type_t responseType; /*!< Command response type */ + uint32_t response[4U]; /*!< Response for this command */ + uint32_t responseErrorFlags; /*!< response error flag, the flag which need to check + the command reponse*/ + uint32_t flags; /*!< Cmd flags */ +} usdhc_command_t; + +/*! @brief ADMA configuration */ +typedef struct _usdhc_adma_config +{ + usdhc_dma_mode_t dmaMode; /*!< DMA mode */ + + usdhc_burst_len_t burstLen; /*!< burst len config */ + + uint32_t *admaTable; /*!< ADMA table address, can't be null if transfer way is ADMA1/ADMA2 */ + uint32_t admaTableWords; /*!< ADMA table length united as words, can't be 0 if transfer way is ADMA1/ADMA2 */ +} usdhc_adma_config_t; + +/*! @brief Transfer state */ +typedef struct _usdhc_transfer +{ + usdhc_data_t *data; /*!< Data to transfer */ + usdhc_command_t *command; /*!< Command to send */ +} usdhc_transfer_t; + +/*! @brief USDHC handle typedef */ +typedef struct _usdhc_handle usdhc_handle_t; + +/*! @brief USDHC callback functions. */ +typedef struct _usdhc_transfer_callback +{ + void (*CardInserted)(USDHC_Type *base, + void *userData); /*!< Card inserted occurs when DAT3/CD pin is for card detect */ + void (*CardRemoved)(USDHC_Type *base, void *userData); /*!< Card removed occurs */ + void (*SdioInterrupt)(USDHC_Type *base, void *userData); /*!< SDIO card interrupt occurs */ + void (*BlockGap)(USDHC_Type *base, void *userData); /*!< stopped at block gap event */ + void (*TransferComplete)(USDHC_Type *base, + usdhc_handle_t *handle, + status_t status, + void *userData); /*!< Transfer complete callback */ + void (*ReTuning)(USDHC_Type *base, void *userData); /*!< handle the re-tuning */ +} usdhc_transfer_callback_t; + +/*! + * @brief USDHC handle + * + * Defines the structure to save the USDHC state information and callback function. The detailed interrupt status when + * sending a command or transfering data can be obtained from the interruptFlags field by using the mask defined in + * usdhc_interrupt_flag_t. + * + * @note All the fields except interruptFlags and transferredWords must be allocated by the user. + */ +struct _usdhc_handle +{ + /* Transfer parameter */ + usdhc_data_t *volatile data; /*!< Data to transfer */ + usdhc_command_t *volatile command; /*!< Command to send */ + + /* Transfer status */ + volatile uint32_t transferredWords; /*!< Words transferred by DATAPORT way */ + + /* Callback functions */ + usdhc_transfer_callback_t callback; /*!< Callback function */ + void *userData; /*!< Parameter for transfer complete callback */ +}; + +/*! @brief USDHC transfer function. */ +typedef status_t (*usdhc_transfer_function_t)(USDHC_Type *base, usdhc_transfer_t *content); + +/*! @brief USDHC host descriptor */ +typedef struct _usdhc_host +{ + USDHC_Type *base; /*!< USDHC peripheral base address */ + uint32_t sourceClock_Hz; /*!< USDHC source clock frequency united in Hz */ + usdhc_config_t config; /*!< USDHC configuration */ + usdhc_capability_t capability; /*!< USDHC capability information */ + usdhc_transfer_function_t transfer; /*!< USDHC transfer function */ +} usdhc_host_t; + +/************************************************************************************************* + * API + ************************************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name Initialization and deinitialization + * @{ + */ + +/*! + * @brief USDHC module initialization function. + * + * Configures the USDHC according to the user configuration. + * + * Example: + @code + usdhc_config_t config; + config.cardDetectDat3 = false; + config.endianMode = kUSDHC_EndianModeLittle; + config.dmaMode = kUSDHC_DmaModeAdma2; + config.readWatermarkLevel = 128U; + config.writeWatermarkLevel = 128U; + USDHC_Init(USDHC, &config); + @endcode + * + * @param base USDHC peripheral base address. + * @param config USDHC configuration information. + * @retval kStatus_Success Operate successfully. + */ +void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config); + +/*! + * @brief Deinitializes the USDHC. + * + * @param base USDHC peripheral base address. + */ +void USDHC_Deinit(USDHC_Type *base); + +/*! + * @brief Resets the USDHC. + * + * @param base USDHC peripheral base address. + * @param mask The reset type mask(_usdhc_reset). + * @param timeout Timeout for reset. + * @retval true Reset successfully. + * @retval false Reset failed. + */ +bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout); + +/* @} */ + +/*! + * @name DMA Control + * @{ + */ + +/*! + * @brief Sets the DMA descriptor table configuration. + * A high level DMA descriptor configuration function. + * @param base USDHC peripheral base address. + * @param adma configuration + * @param data Data descriptor + * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * reference _usdhc_adma_flag + * @retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * @retval kStatus_Success Operate successfully. + */ +status_t USDHC_SetAdmaTableConfig(USDHC_Type *base, + usdhc_adma_config_t *dmaConfig, + usdhc_data_t *dataConfig, + uint32_t flags); + +/*! + * @brief Internal DMA configuration. + * This function is used to config the USDHC DMA related registers. + * @param base USDHC peripheral base address. + * @param adma configuration + * @param dataAddr transfer data address, a simple DMA parameter, if ADMA is used, leave it to NULL. + * @param enAutoCmd23 flag to indicate Auto CMD23 is enable or not, a simple DMA parameter,if ADMA is used, leave it + * to false. + * @retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * @retval kStatus_Success Operate successfully. + */ +status_t USDHC_SetInternalDmaConfig(USDHC_Type *base, + usdhc_adma_config_t *dmaConfig, + const uint32_t *dataAddr, + bool enAutoCmd23); + +/*! + * @brief Sets the ADMA2 descriptor table configuration. + * + * @param admaTable Adma table address. + * @param admaTableWords Adma table length. + * @param dataBufferAddr Data buffer address. + * @param dataBytes Data Data length. + * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * reference _usdhc_adma_flag. + * @retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * @retval kStatus_Success Operate successfully. + */ +status_t USDHC_SetADMA2Descriptor( + uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags); + +/*! + * @brief Sets the ADMA1 descriptor table configuration. + * + * @param admaTable Adma table address. + * @param admaTableWords Adma table length. + * @param dataBufferAddr Data buffer address. + * @param dataBytes Data length. + * @param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please + * reference _usdhc_adma_flag. + * @retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data. + * @retval kStatus_Success Operate successfully. + */ +status_t USDHC_SetADMA1Descriptor( + uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags); + +/*! + * @brief enable internal DMA. + * + * @param base USDHC peripheral base address. + * @param enable enable or disable flag + */ +static inline void USDHC_EnableInternalDMA(USDHC_Type *base, bool enable) +{ + if (enable) + { + base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK; + } + else + { + base->MIX_CTRL &= ~USDHC_MIX_CTRL_DMAEN_MASK; + base->PROT_CTRL &= ~USDHC_PROT_CTRL_DMASEL_MASK; + } +} + +/* @} */ + +/*! + * @name Interrupts + * @{ + */ + +/*! + * @brief Enables the interrupt status. + * + * @param base USDHC peripheral base address. + * @param mask Interrupt status flags mask(_usdhc_interrupt_status_flag). + */ +static inline void USDHC_EnableInterruptStatus(USDHC_Type *base, uint32_t mask) +{ + base->INT_STATUS_EN |= mask; +} + +/*! + * @brief Disables the interrupt status. + * + * @param base USDHC peripheral base address. + * @param mask The interrupt status flags mask(_usdhc_interrupt_status_flag). + */ +static inline void USDHC_DisableInterruptStatus(USDHC_Type *base, uint32_t mask) +{ + base->INT_STATUS_EN &= ~mask; +} + +/*! + * @brief Enables the interrupt signal corresponding to the interrupt status flag. + * + * @param base USDHC peripheral base address. + * @param mask The interrupt status flags mask(_usdhc_interrupt_status_flag). + */ +static inline void USDHC_EnableInterruptSignal(USDHC_Type *base, uint32_t mask) +{ + base->INT_SIGNAL_EN |= mask; +} + +/*! + * @brief Disables the interrupt signal corresponding to the interrupt status flag. + * + * @param base USDHC peripheral base address. + * @param mask The interrupt status flags mask(_usdhc_interrupt_status_flag). + */ +static inline void USDHC_DisableInterruptSignal(USDHC_Type *base, uint32_t mask) +{ + base->INT_SIGNAL_EN &= ~mask; +} + +/* @} */ + +/*! + * @name Status + * @{ + */ + +/*! + * @brief Gets the enabled interrupt status. + * + * @param base USDHC peripheral base address. + * @return Current interrupt status flags mask(_usdhc_interrupt_status_flag). + */ +static inline uint32_t USDHC_GetEnabledInterruptStatusFlags(USDHC_Type *base) +{ + return (base->INT_STATUS) & (base->INT_SIGNAL_EN); +} + +/*! + * @brief Gets the current interrupt status. + * + * @param base USDHC peripheral base address. + * @return Current interrupt status flags mask(_usdhc_interrupt_status_flag). + */ +static inline uint32_t USDHC_GetInterruptStatusFlags(USDHC_Type *base) +{ + return base->INT_STATUS; +} + +/*! + * @brief Clears a specified interrupt status. + * write 1 clears + * @param base USDHC peripheral base address. + * @param mask The interrupt status flags mask(_usdhc_interrupt_status_flag). + */ +static inline void USDHC_ClearInterruptStatusFlags(USDHC_Type *base, uint32_t mask) +{ + base->INT_STATUS = mask; +} + +/*! + * @brief Gets the status of auto command 12 error. + * + * @param base USDHC peripheral base address. + * @return Auto command 12 error status flags mask(_usdhc_auto_command12_error_status_flag). + */ +static inline uint32_t USDHC_GetAutoCommand12ErrorStatusFlags(USDHC_Type *base) +{ + return base->AUTOCMD12_ERR_STATUS; +} + +/*! + * @brief Gets the status of the ADMA error. + * + * @param base USDHC peripheral base address. + * @return ADMA error status flags mask(_usdhc_adma_error_status_flag). + */ +static inline uint32_t USDHC_GetAdmaErrorStatusFlags(USDHC_Type *base) +{ + return base->ADMA_ERR_STATUS & 0xFU; +} + +/*! + * @brief Gets a present status. + * + * This function gets the present USDHC's status except for an interrupt status and an error status. + * + * @param base USDHC peripheral base address. + * @return Present USDHC's status flags mask(_usdhc_present_status_flag). + */ +static inline uint32_t USDHC_GetPresentStatusFlags(USDHC_Type *base) +{ + return base->PRES_STATE; +} + +/* @} */ + +/*! + * @name Bus Operations + * @{ + */ + +/*! + * @brief Gets the capability information. + * + * @param base USDHC peripheral base address. + * @param capability Structure to save capability information. + */ +void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability); + +/*! + * @brief force the card clock on. + * + * @param base USDHC peripheral base address. + * @param enable/disable flag. + */ +static inline void USDHC_ForceClockOn(USDHC_Type *base, bool enable) +{ + if (enable) + { + base->VEND_SPEC |= USDHC_VEND_SPEC_FRC_SDCLK_ON_MASK; + } + else + { + base->VEND_SPEC &= ~USDHC_VEND_SPEC_FRC_SDCLK_ON_MASK; + } +} + +/*! + * @brief Sets the SD bus clock frequency. + * + * @param base USDHC peripheral base address. + * @param srcClock_Hz USDHC source clock frequency united in Hz. + * @param busClock_Hz SD bus clock frequency united in Hz. + * + * @return The nearest frequency of busClock_Hz configured to SD bus. + */ +uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz); + +/*! + * @brief Sends 80 clocks to the card to set it to the active state. + * + * This function must be called each time the card is inserted to ensure that the card can receive the command + * correctly. + * + * @param base USDHC peripheral base address. + * @param timeout Timeout to initialize card. + * @retval true Set card active successfully. + * @retval false Set card active failed. + */ +bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout); + +/*! + * @brief trigger a hardware reset. + * + * @param base USDHC peripheral base address. + * @param 1 or 0 level + */ +static inline void USDHC_AssertHardwareReset(USDHC_Type *base, bool high) +{ + if (high) + { + base->SYS_CTRL |= USDHC_SYS_CTRL_IPP_RST_N_MASK; + } + else + { + base->SYS_CTRL &= ~USDHC_SYS_CTRL_IPP_RST_N_MASK; + } +} + +/*! + * @brief Sets the data transfer width. + * + * @param base USDHC peripheral base address. + * @param width Data transfer width. + */ +static inline void USDHC_SetDataBusWidth(USDHC_Type *base, usdhc_data_bus_width_t width) +{ + base->PROT_CTRL = ((base->PROT_CTRL & ~USDHC_PROT_CTRL_DTW_MASK) | USDHC_PROT_CTRL_DTW(width)); +} + +/*! + * @brief Fills the data port. + * + * This function is used to implement the data transfer by Data Port instead of DMA. + * + * @param base USDHC peripheral base address. + * @param data The data about to be sent. + */ +static inline void USDHC_WriteData(USDHC_Type *base, uint32_t data) +{ + base->DATA_BUFF_ACC_PORT = data; +} + +/*! + * @brief Retrieves the data from the data port. + * + * This function is used to implement the data transfer by Data Port instead of DMA. + * + * @param base USDHC peripheral base address. + * @return The data has been read. + */ +static inline uint32_t USDHC_ReadData(USDHC_Type *base) +{ + return base->DATA_BUFF_ACC_PORT; +} + +/*! + * @brief send command function + * + * @param base USDHC peripheral base address. + * @param command configuration + */ +void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command); + +/*! + * @brief Enables or disables a wakeup event in low-power mode. + * + * @param base USDHC peripheral base address. + * @param mask Wakeup events mask(_usdhc_wakeup_event). + * @param enable True to enable, false to disable. + */ +static inline void USDHC_EnableWakeupEvent(USDHC_Type *base, uint32_t mask, bool enable) +{ + if (enable) + { + base->PROT_CTRL |= mask; + } + else + { + base->PROT_CTRL &= ~mask; + } +} + +/*! + * @brief detect card insert status. + * + * @param base USDHC peripheral base address. + * @param enable/disable flag + */ +static inline void USDHC_CardDetectByData3(USDHC_Type *base, bool enable) +{ + if (enable) + { + base->PROT_CTRL |= USDHC_PROT_CTRL_D3CD_MASK; + } + else + { + base->PROT_CTRL &= ~USDHC_PROT_CTRL_D3CD_MASK; + } +} + +/*! + * @brief detect card insert status. + * + * @param base USDHC peripheral base address. + */ +static inline bool USDHC_DetectCardInsert(USDHC_Type *base) +{ + return (base->PRES_STATE & kUSDHC_CardInsertedFlag) ? true : false; +} + +/*! + * @brief Enables or disables the SDIO card control. + * + * @param base USDHC peripheral base address. + * @param mask SDIO card control flags mask(_usdhc_sdio_control_flag). + * @param enable True to enable, false to disable. + */ +static inline void USDHC_EnableSdioControl(USDHC_Type *base, uint32_t mask, bool enable) +{ + if (enable) + { + base->PROT_CTRL |= mask; + } + else + { + base->PROT_CTRL &= ~mask; + } +} + +/*! + * @brief Restarts a transaction which has stopped at the block GAP for the SDIO card. + * + * @param base USDHC peripheral base address. + */ +static inline void USDHC_SetContinueRequest(USDHC_Type *base) +{ + base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK; +} + +/*! + * @brief Request stop at block gap function. + * + * @param base USDHC peripheral base address. + * @param enable true to stop at block gap, false to normal transfer + */ +static inline void USDHC_RequestStopAtBlockGap(USDHC_Type *base, bool enable) +{ + if (enable) + { + base->PROT_CTRL |= USDHC_PROT_CTRL_SABGREQ_MASK; + } + else + { + base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK; + } +} + +/*! + * @brief Configures the MMC boot feature. + * + * Example: + @code + usdhc_boot_config_t config; + config.ackTimeoutCount = 4; + config.bootMode = kUSDHC_BootModeNormal; + config.blockCount = 5; + config.enableBootAck = true; + config.enableBoot = true; + config.enableAutoStopAtBlockGap = true; + USDHC_SetMmcBootConfig(USDHC, &config); + @endcode + * + * @param base USDHC peripheral base address. + * @param config The MMC boot configuration information. + */ +void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config); + +/*! + * @brief Enables or disables the mmc boot mode. + * + * @param base USDHC peripheral base address. + * @param enable True to enable, false to disable. + */ +static inline void USDHC_EnableMmcBoot(USDHC_Type *base, bool enable) +{ + if (enable) + { + base->MMC_BOOT |= USDHC_MMC_BOOT_BOOT_EN_MASK; + } + else + { + base->MMC_BOOT &= ~USDHC_MMC_BOOT_BOOT_EN_MASK; + } +} + +/*! + * @brief Forces generating events according to the given mask. + * + * @param base USDHC peripheral base address. + * @param mask The force events bit posistion (_usdhc_force_event). + */ +static inline void USDHC_SetForceEvent(USDHC_Type *base, uint32_t mask) +{ + base->FORCE_EVENT = mask; +} + +/*! + * @brief select the usdhc output voltage + * + * @param base USDHC peripheral base address. + * @param true 1.8V, false 3.0V + */ +static inline void UDSHC_SelectVoltage(USDHC_Type *base, bool en18v) +{ + if (en18v) + { + base->VEND_SPEC |= USDHC_VEND_SPEC_VSELECT_MASK; + } + else + { + base->VEND_SPEC &= ~USDHC_VEND_SPEC_VSELECT_MASK; + } +} + +#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) +/*! + * @brief check the SDR50 mode request tuning bit + * When this bit set, user should call USDHC_StandardTuning function + * @param base USDHC peripheral base address. + */ +static inline bool USDHC_RequestTuningForSDR50(USDHC_Type *base) +{ + return base->HOST_CTRL_CAP & USDHC_HOST_CTRL_CAP_USE_TUNING_SDR50_MASK ? true : false; +} + +/*! + * @brief check the request re-tuning bit + * When this bit is set, user should do manual tuning or standard tuning function + * @param base USDHC peripheral base address. + */ +static inline bool USDHC_RequestReTuning(USDHC_Type *base) +{ + return base->PRES_STATE & USDHC_PRES_STATE_RTR_MASK ? true : false; +} + +/*! + * @brief the SDR104 mode auto tuning enable and disable + * This function should call after tuning function execute pass, auto tuning will handle + * by hardware + * @param base USDHC peripheral base address. + * @param enable/disable flag + */ +static inline void USDHC_EnableAutoTuning(USDHC_Type *base, bool enable) +{ + if (enable) + { + base->MIX_CTRL |= USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK; + } + else + { + base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK; + } +} + +/*! + * @brief the config the re-tuning timer for mode 1 and mode 3 + * This timer is used for standard tuning auto re-tuning, + * @param base USDHC peripheral base address. + * @param timer counter value + */ +static inline void USDHC_SetRetuningTimer(USDHC_Type *base, uint32_t counter) +{ + base->HOST_CTRL_CAP &= ~USDHC_HOST_CTRL_CAP_TIME_COUNT_RETUNING_MASK; + base->HOST_CTRL_CAP |= USDHC_HOST_CTRL_CAP_TIME_COUNT_RETUNING(counter); +} + +/*! + * @brief the auto tuning enbale for CMD/DATA line + * + * @param base USDHC peripheral base address. + */ +void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base); + +/*! + * @brief manual tuning trigger or abort + * User should handle the tuning cmd and find the boundary of the delay + * then calucate a average value which will be config to the CLK_TUNE_CTRL_STATUS + * This function should called before USDHC_AdjustDelayforSDR104 function + * @param base USDHC peripheral base address. + * @param tuning enable flag + */ +void USDHC_EnableManualTuning(USDHC_Type *base, bool enable); + +/*! + * @brief the SDR104 mode delay setting adjust + * This function should called after USDHC_ManualTuningForSDR104 + * @param base USDHC peripheral base address. + * @param delay setting configuration + * @retval kStatus_Fail config the delay setting fail + * @retval kStatus_Success config the delay setting success + */ +status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay); + +/*! + * @brief the enable standard tuning function + * The standard tuning window and tuning counter use the default config + * tuning cmd is send by the software, user need to check the tuning result + * can be used for SDR50,SDR104,HS200 mode tuning + * @param base USDHC peripheral base address. + * @param tuning start tap + * @param tuning step + * @param enable/disable flag + */ +void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable); + +/*! + * @brief Get execute std tuning status + * + * @param base USDHC peripheral base address. + */ +static inline uint32_t USDHC_GetExecuteStdTuningStatus(USDHC_Type *base) +{ + return (base->AUTOCMD12_ERR_STATUS & USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK); +} + +/*! + * @brief check std tuning result + * + * @param base USDHC peripheral base address. + */ +static inline uint32_t USDHC_CheckStdTuningResult(USDHC_Type *base) +{ + return (base->AUTOCMD12_ERR_STATUS & USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK); +} + +/*! + * @brief check tuning error + * + * @param base USDHC peripheral base address. + */ +static inline uint32_t USDHC_CheckTuningError(USDHC_Type *base) +{ + return (base->CLK_TUNE_CTRL_STATUS & + (USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK)); +} + +#endif +/*! + * @brief the enable/disable DDR mode + * + * @param base USDHC peripheral base address. + * @param enable/disable flag + * @param nibble position + */ +void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos); + +/*! + * @brief the enable/disable HS400 mode + * + * @param base USDHC peripheral base address. + * @param enable/disable flag + */ +#if FSL_FEATURE_USDHC_HAS_HS400_MODE +static inline void USDHC_EnableHS400Mode(USDHC_Type *base, bool enable) +{ + if (enable) + { + base->MIX_CTRL |= USDHC_MIX_CTRL_HS400_MODE_MASK; + } + else + { + base->MIX_CTRL &= ~USDHC_MIX_CTRL_HS400_MODE_MASK; + } +} + +/*! + * @brief reset the strobe DLL + * + * @param base USDHC peripheral base address. + */ +static inline void USDHC_ResetStrobeDLL(USDHC_Type *base) +{ + base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_RESET_MASK; +} + +/*! + * @brief enable/disable the strobe DLL + * + * @param base USDHC peripheral base address. + * @param enable/disable flag + */ +static inline void USDHC_EnableStrobeDLL(USDHC_Type *base, bool enable) +{ + if (enable) + { + base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK; + } + else + { + base->STROBE_DLL_CTRL &= ~USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK; + } +} + +/*! + * @brief config the strobe DLL delay target and update interval + * + * @param base USDHC peripheral base address. + * @param delay target + * @param update interval + */ +static inline void USDHC_ConfigStrobeDLL(USDHC_Type *base, uint32_t delayTarget, uint32_t updateInterval) +{ + base->STROBE_DLL_CTRL &= (USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_UPDATE_INT_MASK | + USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_MASK); + + base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_UPDATE_INT(updateInterval) | + USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET(delayTarget); +} + +/*! + * @brief get the strobe DLL status + * + * @param base USDHC peripheral base address. + */ +static inline uint32_t USDHC_GetStrobeDLLStatus(USDHC_Type *base) +{ + return base->STROBE_DLL_STATUS; +} + +#endif + +/* @} */ + +/*! + * @name Transactional + * @{ + */ + +/*! + * @brief Transfers the command/data using a blocking method. + * + * This function waits until the command response/data is received or the USDHC encounters an error by polling the + * status + * flag. + * The application must not call this API in multiple threads at the same time. Because of that this API doesn't + * support the re-entry mechanism. + * + * @note There is no need to call the API 'USDHC_TransferCreateHandle' when calling this API. + * + * @param base USDHC peripheral base address. + * @param adma configuration + * @param transfer Transfer content. + * @retval kStatus_InvalidArgument Argument is invalid. + * @retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. + * @retval kStatus_USDHC_SendCommandFailed Send command failed. + * @retval kStatus_USDHC_TransferDataFailed Transfer data failed. + * @retval kStatus_Success Operate successfully. + */ +status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer); + +/*! + * @brief Creates the USDHC handle. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle pointer. + * @param callback Structure pointer to contain all callback functions. + * @param userData Callback function parameter. + */ +void USDHC_TransferCreateHandle(USDHC_Type *base, + usdhc_handle_t *handle, + const usdhc_transfer_callback_t *callback, + void *userData); + +/*! + * @brief Transfers the command/data using an interrupt and an asynchronous method. + * + * This function sends a command and data and returns immediately. It doesn't wait the transfer complete or + * encounter an error. The application must not call this API in multiple threads at the same time. Because of that + * this API doesn't support the re-entry mechanism. + * + * @note Call the API 'USDHC_TransferCreateHandle' when calling this API. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle. + * @param adma configuration. + * @param transfer Transfer content. + * @retval kStatus_InvalidArgument Argument is invalid. + * @retval kStatus_USDHC_BusyTransferring Busy transferring. + * @retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed. + * @retval kStatus_Success Operate successfully. + */ +status_t USDHC_TransferNonBlocking(USDHC_Type *base, + usdhc_handle_t *handle, + usdhc_adma_config_t *dmaConfig, + usdhc_transfer_t *transfer); + +/*! + * @brief IRQ handler for the USDHC. + * + * This function deals with the IRQs on the given host controller. + * + * @param base USDHC peripheral base address. + * @param handle USDHC handle. + */ +void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle); + +/* @} */ + +#if defined(__cplusplus) +} +#endif +/*! @} */ + +#endif /* _FSL_USDHC_H_*/ 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 index f06c0d26e..7db5f08f9 100644 --- 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 @@ -188,16 +188,12 @@ static uint32 SdioConfigure(void *drv, struct BusConfigureInfo *configure_info) 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); + NULL_PARAM_CHECK(configure_info->private_data); + struct DeviceBlockArrange *args = (struct DeviceBlockArrange *)configure_info->private_data; - // // 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; + args->size_perbank = g_sd.blockSize; + args->block_size = g_sd.blockSize; + args->bank_num = g_sd.blockCount; } return EOK; @@ -230,37 +226,18 @@ static uint32 SdioClose(void *dev) static uint32 SdioRead(void *dev, struct BusBlockReadParam *read_param) { uint8 ret = EOK; + uint32 sector = read_param->pos; + uint32 block_num = read_param->size; + uint8 *read_buffer = (uint8 *)read_param->buffer; KSemaphoreObtain(sd_lock, WAITING_FOREVER); - // if (((uint32)read_param->buffer & 0x03) != 0) { - // uint64_t sector; - // uint8_t* temp; + if (kStatus_Success != SD_ReadBlocks(&g_sd, read_buffer, sector, block_num)) { + KPrintf("Read multiple data blocks failed.\r\n"); + return 0; + } - // 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); + KSemaphoreAbandon(sd_lock); return read_param->size; } @@ -268,35 +245,16 @@ static uint32 SdioRead(void *dev, struct BusBlockReadParam *read_param) static uint32 SdioWrite(void *dev, struct BusBlockWriteParam *write_param) { uint8 ret = EOK; + uint32 sector = write_param->pos; + uint32 block_num = write_param->size; + const uint8 *write_buffer = (uint8 *)write_param->buffer; - // KSemaphoreObtain(sd_lock, WAITING_FOREVER); + 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; - // } - // } + if (kStatus_Success != SD_WriteBlocks(&g_sd, write_buffer, sector, block_num)) { + KPrintf("Write multiple data blocks failed.\r\n"); + return 0; + } KSemaphoreAbandon(sd_lock); From 2ecded6feb4ec7b89e9702c84e844493c4a46e8e Mon Sep 17 00:00:00 2001 From: Liu_Weichao Date: Wed, 9 Feb 2022 09:55:48 +0800 Subject: [PATCH 3/5] set sd device function default off --- Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig index b43f274f1..ef9867af5 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig @@ -20,7 +20,7 @@ menuconfig BSP_USING_SEMC menuconfig BSP_USING_SDIO bool "Using SD card device" - default y + default n select RESOURCES_SDIO if BSP_USING_SDIO source "$BSP_DIR/third_party_driver/sdio/Kconfig" From 84b27692c01c09a4fb53939531cb62f5259b5f5b Mon Sep 17 00:00:00 2001 From: Liu_Weichao Date: Thu, 17 Feb 2022 15:18:27 +0800 Subject: [PATCH 4/5] feat support USB HOST for ok1052-c board --- .../XiUOS/arch/arm/cortex-m7/arch_interrupt.h | 3 + .../XiUOS/board/aiit-arm32-board/.defconfig | 2 +- .../third_party_driver/Kconfig | 2 +- .../third_party_driver/usb/Kconfig | 4 +- .../third_party_driver/usb/usbh.c | 2 +- Ubiquitous/XiUOS/board/ok1052-c/link.lds | 4 +- .../board/ok1052-c/third_party_driver/Kconfig | 8 + .../ok1052-c/third_party_driver/Makefile | 4 + .../third_party_driver/include/connect_usb.h | 53 + .../ok1052-c/third_party_driver/usb/Kconfig | 15 + .../ok1052-c/third_party_driver/usb/Makefile | 5 + .../third_party_driver/usb/connect_usb.c | 296 + .../usb/nxp_usb_driver/Makefile | 5 + .../usb/nxp_usb_driver/host/Makefile | 5 + .../usb/nxp_usb_driver/host/class/Makefile | 3 + .../nxp_usb_driver/host/class/usb_host_hub.c | 608 +++ .../nxp_usb_driver/host/class/usb_host_hub.h | 379 ++ .../host/class/usb_host_hub_app.c | 1631 ++++++ .../host/class/usb_host_hub_app.h | 87 + .../nxp_usb_driver/host/class/usb_host_msd.c | 1137 ++++ .../nxp_usb_driver/host/class/usb_host_msd.h | 851 +++ .../host/class/usb_host_msd_ufi.c | 451 ++ .../usb/nxp_usb_driver/host/usb_host.h | 705 +++ .../nxp_usb_driver/host/usb_host_devices.c | 1393 +++++ .../nxp_usb_driver/host/usb_host_devices.h | 156 + .../usb/nxp_usb_driver/host/usb_host_ehci.c | 4796 +++++++++++++++++ .../usb/nxp_usb_driver/host/usb_host_ehci.h | 477 ++ .../nxp_usb_driver/host/usb_host_framework.c | 361 ++ .../nxp_usb_driver/host/usb_host_framework.h | 85 + .../usb/nxp_usb_driver/host/usb_host_hci.c | 1047 ++++ .../usb/nxp_usb_driver/host/usb_host_hci.h | 109 + .../usb/nxp_usb_driver/host_msd_command.c | 699 +++ .../nxp_usb_driver/include/host_msd_command.h | 83 + .../usb/nxp_usb_driver/include/usb.h | 136 + .../nxp_usb_driver/include/usb_host_config.h | 240 + .../usb/nxp_usb_driver/include/usb_misc.h | 452 ++ .../usb/nxp_usb_driver/include/usb_spec.h | 300 ++ .../usb/nxp_usb_driver/osa/Makefile | 3 + .../usb/nxp_usb_driver/osa/usb_osa.h | 577 ++ .../usb/nxp_usb_driver/osa/usb_osa_bm.c | 522 ++ .../usb/nxp_usb_driver/osa/usb_osa_bm.h | 35 + .../usb/nxp_usb_driver/phy/Makefile | 3 + .../usb/nxp_usb_driver/phy/usb_phy.c | 243 + .../usb/nxp_usb_driver/phy/usb_phy.h | 91 + .../XiUOS/board/stm32f103-nano/.defconfig | 2 +- .../board/stm32f407-st-discovery/.defconfig | 2 +- .../third_party_driver/Kconfig | 2 +- .../third_party_driver/usb/Kconfig | 2 +- .../third_party_driver/usb/usbh.c | 2 +- .../XiUOS/board/stm32f407zgt6/.defconfig | 2 +- Ubiquitous/XiUOS/kernel/thread/init.c | 7 +- Ubiquitous/XiUOS/path_kernel.mk | 5 + Ubiquitous/XiUOS/resources/include/device.h | 2 +- .../{usb_common.h => stm32_usb_common.h} | 4 +- .../include/{usb_host.h => stm32_usb_host.h} | 6 +- .../resources/usb/third_party_usb/Makefile | 4 +- .../usb/third_party_usb/usbhost/class/mass.c | 2 +- .../usb/third_party_usb/usbhost/class/udisk.c | 2 +- .../usb/third_party_usb/usbhost/core/core.c | 2 +- .../usb/third_party_usb/usbhost/core/driver.c | 2 +- .../usb/third_party_usb/usbhost/core/hub.c | 2 +- .../third_party_usb/usbhost/core/usbhost.c | 2 +- 62 files changed, 18092 insertions(+), 28 deletions(-) create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_usb.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/Kconfig create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/connect_usb.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub_app.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub_app.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd_ufi.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_devices.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_devices.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_ehci.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_ehci.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_framework.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_framework.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_hci.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_hci.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host_msd_command.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/host_msd_command.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_host_config.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_misc.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_spec.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa_bm.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa_bm.h create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/Makefile create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/usb_phy.c create mode 100644 Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/usb_phy.h rename Ubiquitous/XiUOS/resources/include/{usb_common.h => stm32_usb_common.h} (99%) rename Ubiquitous/XiUOS/resources/include/{usb_host.h => stm32_usb_host.h} (98%) diff --git a/Ubiquitous/XiUOS/arch/arm/cortex-m7/arch_interrupt.h b/Ubiquitous/XiUOS/arch/arm/cortex-m7/arch_interrupt.h index 589d49e28..f75920620 100644 --- a/Ubiquitous/XiUOS/arch/arm/cortex-m7/arch_interrupt.h +++ b/Ubiquitous/XiUOS/arch/arm/cortex-m7/arch_interrupt.h @@ -29,6 +29,9 @@ #define UART1_IRQn 20 #define UART2_IRQn 21 +#define USB1_IRQn 113 +#define USB2_IRQn 112 + int32 ArchEnableHwIrq(uint32 irq_num); int32 ArchDisableHwIrq(uint32 irq_num); diff --git a/Ubiquitous/XiUOS/board/aiit-arm32-board/.defconfig b/Ubiquitous/XiUOS/board/aiit-arm32-board/.defconfig index 028b6dbab..08045f21c 100644 --- a/Ubiquitous/XiUOS/board/aiit-arm32-board/.defconfig +++ b/Ubiquitous/XiUOS/board/aiit-arm32-board/.defconfig @@ -28,7 +28,7 @@ CONFIG_BSP_USING_UART=y # CONFIG_BSP_USING_UART4 is not set # CONFIG_BSP_USING_UART5 is not set # CONFIG_BSP_USING_USB is not set -# CONFIG_BSP_USING_USBH is not set +# CONFIG_BSP_USING_STM32_USBH is not set # # Hardware feature diff --git a/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/Kconfig b/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/Kconfig index 8dbc94076..a7978bc61 100755 --- a/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/Kconfig +++ b/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/Kconfig @@ -120,7 +120,7 @@ endif menuconfig BSP_USING_USB bool "Using USB device" default n -select BSP_USING_USBH +select BSP_USING_STM32_USBH select RESOURCES_USB select RESOURCES_USB_HOST select USBH_MSTORAGE diff --git a/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/usb/Kconfig b/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/usb/Kconfig index 75c6685ba..4fcd37871 100644 --- a/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/usb/Kconfig +++ b/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/usb/Kconfig @@ -1,7 +1,7 @@ -config BSP_USING_USBH +config BSP_USING_STM32_USBH bool "Using usb host" default y - if BSP_USING_USBH + if BSP_USING_STM32_USBH config USB_BUS_NAME string "usb bus name" default "usb" diff --git a/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/usb/usbh.c b/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/usb/usbh.c index c80645539..c28503494 100644 --- a/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/usb/usbh.c +++ b/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/usb/usbh.c @@ -31,7 +31,7 @@ Modification: *************************************************/ #include -#include +#include #include #include #include diff --git a/Ubiquitous/XiUOS/board/ok1052-c/link.lds b/Ubiquitous/XiUOS/board/ok1052-c/link.lds index 0d3ab2a58..41649a29f 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/link.lds +++ b/Ubiquitous/XiUOS/board/ok1052-c/link.lds @@ -241,9 +241,9 @@ SECTIONS stack_end = .; __StackTop = .; heap_start = .; - } > m_data2 + } > m_data - PROVIDE(heap_end = ORIGIN(m_data2) + LENGTH(m_data2)); + PROVIDE(heap_end = ORIGIN(m_data) + LENGTH(m_data)); .ARM.attributes 0 : { *(.ARM.attributes) } } diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig index ef9867af5..91a0c2a5d 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig @@ -25,3 +25,11 @@ menuconfig BSP_USING_SDIO if BSP_USING_SDIO source "$BSP_DIR/third_party_driver/sdio/Kconfig" endif + +menuconfig BSP_USING_USB + bool "Using USB device" + default n + select RESOURCES_USB + if BSP_USING_USB + source "$BSP_DIR/third_party_driver/usb/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 4613b4f05..677573fef 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Makefile +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Makefile @@ -16,4 +16,8 @@ ifeq ($(CONFIG_BSP_USING_SDIO),y) SRC_DIR += sdio endif +ifeq ($(CONFIG_BSP_USING_USB),y) + SRC_DIR += usb +endif + include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_usb.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_usb.h new file mode 100644 index 000000000..2510702d7 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_usb.h @@ -0,0 +1,53 @@ +/* +* 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_usb.h +* @brief define ok1052-board usb function and struct +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2022-02-09 +*/ + +#ifndef CONNECT_USB_H +#define CONNECT_USB_H + +#include +#include +#include +#include +#include +#include +#include + +#if defined(FS_VFS) +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define CONTROLLER_ID kUSB_ControllerEhci1 +#define USB_HOST_INTERRUPT_PRIORITY (3U) + +#define USB_HOST_STACK_SIZE 4096 + +#define USB_SINGLE_BLOCK_SIZE 512 + +int Imrt1052HwUsbHostInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/Kconfig b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/Kconfig new file mode 100644 index 000000000..a1f439ca9 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/Kconfig @@ -0,0 +1,15 @@ +config BSP_USING_NXP_USBH + bool "Using usb host by NXP library" + default n + if BSP_USING_NXP_USBH + config USB_BUS_NAME + string "usb bus name" + default "usb" + config USB_DRIVER_NAME + string "usb bus driver name" + default "usb_drv" + config USB_DEVICE_NAME + string "usb bus device name" + default "usb_dev" + endif + diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/Makefile new file mode 100644 index 000000000..01f068d18 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/Makefile @@ -0,0 +1,5 @@ +SRC_DIR := nxp_usb_driver + +SRC_FILES := connect_usb.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/connect_usb.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/connect_usb.c new file mode 100644 index 000000000..dc530f79f --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/connect_usb.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** +* @file connect_usb.c +* @brief support usb host function using bus driver framework on OK1052 board +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2022-02-09 +*/ + +/************************************************* +File name: connect_usb.c +Description: support imxrt1052-board usb host configure and sdio bus register function +Others: take SDK_2.6.1_MIMXRT1052xxxxB/boards/evkbimxrt1050/usb_examples/usb_host_msd_command for references +History: +1. Date: 2022-02-09 +Author: AIIT XUOS Lab +Modification: +1. support imxrt1052-board usb host configure, write and read +2. support imxrt1052-board usb host bus device and driver register +*************************************************/ +#include +#include + +#define BSP_USING_NXP_USBH +#ifdef BSP_USING_NXP_USBH + +/*! @brief USB host msd command instance global variable */ +extern usb_host_msd_command_instance_t g_MsdCommandInstance; +usb_host_handle g_HostHandle; + +extern usb_status_t USB_HostMsdReadApi(usb_host_msd_command_instance_t *msdCommandInstance, uint8_t *buffer, uint32_t pos, uint32_t block_size, uint32_t block_num); +extern usb_status_t USB_HostMsdWriteApi(usb_host_msd_command_instance_t *msdCommandInstance, uint8_t *buffer, uint32_t pos, uint32_t block_size, uint32_t block_num); + +//USB HOST ISR +void UsbOtg2IrqHandler(int irqn, void *arg) +{ + x_base lock = 0; + lock = DISABLE_INTERRUPT(); + + USB_HostEhciIsrFunction(g_HostHandle); + + ENABLE_INTERRUPT(lock); +} +DECLARE_HW_IRQ(USB2_IRQn, UsbOtg2IrqHandler, NONE); + +void UsbHostClockInit(void) +{ + usb_phy_config_struct_t phyConfig = { + BOARD_USB_PHY_D_CAL, + BOARD_USB_PHY_TXCAL45DP, + BOARD_USB_PHY_TXCAL45DM, + }; + + if (CONTROLLER_ID == kUSB_ControllerEhci0) { + CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U); + CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U); + } else { + CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U); + CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U); + } + USB_EhciPhyInit(CONTROLLER_ID, BOARD_XTAL0_CLK_HZ, &phyConfig); +} + +void UsbHostIsrEnable(void) +{ + uint8_t irqNumber; + + uint8_t usbHOSTEhciIrq[] = USBHS_IRQS; + irqNumber = usbHOSTEhciIrq[CONTROLLER_ID - kUSB_ControllerEhci0]; +/* USB_HOST_CONFIG_EHCI */ + +/* Install isr, set priority, and enable IRQ. */ + NVIC_SetPriority((IRQn_Type)irqNumber, USB_HOST_INTERRUPT_PRIORITY); + EnableIRQ((IRQn_Type)irqNumber); +} + +void UsbHostTaskFn(void *param) +{ + USB_HostEhciTaskFunction(param); +} + +/*! + * @brief USB isr function. + */ +static usb_status_t UsbHostEvent(usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode) +{ + usb_status_t status = kStatus_USB_Success; + switch (eventCode) + { + case kUSB_HostEventAttach: + KPrintf("usb device attached\n"); + status = USB_HostMsdEvent(deviceHandle, configurationHandle, eventCode); + break; + + case kUSB_HostEventNotSupported: + KPrintf("device not supported.\r\n"); + break; + + case kUSB_HostEventEnumerationDone: + status = USB_HostMsdEvent(deviceHandle, configurationHandle, eventCode); + break; + + case kUSB_HostEventDetach: + KPrintf("usb device detached\n"); + status = USB_HostMsdEvent(deviceHandle, configurationHandle, eventCode); + break; + + default: + break; + } + return status; +} + +static void UsbHostApplicationInit(void) +{ + usb_status_t status = kStatus_USB_Success; + + UsbHostClockInit(); + + status = USB_HostInit(CONTROLLER_ID, &g_HostHandle, UsbHostEvent); + if (status != kStatus_USB_Success) { + KPrintf("host init error\r\n"); + return; + } + UsbHostIsrEnable(); + + KPrintf("host init done\r\n"); +} + +#if defined(FS_VFS) +void UsbMountFileSystem() +{ + if (MountFilesystem(USB_BUS_NAME, USB_DEVICE_NAME, USB_DRIVER_NAME, FSTYPE_FATFS, UDISK_MOUNTPOINT) == 0) + KPrintf("Mount FAT on Udisk successful.\n"); + else + KPrintf("Mount FAT on Udisk failed.\n"); +} + +void UsbUnmountFileSystem() +{ + UnmountFileSystem(UDISK_MOUNTPOINT); +} +#endif + +static uint32 UsbHostOpen(void *dev) +{ + return EOK; +} + +static uint32 UsbHostClose(void *dev) +{ + return EOK; +} + +static uint32 UsbHostRead(void *dev, struct BusBlockReadParam *read_param) +{ + usb_status_t status; + + status = USB_HostMsdReadApi(&g_MsdCommandInstance, (uint8 *)read_param->buffer, read_param->pos, USB_SINGLE_BLOCK_SIZE, read_param->size); + if (kStatus_USB_Success == status) { + return read_param->size; + } + + return 0; +} + +static uint32 UsbHostWrite(void *dev, struct BusBlockWriteParam *write_param) +{ + usb_status_t status; + + status = USB_HostMsdWriteApi(&g_MsdCommandInstance, (uint8 *)write_param->buffer, write_param->pos, USB_SINGLE_BLOCK_SIZE, write_param->size); + if (kStatus_USB_Success == status) { + return write_param->size; + } + + return 0; +} + +/*manage the usb device operations*/ +static const struct UsbDevDone dev_done = +{ + .open = UsbHostOpen, + .close = UsbHostClose, + .write = UsbHostWrite, + .read = UsbHostRead, +}; + +static void UsbHostTask(void* parameter) +{ + while (1) { + UsbHostTaskFn(g_HostHandle); + USB_HostMsdTask(&g_MsdCommandInstance); + } +} + +/*Init usb host bus、driver*/ +static int BoardUsbBusInit(struct UsbBus *usb_bus, struct UsbDriver *usb_driver) +{ + x_err_t ret = EOK; + + /*Init the usb bus */ + ret = UsbBusInit(usb_bus, USB_BUS_NAME); + if (EOK != ret) { + KPrintf("board_usb_init UsbBusInit error %d\n", ret); + return ERROR; + } + + /*Init the usb driver*/ + ret = UsbDriverInit(usb_driver, USB_DRIVER_NAME); + if (EOK != ret){ + KPrintf("board_usb_init UsbDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the usb driver to the usb bus*/ + ret = UsbDriverAttachToBus(USB_DRIVER_NAME, USB_BUS_NAME); + if (EOK != ret) { + KPrintf("board_usb_init USEDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the usb device to the usb bus*/ +static int BoardUsbDevBend(void) +{ + x_err_t ret = EOK; + static struct UsbHardwareDevice usb_device; + memset(&usb_device, 0, sizeof(struct UsbHardwareDevice)); + + usb_device.dev_done = &dev_done; + + ret = USBDeviceRegister(&usb_device, NONE, USB_DEVICE_NAME); + if (EOK != ret) { + KPrintf("USBDeviceRegister device %s error %d\n", USB_DEVICE_NAME, ret); + return ERROR; + } + + ret = USBDeviceAttachToBus(USB_DEVICE_NAME, USB_BUS_NAME); + if (EOK != ret) { + KPrintf("USBDeviceAttachToBus device %s error %d\n", USB_DEVICE_NAME, ret); + return ERROR; + } + + return ret; +} + +/*RT1052 BOARD USB INIT*/ +int Imrt1052HwUsbHostInit(void) +{ + x_err_t ret = EOK; + int32 usb_host_task = 0; + + static struct UsbBus usb_bus; + memset(&usb_bus, 0, sizeof(struct UsbBus)); + + static struct UsbDriver usb_driver; + memset(&usb_driver, 0, sizeof(struct UsbDriver)); + + UsbHostApplicationInit(); + + ret = BoardUsbBusInit(&usb_bus, &usb_driver); + if (EOK != ret) { + KPrintf("BoardUsbBusInit error ret %u\n", ret); + return ERROR; + } + + ret = BoardUsbDevBend(); + if (EOK != ret) { + KPrintf("BoardUsbDevBend error ret %u\n", ret); + return ERROR; + } + + usb_host_task = KTaskCreate("usbh", UsbHostTask, NONE, + USB_HOST_STACK_SIZE, 8); + if(usb_host_task < 0) { + KPrintf("usb_host_task create failed ...%s %d.\n", __FUNCTION__,__LINE__); + return ERROR; + } + + StartupKTask(usb_host_task); + + return ret; +} + +#endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/Makefile new file mode 100644 index 000000000..c1a2ffb13 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/Makefile @@ -0,0 +1,5 @@ +SRC_DIR += host phy osa + +SRC_FILES := host_msd_command.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/Makefile new file mode 100644 index 000000000..f871ce276 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/Makefile @@ -0,0 +1,5 @@ +SRC_DIR += class + +SRC_FILES += usb_host_devices.c usb_host_framework.c usb_host_ehci.c usb_host_hci.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/Makefile new file mode 100644 index 000000000..f52717f14 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/Makefile @@ -0,0 +1,3 @@ +SRC_FILES += usb_host_msd_ufi.c usb_host_msd.c usb_host_hub.c usb_host_hub_app.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub.c new file mode 100644 index 000000000..62b4e68ed --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub.c @@ -0,0 +1,608 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) +#include "usb_host.h" +#include "usb_host_hub.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief hub control transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostHubControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief hub interrupt in transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostHubInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief USB_HostHubSendPortReset's transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostHubResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief hub control transfer common code. + * + * @param classHandle the class handle. + * @param requestType request type. + * @param request setup packet request field. + * @param wvalue setup packet wValue field. + * @param windex setup packet wIndex field. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostHubClassRequestCommon(usb_host_class_handle classHandle, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostHubControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + hubInstance->controlTransfer = NULL; + if (hubInstance->controlCallbackFn) + { + /* callback to application, callback function is initialized in the USB_HostPrinterControl, + USB_HostPrinterSetInterface + or USB_HostHubClassRequestCommon, but is the same function */ + hubInstance->controlCallbackFn(hubInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); /* callback to application */ + } + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); +} + +static void USB_HostHubInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + if (hubInstance->inCallbackFn) + { + /* callback to application, callback function is initialized in the USB_HostHubInterruptRecv */ + hubInstance->inCallbackFn(hubInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); /* callback to application */ + } + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); +} + +static void USB_HostHubResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + /* note: there is not callback to application, the re-enumeration will start automatically after reset. */ + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostHubClassRequestCommon(usb_host_class_handle classHandle, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (hubInstance->controlTransfer != NULL) + { + return kStatus_USB_Busy; + } + + /* get transfer */ + if (USB_HostMallocTransfer(hubInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + + /* save hub application callback */ + hubInstance->controlCallbackFn = callbackFn; + hubInstance->controlCallbackParam = callbackParam; + + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostHubControlCallback; + transfer->callbackParam = hubInstance; + transfer->setupPacket->bmRequestType = requestType; + transfer->setupPacket->bRequest = request; + transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(wvalue); + transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(windex); + transfer->setupPacket->wLength = USB_SHORT_TO_LITTLE_ENDIAN(bufferLength); + + /* send transfer */ + if (USB_HostSendSetup(hubInstance->hostHandle, hubInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("Error in hid get report descriptor\r\n"); +#endif + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + hubInstance->controlTransfer = transfer; /* record the on-going setup transfer */ + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) +{ + /* malloc the hub instance */ + usb_host_hub_instance_t *hubInstance = + (usb_host_hub_instance_t *)USB_OsaMemoryAllocate(sizeof(usb_host_hub_instance_t)); + + uint32_t infoValue; + + if (hubInstance == NULL) + { + return kStatus_USB_AllocFail; + } + +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + hubInstance->hubDescriptor = (uint8_t *)SDK_Malloc(7 + (USB_HOST_HUB_MAX_PORT >> 3) + 1, USB_CACHE_LINESIZE); + hubInstance->portStatusBuffer = (uint8_t *)SDK_Malloc(4, USB_CACHE_LINESIZE); + hubInstance->hubStatusBuffer = (uint8_t *)SDK_Malloc(4, USB_CACHE_LINESIZE); + hubInstance->hubBitmapBuffer = (uint8_t *)SDK_Malloc((USB_HOST_HUB_MAX_PORT >> 3) + 1, USB_CACHE_LINESIZE); +#endif + + /* initialize hub instance structure */ + hubInstance->deviceHandle = deviceHandle; + hubInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + hubInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + hubInstance->controlPipe = (usb_host_pipe_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + hubInstance->hubLevel = infoValue; + + *classHandle = hubInstance; /* return the hub class handle */ + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status; + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_interface_t *interface = (usb_host_interface_t *)interfaceHandle; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_pipe_init_t pipeInit; + uint8_t epIndex; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + hubInstance->interfaceHandle = interfaceHandle; /* save the interface handle */ + + /* notify the host driver that the interface is used by class */ + status = USB_HostOpenDeviceInterface(hubInstance->deviceHandle, interfaceHandle); + if (status != kStatus_USB_Success) + { + return status; + } + + /* close opened hub interrupt pipe */ + if (hubInstance->interruptPipe != NULL) + { + status = USB_HostCancelTransfer(hubInstance->hostHandle, hubInstance->interruptPipe, NULL); + status = USB_HostClosePipe(hubInstance->hostHandle, hubInstance->interruptPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + hubInstance->interruptPipe = NULL; + } + + /* open hub interrupt pipe */ + for (epIndex = 0; epIndex < interface->epCount; ++epIndex) + { + epDesc = interface->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT)) + { + /* get pipe information from endpoint descriptor */ + pipeInit.devInstance = hubInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_INTERRUPT; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + /* open hub interrupt in pipe */ + status = USB_HostOpenPipe(hubInstance->hostHandle, &hubInstance->interruptPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_hid_set_interface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + break; + } + } + + /* hub don't support alternatesetting that is not 0 */ + if (alternateSetting == 0) + { + if (callbackFn != NULL) + { + callbackFn(callbackParam, NULL, 0, kStatus_USB_Success); + } + } + else + { +#ifdef HOST_ECHO + usb_echo("host don't support alternate setting\r\n"); +#endif + return kStatus_USB_Error; + } + + return status; +} + +usb_status_t USB_HostHubDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + uint8_t status; + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (classHandle != NULL) + { + /* close opened hub interrupt pipe */ + if (hubInstance->interruptPipe != NULL) + { + status = USB_HostCancelTransfer(hubInstance->hostHandle, hubInstance->interruptPipe, NULL); + status = USB_HostClosePipe(hubInstance->hostHandle, hubInstance->interruptPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("hub close interrupt pipe error\r\n"); +#endif + } + hubInstance->interruptPipe = NULL; + } + + /* cancel control transfer if exist */ + if ((hubInstance->controlPipe != NULL) && (hubInstance->controlTransfer != NULL)) + { + status = + USB_HostCancelTransfer(hubInstance->hostHandle, hubInstance->controlPipe, hubInstance->controlTransfer); + } + + /* notify host driver that the interface will not be used */ + USB_HostCloseDeviceInterface(deviceHandle, hubInstance->interfaceHandle); +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(hubInstance->hubDescriptor); + SDK_Free(hubInstance->portStatusBuffer); + SDK_Free(hubInstance->hubStatusBuffer); + SDK_Free(hubInstance->hubBitmapBuffer); +#endif + USB_OsaMemoryFree(hubInstance); + } + else + { + /* notify host driver that the interface will not be used */ + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubInterruptRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* get transfer */ + if (USB_HostMallocTransfer(hubInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + + /* save hub application callback */ + hubInstance->inCallbackFn = callbackFn; + hubInstance->inCallbackParam = callbackParam; + + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostHubInPipeCallback; + transfer->callbackParam = hubInstance; + + /* call host driver API to receive data */ + if (USB_HostRecv(hubInstance->hostHandle, hubInstance->interruptPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("failed to USB_HostRecv\r\n"); +#endif + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubSendPortReset(usb_host_class_handle classHandle, uint8_t portNumber) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* get transfer */ + if (USB_HostMallocTransfer(hubInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + + /* initialize transfer */ + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + transfer->callbackFn = USB_HostHubResetCallback; + transfer->callbackParam = hubInstance; + transfer->setupPacket->bmRequestType = + USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER; + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_SET_FEATURE; + transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(PORT_RESET); + transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(portNumber); + transfer->setupPacket->wLength = 0; + + /* send the transfer */ + if (USB_HostSendSetup(hubInstance->hostHandle, hubInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("Error in hid get report descriptor\r\n"); +#endif + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + return kStatus_USB_Success; +} + +/*! + * @brief hub get descriptor. + * + * This function implements get hub descriptor specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubGetDescriptor(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_DEVICE, + USB_REQUEST_STANDARD_GET_DESCRIPTOR, 0x00, 0, buffer, bufferLength, callbackFn, callbackParam); +} + +/*! + * @brief hub clear feature. + * + * This function implements clear hub feature specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubClearFeature(usb_host_class_handle classHandle, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon(classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS, + USB_REQUEST_STANDARD_CLEAR_FEATURE, feature, 0, NULL, 0, callbackFn, + callbackParam); +} + +/*! + * @brief hub get status. + * + * This function implements get hub status specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubGetStatus(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon(classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS, + USB_REQUEST_STANDARD_GET_STATUS, 0, 0, buffer, bufferLength, callbackFn, + callbackParam); +} + +/*! + * @brief hub set feature. + * + * This function implements set hub feature specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubSetPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_SET_FEATURE, feature, portNumber, NULL, 0, callbackFn, callbackParam); +} + +/*! + * @brief hub clear port feature. + * + * This function implements clear hub port feature specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubClearPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_CLEAR_FEATURE, feature, portNumber, NULL, 0, callbackFn, callbackParam); +} + +/*! + * @brief hub port get status. + * + * This function implements get hub port status specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +usb_status_t USB_HostHubGetPortStatus(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_GET_STATUS, 0, portNumber, buffer, bufferLength, callbackFn, callbackParam); +} + +#endif /* USB_HOST_CONFIG_HUB */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub.h new file mode 100644 index 000000000..d47af8637 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub.h @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _USB_HOST_HUB_H_ +#define _USB_HOST_HUB_H_ + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief USB host HUB maximum port count */ +#define USB_HOST_HUB_MAX_PORT (7U) + +/*! @brief HUB class code */ +#define USB_HOST_HUB_CLASS_CODE (9U) +/*! @brief HUB sub-class code */ +#define USB_HOST_HUB_SUBCLASS_CODE_NONE (0U) + +/* HUB and PORT status according to Table 11-17 in chapter 11.*/ +/*! @brief Local Power Status Change: This field indicates that a change has occurred in the HUB's Local Power Source */ +#define C_HUB_LOCAL_POWER (0U) +/*! @brief Over-Current Change: This field indicates if a change has occurred in the Over-Current field*/ +#define C_HUB_OVER_CURRENT (1U) +/*! @brief Current Connect Status: This field reflects whether or not a device is currently connected to this port*/ +#define PORT_CONNECTION (0U) +/*! @brief Port Enabled/Disabled: Ports can be enabled by the USB System Software only. Ports +can be disabled by either a fault condition (disconnect event or other fault condition) or by the USB System +Software*/ +#define PORT_ENABLE (1U) +/*! @brief Suspend: This field indicates whether or not the device on this port is suspended */ +#define PORT_SUSPEND (2U) +/*! @brief this field indicate that the current drain on the port exceeds the specified maximum. */ +#define PORT_OVER_CURRENT (3U) +/*! @brief This field is set when the host wishes to reset the attached device */ +#define PORT_RESET (4U) +/*! @brief This field reflects a port's logical, power control state */ +#define PORT_POWER (8U) +/*! @brief Low- Speed Device Attached: This is relevant only if a device is attached */ +#define PORT_LOW_SPEED (9U) +/*! @brief High-speed Device Attached: This is relevant only if a device is attached */ +#define PORT_HIGH_SPEED (10U) +/*! @brief Connect Status Change: Indicates a change has occurred in the port's Current Connect Status */ +#define C_PORT_CONNECTION (16U) +/*! @brief Port Enable/Disable Change: This field is set to one when a port is disabled because of a Port_Error + * condition */ +#define C_PORT_ENABLE (17U) +/*! @brief Suspend Change: This field indicates a change in the host-visible suspend state of the attached device */ +#define C_PORT_SUSPEND (18U) +/*! @brief Over-Current Indicator Change: This field applies only to HUBs that report over-current conditions on a + * per-port basis */ +#define C_PORT_OVER_CURRENT (19U) +/*! @brief Reset Change: This field is set when reset processing on this port is complete */ +#define C_PORT_RESET (20U) + +/*! @brief Get HUB think time value */ +#define USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_MASK (0x60U) +/*! @brief Get HUB think time value */ +#define USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_SHIFT (5U) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! @brief HUB descriptor structure */ +typedef struct _usb_host_hub_descriptor +{ + uint8_t blength; /*!< Number of bytes in this descriptor*/ + uint8_t bdescriptortype; /*!< Descriptor Type*/ + uint8_t bnrports; /*!< Number of downstream facing ports that this HUB supports*/ + uint8_t whubcharacteristics[2]; /*!< HUB characteristics please reference to Table 11-13 in usb2.0 specification*/ + uint8_t bpwron2pwrgood; /*!< Time (in 2 ms intervals) from the time the power-on sequence begins on a port until + power is good on that port.*/ + uint8_t bhubcontrcurrent; /*!< Maximum current requirements of the HUB Controller electronics in mA*/ + uint8_t deviceremovable; /*!< Indicates if a port has a removable device attached*/ +} usb_host_hub_descriptor_t; + +/*! @brief HUB port instance structure */ +typedef struct _usb_host_hub_port_instance +{ + usb_device_handle deviceHandle; /*!< Device handle*/ + uint8_t portStatus; /*!< Port running status*/ + uint8_t resetCount; /*!< Port reset time*/ + uint8_t speed; /*!< Port's device speed*/ +} usb_host_hub_port_instance_t; + +/*! @brief HUB instance structure */ +typedef struct _usb_host_hub_instance +{ + struct _usb_host_hub_instance *next; /*!< Next HUB instance*/ + usb_host_handle hostHandle; /*!< Host handle*/ + usb_device_handle deviceHandle; /*!< Device handle*/ + usb_host_interface_handle interfaceHandle; /*!< Interface handle*/ + usb_host_pipe_handle controlPipe; /*!< Control pipe handle*/ + usb_host_pipe_handle interruptPipe; /*!< HUB interrupt in pipe handle*/ + usb_host_hub_port_instance_t *portList; /*!< HUB's port instance list*/ + usb_host_transfer_t *controlTransfer; /*!< Control transfer in progress*/ + transfer_callback_t inCallbackFn; /*!< Interrupt in callback*/ + void *inCallbackParam; /*!< Interrupt in callback parameter*/ + transfer_callback_t controlCallbackFn; /*!< Control callback*/ + void *controlCallbackParam; /*!< Control callback parameter*/ + /* HUB property */ + uint16_t totalThinktime; /*!< HUB total think time*/ + uint8_t hubLevel; /*!< HUB level, the root HUB's level is 1*/ + + /* HUB application parameter */ +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + uint8_t *hubDescriptor; /*!< HUB descriptor buffer*/ + uint8_t *hubBitmapBuffer; /*!< HUB receiving bitmap data buffer*/ + uint8_t *hubStatusBuffer; /*!< HUB status buffer*/ + uint8_t *portStatusBuffer; /*!< Port status buffer*/ +#else + uint8_t hubDescriptor[7 + (USB_HOST_HUB_MAX_PORT >> 3) + 1]; /*!< HUB descriptor buffer*/ + uint8_t hubBitmapBuffer[(USB_HOST_HUB_MAX_PORT >> 3) + 1]; /*!< HUB receiving bitmap data buffer*/ + uint8_t hubStatusBuffer[4]; /*!< HUB status buffer*/ + uint8_t portStatusBuffer[4]; /*!< Port status buffer*/ +#endif + uint8_t hubStatus; /*!< HUB instance running status*/ + uint8_t portCount; /*!< HUB port count*/ + uint8_t portIndex; /*!< Record the index when processing ports in turn*/ + uint8_t portProcess; /*!< The port that is processing*/ + uint8_t primeStatus; /*!< Data prime transfer status*/ + uint8_t invalid; /*!< 0/1, when invalid, cannot send transfer to the class*/ +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + uint8_t supportRemoteWakeup; /*!< The HUB supports remote wakeup or not*/ + uint8_t controlRetry; /*!< Retry count for set remote wakeup feature*/ +#endif +} usb_host_hub_instance_t; + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Initializes the HUB instance. + * + * This function allocates the resource for HUB instance. + * + * @param deviceHandle The device handle. + * @param classHandle Return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +extern usb_status_t USB_HostHubInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets interface. + * + * This function binds the interfaces with the HUB instance. + * + * @param classHandle The class handle. + * @param interfaceHandle The interface handle. + * @param alternateSetting The alternate setting value. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Open pipe fail. See the USB_HostOpenPipe. + * Or send transfer fail. See the USB_HostSendSetup, + */ +extern usb_status_t USB_HostHubSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Deinitializes the HUB instance. + * + * This function releases the resource for HUB instance. + * + * @param deviceHandle The device handle. + * @param classHandle The class handle. + * + * @retval kStatus_USB_Success The device is deinitialized successfully. + */ +extern usb_status_t USB_HostHubDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Receives data. + * + * This function implements the HUB receiving data. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Receive request successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostRecv. + */ +extern usb_status_t USB_HostHubInterruptRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Port reset setup. + * + * This function sends the HUB port reset transfer. + * + * @param classHandle The class handle. + * @param portNumber Port number. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubSendPortReset(usb_host_class_handle classHandle, uint8_t portNumber); + +/*! + * @brief HUB get descriptor. + * + * This function implements get HUB descriptor-specific request. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubGetDescriptor(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB clear feature. + * + * This function implements clear HUB feature specific request. + * + * @param classHandle the class handle. + * @param buffer the buffer pointer. + * @param bufferLength the buffer length. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error pipe is not initialized. + * Or, send transfer fail, please reference to USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubClearFeature(usb_host_class_handle classHandle, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB get status. + * + * This function implements the get HUB status-specific request. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubGetStatus(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB set feature. + * + * This function implements the set HUB feature-specific request. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubSetPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB clear port feature. + * + * This function implements the clear HUB port feature-specific request. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubClearPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB port get status. + * + * This function implements the get HUB port status-specific request. + * + * @param classHandle The class handle. + * @param buffer The buffer pointer. + * @param bufferLength The buffer length. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Pipe is not initialized. + * Or, send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubGetPortStatus(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +#ifdef __cplusplus +} +#endif + +#endif /* USB_HOST_CONFIG_HUB */ + +#endif /* _USB_HSOT_HUB_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub_app.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub_app.c new file mode 100644 index 000000000..89a24c122 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub_app.c @@ -0,0 +1,1631 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +#include "usb_host.h" +#include "usb_host_hub.h" +#include "usb_host_hci.h" +#include "usb_host_hub_app.h" +#include "usb_host_devices.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief HUB lock */ +#define USB_HostHubLock() USB_OsaMutexLock(hubGlobal->hubMutex) +/*! @brief HUB unlock */ +#define USB_HostHubUnlock() USB_OsaMutexUnlock(hubGlobal->hubMutex) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief prime interrupt in data. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubGetInterruptStatus(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub process state machine. hub is enable after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcess(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port attach process state machine. one device is attached to the port after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPortAttach(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port detach process state machine. one device is detached from the port after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPortDetach(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port process. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPort(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub interrupt in data process. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessData(usb_host_hub_global_t *hubGlobal, usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub control pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostHubControlCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status); + +/*! + * @brief hub interrupt pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostHubInterruptInCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status); + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + +static usb_host_hub_instance_t *USB_HostHubGetHubDeviceHandle(usb_host_handle hostHandle, uint8_t parentHubNo); + +static usb_status_t USB_HostSendHubRequest(usb_device_handle deviceHandle, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + host_inner_transfer_callback_t callbackFn, + void *callbackParam); + +#endif +/******************************************************************************* + * Variables + ******************************************************************************/ + +static usb_device_handle s_HubDeviceHandle; +static usb_host_interface_handle s_HubInterfaceHandle; +static usb_host_hub_global_t s_HubGlobalArray[USB_HOST_CONFIG_MAX_HOST]; + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) +static usb_host_configuration_t *s_HubConfiguration; +#endif + +/******************************************************************************* + * Code + ******************************************************************************/ + +static usb_host_hub_global_t *USB_HostHubGetHubList(usb_host_handle hostHandle) +{ +#if (USB_HOST_CONFIG_MAX_HOST == 1U) + return &s_HubGlobalArray[0]; +#else + uint8_t index; + for (index = 0; index < USB_HOST_CONFIG_MAX_HOST; ++index) + { + if (s_HubGlobalArray[index].hostHandle == hostHandle) + { + return &s_HubGlobalArray[index]; + } + } + /* There is no used usb_host_hub_global_t instance */ + for (index = 0; index < USB_HOST_CONFIG_MAX_HOST; ++index) + { + if (s_HubGlobalArray[index].hostHandle == NULL) + { + s_HubGlobalArray[index].hostHandle = hostHandle; + return &s_HubGlobalArray[index]; + } + } + /* Look for the usb_host_hub_global_t instance that is not used any more */ + for (index = 0; index < USB_HOST_CONFIG_MAX_HOST; ++index) + { + if (s_HubGlobalArray[index].hubList == NULL) + { + s_HubGlobalArray[index].hostHandle = hostHandle; + return &s_HubGlobalArray[index]; + } + } + return NULL; +#endif +} + +static void USB_HostHubGetInterruptStatus(usb_host_hub_instance_t *hubInstance) +{ + if (hubInstance == NULL) + { + return; + } + + /* there is no prime for control or interrupt */ + if (hubInstance->primeStatus != kPrimeNone) + { + return; + } + + /* receive interrupt data */ + if (USB_HostHubInterruptRecv(hubInstance, hubInstance->hubBitmapBuffer, (hubInstance->portCount >> 3) + 1, + USB_HostHubInterruptInCallback, hubInstance) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error in hub interrupt recv\r\n"); +#endif + } + else + { + hubInstance->primeStatus = kPrimeInterrupt; + } +} + +static void USB_HostHubProcess(usb_host_hub_instance_t *hubInstance) +{ + uint8_t needPrimeInterrupt = 0; /* need to prime interrupt in transfer (0 - don't need; 1 - need) */ + uint8_t processSuccess = 0; /* the code execute successfully (0 - fail; 1 - success) */ + uint32_t tmp = 0; + usb_host_hub_descriptor_t *hubDescriptor; + + switch (hubInstance->hubStatus) + { + case kHubRunIdle: + case kHubRunInvalid: + break; + + case kHubRunWaitSetInterface: + hubInstance->hubStatus = kHubRunGetDescriptor7; /* update as next state */ + /* get hub descriptor */ + if (USB_HostHubGetDescriptor(hubInstance, hubInstance->hubDescriptor, 7, USB_HostHubControlCallback, + hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* control transfer is on-going */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("hub get descriptor 7\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("hub get descriptor 7 error\r\n"); +#endif + break; + } + break; + + case kHubRunGetDescriptor7: + hubDescriptor = (usb_host_hub_descriptor_t *)&hubInstance->hubDescriptor[0]; + + /* get the hub think time */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetHubThinkTime, &tmp); + hubInstance->totalThinktime = tmp; + tmp = ((((uint32_t)hubDescriptor->whubcharacteristics[0] & + USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_MASK) >> + USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_SHIFT)); + /* + 00 - 8 FS bit times; + 01 - 16 FS bit times; + 10 - 24 FS bit times; + 11 - 32 FS bit times; + */ + tmp = (tmp + 1) << 3; + hubInstance->totalThinktime += tmp; + + /* get hub port number */ + hubInstance->portCount = hubDescriptor->bnrports; + if (hubInstance->portCount > USB_HOST_HUB_MAX_PORT) + { +#ifdef HOST_ECHO + usb_echo("port number is bigger than USB_HOST_HUB_MAX_PORT\r\n"); +#endif + return; + } + + hubInstance->hubStatus = kHubRunGetDescriptor; /* update as next state */ + /* get hub descriptor */ + if (USB_HostHubGetDescriptor(hubInstance, hubInstance->hubDescriptor, 7 + (hubInstance->portCount >> 3) + 1, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* control transfer is on-going */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("hub get descriptor\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("hub get descriptor error\r\n"); +#endif + break; + } + break; + + case kHubRunGetDescriptor: + /* malloc port instance for the hub's ports */ + hubInstance->portList = (usb_host_hub_port_instance_t *)USB_OsaMemoryAllocate( + hubInstance->portCount * sizeof(usb_host_hub_port_instance_t)); + if (hubInstance->portList == NULL) + { +#ifdef HOST_ECHO + usb_echo("port list allocate fail\r\n"); +#endif + hubInstance->hubStatus = kHubRunInvalid; + break; + } + /* TODO: port instance status -> can be removed. app_status */ + + hubInstance->hubStatus = kHubRunSetPortPower; /* update as next state */ + hubInstance->portIndex = 0; + + /* there is no significance, just for fixing misra error */ + if (hubInstance->hubStatus != kHubRunSetPortPower) + { + break; + } + + case kHubRunSetPortPower: + /* set PORT_POWER for all ports */ + if (hubInstance->portIndex < hubInstance->portCount) + { + hubInstance->portIndex++; + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portIndex, PORT_POWER, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* update as next state */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("set port feature PORT_POWER\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("set port feature PORT_POWER fail\r\n"); +#endif + needPrimeInterrupt = 1; + break; + } + break; + } + hubInstance->portProcess = 0; + /* reset port information as default */ + for (tmp = 0; tmp < hubInstance->portCount; ++tmp) + { + hubInstance->portList[tmp].deviceHandle = NULL; + hubInstance->portList[tmp].resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + hubInstance->portList[tmp].portStatus = kPortRunWaitPortChange; + } + hubInstance->hubStatus = kHubRunIdle; + needPrimeInterrupt = 1; + break; + + case kHubRunGetStatusDone: /* process hub status change */ + tmp = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS((&hubInstance->hubStatusBuffer[2])); + hubInstance->hubStatus = kHubRunIdle; + if ((1 << C_HUB_LOCAL_POWER) & tmp) /* C_HUB_LOCAL_POWER */ + { + if (USB_HostHubClearFeature(hubInstance, C_HUB_LOCAL_POWER, USB_HostHubControlCallback, hubInstance) == + kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + hubInstance->hubStatus = kHubRunClearDone; + processSuccess = 1; + } + else + { + needPrimeInterrupt = 1; + } + } + else if ((1 << C_HUB_OVER_CURRENT) & tmp) /* C_HUB_OVER_CURRENT */ + { + if (USB_HostHubClearFeature(hubInstance, C_HUB_OVER_CURRENT, USB_HostHubControlCallback, hubInstance) == + kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + processSuccess = 1; + hubInstance->hubStatus = kHubRunClearDone; + } + else + { + needPrimeInterrupt = 1; + } + } + else + { + needPrimeInterrupt = 1; + } + break; + + case kHubRunClearDone: + hubInstance->hubStatus = kHubRunIdle; + needPrimeInterrupt = 1; + break; + + default: + break; + } + + if (needPrimeInterrupt == 1) /* prime interrupt in transfer */ + { + hubInstance->hubStatus = kHubRunIdle; + USB_HostHubGetInterruptStatus(hubInstance); + } + else + { + if (processSuccess == 0) + { + hubInstance->hubStatus = kHubRunInvalid; + } + } +} + +static void USB_HostHubProcessPort(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; + + /* for device attach */ + if (portInstance->deviceHandle == NULL) + { + USB_HostHubProcessPortAttach(hubInstance); + } + else /* for device detach */ + { + USB_HostHubProcessPortDetach(hubInstance); + } +} + +static void USB_HostHubProcessPortAttach(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; + uint8_t processSuccess = 0; + uint32_t specStatus; + uint8_t feature; + uint32_t infoValue; + usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hubInstance->hostHandle); + if (hubGlobal == NULL) + { + return; + } + + switch (portInstance->portStatus) + { + case kPortRunIdle: + case kPortRunInvalid: + break; + case kPortRunWaitPortChange: /* (1) port is changed, and get port status */ + portInstance->portStatus = kPortRunCheckCPortConnection; /* update as next state */ + /* send class-specific request to get port status */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckCPortConnection: /* (2) check port status, and clear the status bits */ + feature = 0; + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS((hubInstance->portStatusBuffer)); + if ((1 << C_PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunGetPortConnection; /* update as next state */ + /* clear C_PORT_CONNECTION */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_CONNECTION, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } + else if ((1 << PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunWaitPortResetDone; /* update as next state */ + /* set PORT_RESET */ + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portProcess, PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + if (portInstance->resetCount > 0) + { + portInstance->resetCount--; + } + } + break; + } + else if ((1 << C_PORT_RESET) & specStatus) + { + feature = C_PORT_RESET; /* clear C_PORT_RESET */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_RESET when detached\r\n"); +#endif + } + else if ((1 << C_PORT_ENABLE) & specStatus) + { + feature = C_PORT_ENABLE; /* clear C_PORT_ENABLE */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_ENABLE when detached\r\n"); +#endif + } + else if ((1 << C_PORT_OVER_CURRENT) & specStatus) + { + feature = C_PORT_OVER_CURRENT; /* clear C_PORT_OVER_CURRENT */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_OVER_CURRENT when detached\r\n"); +#endif + } + else + { + } + + if (feature != 0) + { + portInstance->portStatus = kPortRunWaitPortChange; /* update as next state */ + /* clear feature */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, feature, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + } + break; + + case kPortRunGetPortConnection: /* (3) get port status */ + portInstance->portStatus = kPortRunCheckPortConnection; /* update as next state */ + /* get port status bits */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; /* control transfer is on-going */ + processSuccess = 1; + } + break; + + case kPortRunCheckPortConnection: /* (4) check PORT_CONNECTION bit */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunWaitPortResetDone; /* update as next state */ + /* set PORT_RESET */ + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portProcess, PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + if (portInstance->resetCount > 0) + { + portInstance->resetCount--; + } + } + } + break; + + case kPortRunWaitPortResetDone: /* (5) wait port change */ + portInstance->portStatus = kPortRunWaitCPortReset; /* update as next state */ + processSuccess = 1; + /* must wait the enumeration done, then operate the next port */ + USB_HostHubGetInterruptStatus(hubInstance); + break; + + case kPortRunWaitCPortReset: /* (6) get port status for checking C_PORT_RESET */ + portInstance->portStatus = KPortRunCheckCPortReset; /* update as next state */ + /* get port status bits */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case KPortRunCheckCPortReset: /* (7) check C_PORT_RESET and clear C_PORT_RESET */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << C_PORT_RESET) & specStatus) + { + if (portInstance->resetCount == 0) + { + portInstance->portStatus = kPortRunPortAttached; /* update as next state */ + /* get port's device speed */ + if (specStatus & (1 << PORT_HIGH_SPEED)) + { + portInstance->speed = USB_SPEED_HIGH; + } + else if (specStatus & (1 << PORT_LOW_SPEED)) + { + portInstance->speed = USB_SPEED_LOW; + } + else + { + portInstance->speed = USB_SPEED_FULL; + } + } + else + { + portInstance->portStatus = kPortRunResetAgain; /* update as next state */ + } + + /* clear C_PORT_RESET */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + } + break; + + case kPortRunResetAgain: /* (8) reset again */ + portInstance->portStatus = kPortRunCheckPortConnection; /* check connection then reset again */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunPortAttached: /* (9) the port have one device attached */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + USB_HostAttachDevice(hubInstance->hostHandle, portInstance->speed, infoValue, hubInstance->portProcess, + hubInstance->hubLevel + 1, &portInstance->deviceHandle); + processSuccess = 1; + hubInstance->portProcess = 0; + hubGlobal->hubProcess = NULL; + portInstance->resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + USB_HostHubGetInterruptStatus(hubInstance); + break; + default: + break; + } + + if (processSuccess == 0) + { + portInstance->portStatus = kPortRunWaitPortChange; + hubInstance->portProcess = 0; + hubGlobal->hubProcess = NULL; + portInstance->resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +static void USB_HostHubProcessPortDetach(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + usb_host_instance_t *hostPointer = (usb_host_instance_t *)hubInstance->hostHandle; +#endif + uint8_t processSuccess = 0; + uint32_t specStatus; + usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hubInstance->hostHandle); + if (hubGlobal == NULL) + { + return; + } + + switch (portInstance->portStatus) + { + case kPortRunIdle: + case kPortRunInvalid: + break; +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + case kPortRunPortSuspended: +#endif + case kPortRunPortAttached: /* (1) port is changed, then get port status */ + portInstance->portStatus = kPortRunCheckPortDetach; + /* get port status */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckPortDetach: /* (2) check port status bits */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + portInstance->portStatus = kPortRunGetConnectionBit; + if ((1 << C_PORT_CONNECTION) & specStatus) /* C_PORT_CONNECTION */ + { + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_CONNECTION, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } + else if ((1 << C_PORT_ENABLE) & specStatus) /* C_PORT_ENABLE */ + { + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_ENABLE, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + else if ((1 << C_PORT_SUSPEND) & specStatus) + { + /* clear C_PORT_SUSPEND */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_SUSPEND, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + portInstance->portStatus = kPortRunClearCPortSuspend; /* update as next state */ + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + break; + } + } +#endif + else + { + /* don't break to check CONNECTION bit */ + } + case kPortRunGetConnectionBit: /* (3) get port status */ + portInstance->portStatus = kPortRunCheckConnectionBit; + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckConnectionBit: /* (4) check port connection bit */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << PORT_CONNECTION) & specStatus) /* PORT_CONNECTION */ + { + portInstance->portStatus = kPortRunPortAttached; +#ifdef HOST_ECHO + usb_echo("PORT_CONNECTION in attach for detach\r\n"); +#endif + } + else + { + processSuccess = 1; + /* port's device is detached */ + portInstance->portStatus = kPortRunWaitPortChange; + USB_HostDetachDeviceInternal(hubInstance->hostHandle, portInstance->deviceHandle); + portInstance->deviceHandle = NULL; + hubGlobal->hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } + break; +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + case kPortRunClearCPortSuspend: + portInstance->portStatus = kPortRunCheckPortSuspend; /* update as next state */ + /* get port status bits */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + case kPortRunCheckPortSuspend: + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << PORT_SUSPEND) & specStatus) + { + portInstance->portStatus = kPortRunPortSuspended; /* update as next state */ + /* call host callback function, function is initialized in USB_HostInit */ + hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL, + kUSB_HostEventSuspended); /* call host callback function */ + } + else + { + portInstance->portStatus = kPortRunPortAttached; /* update as next state */ + /* call host callback function, function is initialized in USB_HostInit */ + hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL, + kUSB_HostEventResumed); /* call host callback function */ + hostPointer->suspendedDevice = NULL; + } + break; +#endif + default: + break; + } + + if (processSuccess == 0) + { + portInstance->portStatus = kPortRunPortAttached; + hubGlobal->hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +static void USB_HostHubProcessData(usb_host_hub_global_t *hubGlobal, usb_host_hub_instance_t *hubInstance) +{ + uint8_t needPrimeInterrupt = 1; + uint8_t portIndex; + + /* process the port which status change */ + for (portIndex = 0; portIndex <= hubInstance->portCount; ++portIndex) + { + if ((0x01u << (portIndex & 0x07u)) & (hubInstance->hubBitmapBuffer[portIndex >> 3])) + { + if (portIndex == 0) /* hub status change */ + { + if ((hubGlobal->hubProcess == NULL) || + ((hubGlobal->hubProcess == hubInstance) && (hubInstance->portProcess == 0))) + { + hubInstance->hubStatus = kHubRunGetStatusDone; + if (USB_HostHubGetStatus(hubInstance, hubInstance->hubStatusBuffer, 4, USB_HostHubControlCallback, + hubInstance) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error in usb_class_hub_get_status\r\n"); +#endif + hubInstance->hubStatus = kHubRunIdle; + } + else + { + hubInstance->primeStatus = kPrimeHubControl; + needPrimeInterrupt = 0; + return; /* return replace break because the misra */ + } + } + } + else /* port's status change */ + { + /* process the on-going port or process one new port */ + if ((hubGlobal->hubProcess == NULL) || + ((hubGlobal->hubProcess == hubInstance) && (hubInstance->portProcess == 0)) || + ((hubGlobal->hubProcess == hubInstance) && (hubInstance->portProcess == portIndex))) + { + if (hubInstance->controlTransfer == NULL) + { + hubGlobal->hubProcess = hubInstance; + hubInstance->portProcess = portIndex; + needPrimeInterrupt = 0; + USB_HostHubProcessPort(hubInstance); + } + break; /* process the port change in turn */ + } + } + } + } + + if (needPrimeInterrupt == 1) + { + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +void USB_HostHubControlCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hubInstance->hostHandle); + if (hubGlobal == NULL) + { + return; + } + + if (hubInstance->invalid == 1) + { + return; + } + if (status != kStatus_USB_Success) + { + /* if transfer fail, prime a new interrupt in transfer */ + hubInstance->primeStatus = kPrimeNone; + hubGlobal->hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + return; + } + + if (hubInstance->primeStatus == kPrimeHubControl) /* hub related control transfer */ + { + hubInstance->primeStatus = kPrimeNone; + USB_HostHubProcess(hubInstance); + } + else if (hubInstance->primeStatus == kPrimePortControl) /* hub's port related control transfer */ + { + hubInstance->primeStatus = kPrimeNone; + USB_HostHubProcessPort(hubInstance); + } + else + { + } +} + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) +/*! + * @brief get device's hub device instance. + * + * @param parent_hub_no device's parent hub instance. + * + * @return think time value. + */ +static usb_host_hub_instance_t *USB_HostHubGetHubDeviceHandle(usb_host_handle hostHandle, uint8_t parentHubNo) +{ + usb_host_hub_instance_t *hubInstance; + uint32_t deviceAddress; + usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle); + if (hubGlobal == NULL) + { + return NULL; + } + hubInstance = hubGlobal->hubList; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceAddress); + if (parentHubNo == deviceAddress) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + return hubInstance; + } + return (usb_host_hub_instance_t *)NULL; +} + +static void USB_HostSetHubRequestCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)param; + USB_HostFreeTransfer(param, transfer); + + if (kStatus_USB_Success == status) + { + /* call host callback function, function is initialized in USB_HostInit */ + hostInstance->deviceCallback(hostInstance->suspendedDevice, NULL, + kUSB_HostEventSuspended); /* call host callback function */ + } + else + { + /* call host callback function, function is initialized in USB_HostInit */ + hostInstance->deviceCallback(hostInstance->suspendedDevice, NULL, + kUSB_HostEventNotSuspended); /* call host callback function */ + } +} + +static void USB_HostClearHubRequestCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + USB_HostFreeTransfer(param, transfer); + + if (kStatus_USB_Success == status) + { + } +} + +static void USB_HostHubRemoteWakeupCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance; + usb_host_instance_t *hostInstance; + usb_host_device_instance_t *deviceInstance; + if (NULL == param) + { + return; + } + + hubInstance = (usb_host_hub_instance_t *)param; + + hostInstance = (usb_host_instance_t *)hubInstance->hostHandle; + if (NULL == hostInstance) + { + return; + } + + USB_HostFreeTransfer(hostInstance, transfer); + + if (kStatus_USB_Success != status) + { + usb_echo("Transfer failed to set remote wakeup request to HUB.\r\n"); + } + + if (kStatus_USB_Success == status) + { + hubInstance->controlRetry = USB_HOST_HUB_REMOTE_WAKEUP_TIMES; + hubInstance = hubInstance->next; + while (hubInstance) + { + hubInstance->controlRetry = USB_HOST_HUB_REMOTE_WAKEUP_TIMES; + if (hubInstance->supportRemoteWakeup) + { + usb_echo("Set HUB remote wakeup feature: level %d, address %d.\r\n", + ((usb_host_device_instance_t *)hubInstance->deviceHandle)->level, + ((usb_host_device_instance_t *)hubInstance->deviceHandle)->setAddress); + status = USB_HostSendHubRequest( + hubInstance->deviceHandle, + USB_REQUEST_TYPE_RECIPIENT_DEVICE | USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_STANDARD, + USB_REQUEST_STANDARD_SET_FEATURE, USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP, 0, + USB_HostHubRemoteWakeupCallback, hubInstance); + if (kStatus_USB_Success != status) + { + usb_echo("Send set remote wakeup request to HUB failed.\r\n"); + } + break; + } + hubInstance = hubInstance->next; + } + } + else + { + if (hubInstance->controlRetry) + { + hubInstance->controlRetry--; + usb_echo("Retry...\r\n", ((usb_host_device_instance_t *)hubInstance->deviceHandle)->level, + ((usb_host_device_instance_t *)hubInstance->deviceHandle)->setAddress); + status = USB_HostSendHubRequest( + hubInstance->deviceHandle, + USB_REQUEST_TYPE_RECIPIENT_DEVICE | USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_STANDARD, + USB_REQUEST_STANDARD_SET_FEATURE, USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP, 0, + USB_HostHubRemoteWakeupCallback, hubInstance); + if (kStatus_USB_Success != status) + { + usb_echo("Send set remote wakeup request to HUB failed.\r\n"); + } + } + else + { + usb_echo("Transfer failed to set remote wakeup request to HUB.\r\n"); + } + } + if (kStatus_USB_Success != status) + { + /* call host callback function, function is initialized in USB_HostInit */ + hostInstance->deviceCallback(hostInstance->suspendedDevice, NULL, kUSB_HostEventNotSuspended); + return; + } + if (NULL == hubInstance) + { + status = kStatus_USB_Error; + deviceInstance = (usb_host_device_instance_t *)hostInstance->suspendedDevice; + if (NULL == deviceInstance) + { + usb_host_bus_control_t type = kUSB_HostBusSuspend; + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, + &type); + if (kStatus_USB_Success != status) + { + usb_echo("Suspend USB BUS failed.\r\n"); + } + } + else + { + usb_host_hub_instance_t *hubInstance4Device = + USB_HostHubGetHubDeviceHandle(hostInstance, deviceInstance->hubNumber); + if (NULL != hubInstance4Device) + { + status = USB_HostSendHubRequest( + hubInstance4Device->deviceHandle, + USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_SET_FEATURE, PORT_SUSPEND, deviceInstance->portNumber, + USB_HostSetHubRequestCallback, hostInstance); + if (kStatus_USB_Success != status) + { + usb_echo("Send suspend request to HUB is failed.\r\n"); + } + } + else + { + usb_echo("Invalid HUB instance of device.\r\n"); + } + } + if (kStatus_USB_Success != status) + { + /* call host callback function, function is initialized in USB_HostInit */ + hostInstance->deviceCallback(hostInstance->suspendedDevice, NULL, kUSB_HostEventNotSuspended); + return; + } + } +} + +static usb_status_t USB_HostSendHubRequest(usb_device_handle deviceHandle, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + host_inner_transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_transfer_t *transfer; + + /* get transfer */ + if (USB_HostMallocTransfer(deviceInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + + /* initialize transfer */ + transfer->transferBuffer = NULL; + transfer->transferLength = 0U; + transfer->callbackFn = callbackFn; + transfer->callbackParam = callbackParam; + transfer->setupPacket->bmRequestType = requestType; + transfer->setupPacket->bRequest = request; + transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(wvalue); + transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(windex); + transfer->setupPacket->wLength = USB_SHORT_TO_LITTLE_ENDIAN(0U); + + /* send transfer */ + if (USB_HostSendSetup(deviceInstance->hostHandle, deviceInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("Error in sending hub set report!\r\n"); +#endif + USB_HostFreeTransfer(deviceInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + return kStatus_USB_Success; +} +#endif + +void USB_HostHubInterruptInCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hubInstance->hostHandle); + if (hubGlobal == NULL) + { + return; + } + + if (hubInstance->invalid == 1) + { + return; + } + /* interrupt data received */ + hubInstance->primeStatus = kPrimeNone; + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("hub interrupt in data callback error\r\n"); +#endif + /* prime nexe interrupt transfer */ + if (hubInstance->controlTransfer == NULL) + { + hubGlobal->hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } + } + else + { + USB_HostHubProcessData(hubGlobal, hubInstance); /* process the interrupt data */ + } +} + +/*! + * @brief host hub callback function. + * + * This function should be called in the host callback function. + * + * @param hostHandle host handle. + * @param deviceHandle device handle. + * @param configurationHandle attached device's configuration descriptor information. + * @param event_code callback event code, please reference to enumeration host_event_t. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_NotSupported The configuration don't contain hub interface. + */ +usb_status_t USB_HostHubDeviceEvent(usb_host_handle hostHandle, + usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode) +{ + usb_host_configuration_t *configuration; + usb_host_interface_t *interface; + uint8_t interfaceIndex; + uint8_t id; + usb_status_t status = kStatus_USB_Success; + usb_host_class_handle hubClassHandle; + usb_host_hub_instance_t *hubInstance; + usb_host_hub_instance_t *prevInstance; + uint32_t infoValue; + usb_osa_status_t osaStatus; + usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle); + if (hubGlobal == NULL) + { + return kStatus_USB_Error; + } + + switch (eventCode) + { + case kUSB_HostEventAttach: + /* judge whether is configurationHandle supported */ + configuration = (usb_host_configuration_t *)configurationHandle; + for (interfaceIndex = 0; interfaceIndex < configuration->interfaceCount; ++interfaceIndex) + { + interface = &configuration->interfaceList[interfaceIndex]; + id = interface->interfaceDesc->bInterfaceClass; + if (id != USB_HOST_HUB_CLASS_CODE) + { + continue; + } + id = interface->interfaceDesc->bInterfaceSubClass; + if (id != USB_HOST_HUB_SUBCLASS_CODE_NONE) + { + continue; + } + else + { + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + if (infoValue > 5) + { +#ifdef HOST_ECHO + usb_echo("Host can support max 5 level hubs\r\n"); +#endif + continue; + } + /* the interface is hub */ + s_HubDeviceHandle = deviceHandle; + s_HubInterfaceHandle = interface; +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + s_HubConfiguration = configuration; +#endif + return kStatus_USB_Success; + } + } + status = kStatus_USB_NotSupported; + break; + + case kUSB_HostEventEnumerationDone: + /* the device enumeration is done */ + if ((s_HubDeviceHandle != NULL) && (s_HubInterfaceHandle != NULL)) + { + /* print hub information */ + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + usb_echo("hub attached:level=%d ", infoValue); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + usb_echo("address=%d\r\n", infoValue); + + /* initialize hub mutex */ + if (hubGlobal->hubMutex == (usb_osa_mutex_handle)NULL) + { + osaStatus = USB_OsaMutexCreate(&hubGlobal->hubMutex); + if (osaStatus != kStatus_USB_OSA_Success) + { + hubGlobal->hubMutex = NULL; +#ifdef HOST_ECHO + usb_echo("hub mutex error\r\n"); +#endif + } + } + + /* initialize hub class instance */ + status = USB_HostHubInit(s_HubDeviceHandle, &hubClassHandle); + hubInstance = (usb_host_hub_instance_t *)hubClassHandle; + + /* link hub instance to list */ + USB_HostHubLock(); + hubInstance->next = hubGlobal->hubList; + hubGlobal->hubList = hubInstance; + USB_HostHubUnlock(); +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + hubInstance->supportRemoteWakeup = 0U; + hubInstance->controlRetry = USB_HOST_HUB_REMOTE_WAKEUP_TIMES; + if (s_HubConfiguration->configurationDesc->bmAttributes & + USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_REMOTE_WAKEUP_MASK) + { + hubInstance->supportRemoteWakeup = 1U; + } +#endif + /* set hub instance's interface */ + if (status == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + hubInstance->hubStatus = kHubRunWaitSetInterface; + if (USB_HostHubSetInterface(hubClassHandle, s_HubInterfaceHandle, 0, USB_HostHubControlCallback, + hubInstance) != kStatus_USB_Success) + { + hubInstance->hubStatus = kHubRunInvalid; + } + } + } + break; + + case kUSB_HostEventDetach: + /* the device is detached */ + hubInstance = NULL; + + /* get device's hub instance handle */ + USB_HostHubLock(); + prevInstance = hubGlobal->hubList; + if (prevInstance->deviceHandle == deviceHandle) + { + hubInstance = prevInstance; + hubGlobal->hubList = prevInstance->next; + } + else + { + hubInstance = prevInstance->next; + while (hubInstance != NULL) + { + if (hubInstance->deviceHandle == deviceHandle) + { + prevInstance->next = hubInstance->next; + break; + } + prevInstance = hubInstance; + hubInstance = hubInstance->next; + } + } + USB_HostHubUnlock(); + + if (hubInstance != NULL) + { + if (hubInstance == hubGlobal->hubProcess) + { + hubGlobal->hubProcess = NULL; + } + /* print hub information */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + usb_echo("hub detached:level=%d ", infoValue); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + usb_echo("address=%d\r\n", infoValue); + hubInstance->invalid = 1; + /* detach hub ports' devices */ + for (uint8_t portIndex = 0; portIndex < hubInstance->portCount; ++portIndex) + { + if ((hubInstance->portList != NULL) && (hubInstance->portList[portIndex].deviceHandle != NULL)) + { + USB_HostDetachDeviceInternal(hubInstance->hostHandle, + hubInstance->portList[portIndex].deviceHandle); + hubInstance->portList[portIndex].deviceHandle = NULL; + } + } + if (hubInstance->portList != NULL) + { + USB_OsaMemoryFree(hubInstance->portList); + } + USB_HostHubDeinit(deviceHandle, hubInstance); /* de-initialize hub instance */ + } + + /* destroy hub mutex if there is no hub instance */ + if (hubGlobal->hubList == NULL) + { + if (hubGlobal->hubMutex != NULL) + { + USB_OsaMutexDestroy(hubGlobal->hubMutex); + hubGlobal->hubMutex = NULL; + } + } + break; + + default: + break; + } + + return status; +} + +/*! + * @brief remove attached device. called by USB_HostRemoveDevice. + * + * @param hubNumber the device attached hub. + * @param portNumber the device attached port. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostHubRemovePort(usb_host_handle hostHandle, uint8_t hubNumber, uint8_t portNumber) +{ + usb_host_hub_instance_t *hubInstance; + uint32_t infoValue; + usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle); + if (hubGlobal == NULL) + { + return kStatus_USB_Error; + } + + /* get hub number's hub instance handle */ + hubInstance = (usb_host_hub_instance_t *)hubGlobal->hubList; + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + if (infoValue == hubNumber) + { + break; + } + hubInstance = hubInstance->next; + } + + /* set port's status as default, and reset port */ + if (hubInstance != NULL) + { + hubInstance->portList[portNumber - 1].deviceHandle = NULL; + hubInstance->portList[portNumber - 1].portStatus = kPortRunInvalid; + if (hubInstance->portProcess == portNumber) + { + hubInstance->portProcess = 0; + } + USB_HostHubSendPortReset(hubInstance, portNumber); + } + return kStatus_USB_Error; +} + +/*! + * @brief get device's high-speed hub's address. + * + * @param parent_hub_no device's parent hub's address. + * + * @return hub number. + */ +uint32_t USB_HostHubGetHsHubNumber(usb_host_handle hostHandle, uint8_t parentHubNo) +{ + usb_host_hub_instance_t *hubInstance; + uint32_t deviceInfo; + uint32_t hubNumber; + usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle); + if (hubGlobal == NULL) + { + return kStatus_USB_Error; + } + hubInstance = hubGlobal->hubList; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceInfo); + if (parentHubNo == deviceInfo) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceSpeed, &deviceInfo); + if (deviceInfo == USB_SPEED_HIGH) /* parent hub is HS */ + { + hubNumber = parentHubNo; + } + else /* parent hub is not HS */ + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceHSHubNumber, + &hubNumber); + } + return hubNumber; + } + return 0; +} + +/*! + * @brief get device's high-speed hub's port number. + * + * @param parent_hub_no device's parent hub's address. + * @param parent_port_no device's parent port no. + * + * @return port number. + */ +uint32_t USB_HostHubGetHsHubPort(usb_host_handle hostHandle, uint8_t parentHubNo, uint8_t parentPortNo) +{ + usb_host_hub_instance_t *hubInstance; + uint32_t deviceInfo; + uint32_t hubPort; + usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle); + if (hubGlobal == NULL) + { + return kStatus_USB_Error; + } + hubInstance = hubGlobal->hubList; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceInfo); + if (parentHubNo == deviceInfo) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceSpeed, &deviceInfo); + if (deviceInfo == USB_SPEED_HIGH) /* parent hub is HS */ + { + hubPort = parentPortNo; + } + else /* parent hub is not HS */ + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceHSHubNumber, &hubPort); + } + return hubPort; + } + return 0; +} + +/*! + * @brief get device's hub total think time. + * + * @param parent_hub_no device's parent hub's address. + * + * @return think time value. + */ +uint32_t USB_HostHubGetTotalThinkTime(usb_host_handle hostHandle, uint8_t parentHubNo) +{ + usb_host_hub_instance_t *hubInstance; + uint32_t deviceAddress; + usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle); + if (hubGlobal == NULL) + { + return kStatus_USB_Error; + } + hubInstance = hubGlobal->hubList; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceAddress); + if (parentHubNo == deviceAddress) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + return hubInstance->totalThinktime; + } + return 0; +} + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) +/*! + * @brief Suspend the device. + * + * @param hostHandle Host instance. + * + * @return kStatus_USB_Success or error codes. + * + */ +usb_status_t USB_HostHubSuspendDevice(usb_host_handle hostHandle) +{ + usb_host_instance_t *hostInstance; + usb_host_hub_instance_t *hubInstance; + usb_status_t status = kStatus_USB_Error; + usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle); + if (hubGlobal == NULL) + { + return kStatus_USB_Error; + } + hubInstance = hubGlobal->hubList; + + if (NULL == hostHandle) + { + return kStatus_USB_InvalidHandle; + } + hostInstance = (usb_host_instance_t *)hostHandle; + if (NULL == hubInstance) + { + usb_host_bus_control_t type = kUSB_HostBusSuspend; + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = + hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, &type); + if (kStatus_USB_Success != status) + { + usb_echo("Suspend USB BUS failed.\r\n"); + } + return status; + } + /* Scan HUB instance handle */ + while (hubInstance != NULL) + { + hubInstance->controlRetry = USB_HOST_HUB_REMOTE_WAKEUP_TIMES; + if (hubInstance->supportRemoteWakeup) + { + usb_echo("Set HUB remote wakeup feature: level %d, address %d.\r\n", + ((usb_host_device_instance_t *)hubInstance->deviceHandle)->level, + ((usb_host_device_instance_t *)hubInstance->deviceHandle)->setAddress); + status = USB_HostSendHubRequest( + hubInstance->deviceHandle, + USB_REQUEST_TYPE_RECIPIENT_DEVICE | USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_STANDARD, + USB_REQUEST_STANDARD_SET_FEATURE, USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP, 0, + USB_HostHubRemoteWakeupCallback, hubInstance); + break; + } + hubInstance = hubInstance->next; + } + if (NULL == hubInstance) + { + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)hostInstance->suspendedDevice; + if (NULL == deviceInstance) + { + usb_host_bus_control_t type = kUSB_HostBusSuspend; + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, + &type); + if (kStatus_USB_Success != status) + { + usb_echo("Suspend USB BUS failed.\r\n"); + } + } + else + { + usb_host_hub_instance_t *hubInstance4Device = + USB_HostHubGetHubDeviceHandle(hostHandle, deviceInstance->hubNumber); + if (NULL != hubInstance4Device) + { + status = USB_HostSendHubRequest( + hubInstance4Device->deviceHandle, + USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_SET_FEATURE, PORT_SUSPEND, deviceInstance->portNumber, + USB_HostSetHubRequestCallback, hostInstance); + if (kStatus_USB_Success != status) + { + usb_echo("Send suspend request to HUB is failed.\r\n"); + } + } + else + { + usb_echo("Invalid HUB instance of device.\r\n"); + } + } + } + return status; +} + +/*! + * @brief Resume the device. + * + * @param hostHandle Host instance. + * + * @return kStatus_USB_Success or error codes. + * + */ +usb_status_t USB_HostHubResumeDevice(usb_host_handle hostHandle) +{ + usb_host_instance_t *hostInstance; + usb_host_device_instance_t *deviceInstance; + usb_status_t status = kStatus_USB_Error; + + if (NULL == hostHandle) + { + return kStatus_USB_InvalidHandle; + } + hostInstance = (usb_host_instance_t *)hostHandle; + + deviceInstance = (usb_host_device_instance_t *)hostInstance->suspendedDevice; + if (NULL == deviceInstance) + { + return kStatus_USB_InvalidHandle; + } + + status = USB_HostSendHubRequest( + USB_HostHubGetHubDeviceHandle(hostHandle, deviceInstance->hubNumber)->deviceHandle, + USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_CLEAR_FEATURE, PORT_SUSPEND, deviceInstance->portNumber, USB_HostClearHubRequestCallback, + hostInstance); + + return status; +} +#endif + +#endif /* USB_HOST_CONFIG_HUB */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub_app.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub_app.h new file mode 100644 index 000000000..4727d0a19 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_hub_app.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _USB_HOST_HUB_APP_H_ +#define _USB_HOST_HUB_APP_H_ + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief HUB reset times*/ +#define USB_HOST_HUB_PORT_RESET_TIMES (1) + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) +/*! @brief HUB Control tansaction retry times for remote wakeup*/ +#define USB_HOST_HUB_REMOTE_WAKEUP_TIMES (3U) +#endif + +/*! @brief HUB application global structure */ +typedef struct _usb_host_hub_global +{ + usb_host_handle hostHandle; /*!< This HUB list belong to this host*/ + usb_host_hub_instance_t *hubProcess; /*!< HUB in processing*/ + usb_host_hub_instance_t *hubList; /*!< host's HUB list*/ + usb_osa_mutex_handle hubMutex; /*!< HUB mutex*/ +} usb_host_hub_global_t; + +/*! @brief HUB application status */ +typedef enum _usb_host_hub_app_status +{ + kHubRunIdle = 0, /*!< Idle */ + kHubRunInvalid, /*!< Invalid state */ + kHubRunWaitSetInterface, /*!< Wait callback of set interface */ + kHubRunGetDescriptor7, /*!< Get 7 bytes HUB descriptor */ + kHubRunGetDescriptor, /*!< Get all HUB descriptor */ + kHubRunSetPortPower, /*!< Set HUB's port power */ + kHubRunGetStatusDone, /*!< HUB status changed */ + kHubRunClearDone, /*!< clear HUB feature callback */ +} usb_host_hub_app_status_t; + +/*! @brief HUB port application status */ +typedef enum _usb_host_port_app_status +{ + kPortRunIdle = 0, /*!< Idle */ + kPortRunInvalid, /*!< Invalid state */ + kPortRunWaitPortChange, /*!< Wait port status change */ + kPortRunCheckCPortConnection, /*!< Check C_PORT_CONNECTION */ + kPortRunGetPortConnection, /*!< Get port status data */ + kPortRunCheckPortConnection, /*!< Check PORT_CONNECTION */ + kPortRunWaitPortResetDone, /*!< Wait port reset transfer done */ + kPortRunWaitCPortReset, /*!< Wait C_PORT_RESET */ + KPortRunCheckCPortReset, /*!< Check C_PORT_RESET */ + kPortRunResetAgain, /*!< Reset port again */ + kPortRunPortAttached, /*!< Device is attached on the port */ + kPortRunCheckPortDetach, /*!< Check port is detached */ + kPortRunGetConnectionBit, /*!< Get the port status data */ + kPortRunCheckConnectionBit, /*!< Check PORT_CONNECTION */ +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + kPortRunClearCPortSuspend, /*!< Clear C_PORT_SUSPEND */ + kPortRunCheckPortSuspend, /*!< Check PORT_SUSPEND */ + kPortRunPortSuspended, /*!< Port is suspended */ +#endif +} usb_host_port_app_status_t; + +/*! @brief HUB data prime status */ +typedef enum _usb_host_hub_prime_status +{ + kPrimeNone = 0, /*!< Don't prime data*/ + kPrimeHubControl, /*!< Prime HUB control transfer*/ + kPrimePortControl, /*!< Prime port control transfer*/ + kPrimeInterrupt, /*!< Prime interrupt transfer*/ +} usb_host_hub_prime_status_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#endif /* USB_HOST_CONFIG_HUB */ + +#endif /* _USB_HOST_HUB_APP_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd.c new file mode 100644 index 000000000..bd34ed7c9 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd.c @@ -0,0 +1,1137 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016, 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_MSD) && (USB_HOST_CONFIG_MSD)) +#include "usb_host.h" +#include "usb_host_msd.h" +#include "usb_host_hci.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief clear stall transfer callback. + * + * @param param callback parameter. + * @param transfer transfer. + * @param status transfer result status. + */ +static void USB_HostMsdClearHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief send clear stall transfer. + * + * @param msdInstance msd instance pointer. + * @param callbackFn callback function. + * @param endpoint endpoint address. + * + * @return An error code or kStatus_USB_Success. + */ +static usb_status_t USB_HostMsdClearHalt(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t callbackFn, + uint8_t endpoint); + +/*! + * @brief mass storage reset three step processes are done. + * + * @param msdInstance msd instance pointer. + * @param status result status. + */ +static void USB_HostMsdResetDone(usb_host_msd_instance_t *msdInstance, usb_status_t status); + +/*! + * @brief mass storage reset process step 3 callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdMassResetClearOutCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief mass storage reset process step 2 callback. + * + * @param msdInstance msd instance pointer. + * @transfer transfer + * @param status result status. + */ +static void USB_HostMsdMassResetClearInCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief mass storage reset process step 1 callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdMassResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief mass storage control transfer callback function. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief this function is called when ufi command is done. + * + * @param msdInstance msd instance pointer. + */ +static void USB_HostMsdCommandDone(usb_host_msd_instance_t *msdInstance, usb_status_t status); + +/*! + * @brief csw transfer callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdCswCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief cbw transfer callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdCbwCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief data transfer callback. + * + * @param msdInstance sd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdDataCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief msd open interface. + * + * @param msdInstance msd instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostMsdOpenInterface(usb_host_msd_instance_t *msdInstance); + +/*! + * @brief msd set interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostMsdSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief msd control transfer common code. + * + * This function allocate the resource for msd instance. + * + * @param msdInstance the msd class instance. + * @param pipeCallbackFn inner callback function. + * @param callbackFn callback function. + * @param callbackParam callback parameter. + * @param buffer buffer pointer. + * @param bufferLength buffer length. + * @param requestType request type. + * @param requestValue request value. + * + * @return An error code or kStatus_USB_Success. + */ +static usb_status_t USB_HostMsdControl(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t pipeCallbackFn, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t *buffer, + uint16_t bufferLength, + uint8_t requestType, + uint8_t requestValue); + +/*! + * @brief command process function, this function is called many time for one command's different state. + * + * @param msdInstance the msd class instance. + * + * @return An error code or kStatus_USB_Success. + */ +static usb_status_t USB_HostMsdProcessCommand(usb_host_msd_instance_t *msdInstance); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostMsdClearHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + if (status != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_TransferCancel); + } + + if (msdInstance->commandStatus == kMSD_CommandErrorDone) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); /* command fail */ + } + else + { + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } +} + +static usb_status_t USB_HostMsdClearHalt(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t callbackFn, + uint8_t endpoint) +{ + usb_status_t status; + usb_host_transfer_t *transfer; + + /* malloc one transfer */ + status = USB_HostMallocTransfer(msdInstance->hostHandle, &transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return status; + } + + /* initialize transfer */ + transfer->callbackFn = callbackFn; + transfer->callbackParam = msdInstance; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_CLEAR_FEATURE; + transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT); + transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(endpoint); + transfer->setupPacket->wLength = 0; + status = USB_HostSendSetup(msdInstance->hostHandle, msdInstance->controlPipe, transfer); + + if (status != kStatus_USB_Success) + { + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + } + msdInstance->controlTransfer = transfer; + + return status; +} + +static void USB_HostMsdResetDone(usb_host_msd_instance_t *msdInstance, usb_status_t status) +{ + if (msdInstance->internalResetRecovery == 1) /* internal mass reset recovery */ + { + msdInstance->internalResetRecovery = 0; + + if ((status != kStatus_USB_Success) || (msdInstance->commandStatus == kMSD_CommandErrorDone)) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); /* command fail */ + } + else + { + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } + } + else /* user call mass storage reset recovery */ + { + if (msdInstance->controlCallbackFn != NULL) + { + /* callback to application, callback function is initialized in the USB_HostMsdControl, + or USB_HostMsdSetInterface, but is the same function */ + msdInstance->controlCallbackFn(msdInstance->controlCallbackParam, NULL, 0, + status); /* callback to application */ + } + } +} + +static void USB_HostMsdMassResetClearOutCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + USB_HostMsdResetDone(msdInstance, status); /* mass storage reset done */ +} + +static void USB_HostMsdMassResetClearInCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + + if (status == kStatus_USB_Success) + { + if (msdInstance->outPipe != NULL) + { + /* continue to process mass storage reset */ + USB_HostMsdClearHalt( + msdInstance, USB_HostMsdMassResetClearOutCallback, + (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)msdInstance->outPipe)->endpointAddress)); + } + } + else + { + USB_HostMsdResetDone(msdInstance, status); /* mass storage reset done */ + } +} + +static void USB_HostMsdMassResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + if (status == kStatus_USB_Success) + { + if (msdInstance->inPipe != NULL) + { + /* continue to process mass storage reset */ + USB_HostMsdClearHalt(msdInstance, USB_HostMsdMassResetClearInCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)); + } + } + else + { + USB_HostMsdResetDone(msdInstance, status); /* mass storage reset done */ + } +} + +static void USB_HostMsdControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + if (msdInstance->controlCallbackFn != NULL) + { + /* callback to application, callback function is initialized in the USB_HostMsdControl, + or USB_HostMsdSetInterface, but is the same function */ + msdInstance->controlCallbackFn(msdInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); /* callback to application */ + } + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); +} + +static void USB_HostMsdCommandDone(usb_host_msd_instance_t *msdInstance, usb_status_t status) +{ + if (msdInstance->commandCallbackFn != NULL) + { + /* callback to application, the callback function is initialized in USB_HostMsdCommand */ + msdInstance->commandCallbackFn(msdInstance->commandCallbackParam, msdInstance->msdCommand.dataBuffer, + msdInstance->msdCommand.dataSofar, status); + } + msdInstance->commandStatus = kMSD_CommandIdle; +} + +static void USB_HostMsdCswCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + if (status == kStatus_USB_Success) + { + /* kStatus_USB_Success */ + if ((transfer->transferSofar == USB_HOST_UFI_CSW_LENGTH) && + (msdInstance->msdCommand.cswBlock.CSWSignature == USB_LONG_TO_LITTLE_ENDIAN(USB_HOST_MSD_CSW_SIGNATURE))) + { + switch (msdInstance->msdCommand.cswBlock.CSWStatus) + { + case 0: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Success); + break; + + case 1: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_MSDStatusFail); + break; + + case 2: + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + break; + + default: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_MSDStatusFail); + break; + } + } + else + { + /* mass reset recovery to end ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + else + { + if (status == kStatus_USB_TransferStall) /* case 1: stall */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (msdInstance->msdCommand.retryTime > 0) + { + /* clear stall to continue the ufi command */ + if (USB_HostMsdClearHalt( + msdInstance, USB_HostMsdClearHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)) != + kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + else if (status == kStatus_USB_TransferCancel) /* case 2: cancel */ + { + USB_HostMsdCommandDone(msdInstance, status); /* command cancel */ + } + else /* case 3: error */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (msdInstance->msdCommand.retryTime > 0) + { + USB_HostMsdProcessCommand(msdInstance); /* retry the last step transaction */ + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + } +} + +static void USB_HostMsdCbwCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + if (status == kStatus_USB_Success) + { + /* kStatus_USB_Success */ + if (transfer->transferSofar == USB_HOST_UFI_CBW_LENGTH) + { + msdInstance->commandStatus = kMSD_CommandTransferData; + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } + else + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; + } + if (msdInstance->msdCommand.retryTime > 0) + { + USB_HostMsdProcessCommand(msdInstance); /* retry the last step transaction */ + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + } + else + { + if (status == kStatus_USB_TransferStall) /* case 1: stall */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (msdInstance->msdCommand.retryTime > 0) + { + /* clear stall to continue the ufi command */ + if (USB_HostMsdClearHalt( + msdInstance, USB_HostMsdClearHaltCallback, + (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)) != + kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + else if (status == kStatus_USB_TransferCancel) /* case 2: cancel */ + { + USB_HostMsdCommandDone(msdInstance, status); /* command cancel */ + } + else /* case 3: error */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; + } + if (msdInstance->msdCommand.retryTime > 0) + { + USB_HostMsdProcessCommand(msdInstance); /* retry the last step transaction */ + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + return; + } +} + +static void USB_HostMsdDataCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + uint8_t direction; + + if (status == kStatus_USB_Success) + { + /* kStatus_USB_Success */ + msdInstance->msdCommand.dataSofar += transfer->transferSofar; + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } + else + { + if (status == kStatus_USB_TransferStall) /* case 1: stall */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (transfer->direction == USB_IN) + { + direction = USB_REQUEST_TYPE_DIR_IN; + } + else + { + direction = USB_REQUEST_TYPE_DIR_OUT; + } + + if (msdInstance->msdCommand.retryTime == 0) + { + msdInstance->commandStatus = kMSD_CommandTransferCSW; /* next step */ + } + /* clear stall to continue the ufi command */ + if (USB_HostMsdClearHalt(msdInstance, USB_HostMsdClearHaltCallback, + (direction | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)) != + kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + else if (status == kStatus_USB_TransferCancel) /* case 2: cancel */ + { + USB_HostMsdCommandDone(msdInstance, status); /* command cancel */ + } + else /* case 3: error */ + { + /* mass reset recovery to finish ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } +} + +static usb_status_t USB_HostMsdProcessCommand(usb_host_msd_instance_t *msdInstance) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_transfer_t *transfer; + + if (msdInstance->msdCommand.transfer == NULL) + { + /* malloc one transfer */ + status = USB_HostMallocTransfer(msdInstance->hostHandle, &(msdInstance->msdCommand.transfer)); + if (status != kStatus_USB_Success) + { + msdInstance->msdCommand.transfer = NULL; +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return kStatus_USB_Busy; + } + } + transfer = msdInstance->msdCommand.transfer; + switch (msdInstance->commandStatus) + { + case kMSD_CommandTransferCBW: /* ufi CBW phase */ + transfer->direction = USB_OUT; + transfer->transferBuffer = (uint8_t *)(&(msdInstance->msdCommand.cbwBlock)); + transfer->transferLength = USB_HOST_UFI_CBW_LENGTH; + transfer->callbackFn = USB_HostMsdCbwCallback; + transfer->callbackParam = msdInstance; + status = USB_HostSend(msdInstance->hostHandle, msdInstance->outPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host send error\r\n"); +#endif + } + break; + + case kMSD_CommandTransferData: /* ufi DATA phase */ + if (msdInstance->msdCommand.dataBuffer != NULL) + { + transfer->direction = msdInstance->msdCommand.dataDirection; + transfer->transferBuffer = (msdInstance->msdCommand.dataBuffer + msdInstance->msdCommand.dataSofar); + transfer->transferLength = (msdInstance->msdCommand.dataLength - msdInstance->msdCommand.dataSofar); + transfer->callbackParam = msdInstance; + if (msdInstance->msdCommand.dataSofar != msdInstance->msdCommand.dataLength) + { + if (transfer->direction == USB_OUT) + { + transfer->callbackFn = USB_HostMsdDataCallback; + status = USB_HostSend(msdInstance->hostHandle, msdInstance->outPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host send error\r\n"); +#endif + } + } + else + { + transfer->callbackFn = USB_HostMsdDataCallback; + status = USB_HostRecv(msdInstance->hostHandle, msdInstance->inPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host recv error\r\n"); +#endif + } + } + break; + } + else + { + /* don't break */ + } + } + else + { + /* don't break */ + } + case kMSD_CommandTransferCSW: /* ufi CSW phase */ + transfer->direction = USB_IN; + transfer->transferBuffer = (uint8_t *)&msdInstance->msdCommand.cswBlock; + transfer->transferLength = USB_HOST_UFI_CSW_LENGTH; + transfer->callbackFn = USB_HostMsdCswCallback; + transfer->callbackParam = msdInstance; + status = USB_HostRecv(msdInstance->hostHandle, msdInstance->inPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host recv error\r\n"); +#endif + } + break; + + case kMSD_CommandDone: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Success); + break; + + default: + break; + } + return status; +} + +/*! + * @brief all ufi function calls this api. + * + * This function implements the common ufi commands. + * + * @param classHandle the class msd handle. + * @param buffer buffer pointer. + * @param bufferLength buffer length. + * @param callbackFn callback function. + * @param callbackParam callback parameter. + * @param direction command direction. + * @param byteValues ufi command fields value. + * + * @return An error code or kStatus_USB_Success. + */ +usb_status_t USB_HostMsdCommand(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t direction, + uint8_t byteValues[10]) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + usb_host_cbw_t *cbwPointer = &(msdInstance->msdCommand.cbwBlock); + uint8_t index = 0; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (msdInstance->commandStatus != kMSD_CommandIdle) + { + return kStatus_USB_Busy; + } + + /* save the application callback function */ + msdInstance->commandCallbackFn = callbackFn; + msdInstance->commandCallbackParam = callbackParam; + + /* initialize CBWCB fields */ + for (index = 0; index < USB_HOST_UFI_BLOCK_DATA_VALID_LENGTH; ++index) + { + cbwPointer->CBWCB[index] = byteValues[index]; + } + + /* initialize CBW fields */ + cbwPointer->CBWDataTransferLength = USB_LONG_TO_LITTLE_ENDIAN(bufferLength); + cbwPointer->CBWFlags = direction; + cbwPointer->CBWLun = (byteValues[1] >> USB_HOST_UFI_LOGICAL_UNIT_POSITION); + cbwPointer->CBWCBLength = USB_HOST_UFI_BLOCK_DATA_VALID_LENGTH; + + msdInstance->commandStatus = kMSD_CommandTransferCBW; + if (direction == USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN) + { + msdInstance->msdCommand.dataDirection = USB_IN; + } + else + { + msdInstance->msdCommand.dataDirection = USB_OUT; + } + msdInstance->msdCommand.dataBuffer = buffer; + + msdInstance->msdCommand.dataLength = bufferLength; + msdInstance->msdCommand.dataSofar = 0; + msdInstance->msdCommand.retryTime = USB_HOST_MSD_RETRY_MAX_TIME; + + return USB_HostMsdProcessCommand(msdInstance); /* start to process ufi command */ +} + +static usb_status_t USB_HostMsdOpenInterface(usb_host_msd_instance_t *msdInstance) +{ + usb_status_t status; + uint8_t epIndex = 0; + usb_host_pipe_init_t pipeInit; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_interface_t *interfacePointer; + + if (msdInstance->inPipe != NULL) /* close bulk in pipe if the pipe is open */ + { + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->inPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + msdInstance->inPipe = NULL; + } + if (msdInstance->outPipe != NULL) /* close bulk out pipe if the pipe is open */ + { + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->outPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + msdInstance->outPipe = NULL; + } + + /* open interface pipes */ + interfacePointer = (usb_host_interface_t *)msdInstance->interfaceHandle; + for (epIndex = 0; epIndex < interfacePointer->epCount; ++epIndex) + { + epDesc = interfacePointer->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = msdInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + status = USB_HostOpenPipe(msdInstance->hostHandle, &msdInstance->inPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_hid_set_interface fail to open pipe\r\n"); +#endif + return status; + } + } + else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = msdInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_OUT; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + status = USB_HostOpenPipe(msdInstance->hostHandle, &msdInstance->outPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_hid_set_interface fail to open pipe\r\n"); +#endif + return status; + } + } + else + { + } + } + + return kStatus_USB_Success; +} + +static void USB_HostMsdSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + status = USB_HostMsdOpenInterface(msdInstance); /* msd open interface */ + } + + if (msdInstance->controlCallbackFn != NULL) + { + /* callback to application, callback function is initialized in the USB_HostMsdControl, + or USB_HostMsdSetInterface, but is the same function */ + msdInstance->controlCallbackFn(msdInstance->controlCallbackParam, NULL, 0, + status); /* callback to application */ + } + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); +} + +usb_status_t USB_HostMsdInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) +{ + uint32_t infoValue; + usb_status_t status; + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)USB_OsaMemoryAllocate( + sizeof(usb_host_msd_instance_t)); /* malloc msd class instance */ + + if (msdInstance == NULL) + { + return kStatus_USB_AllocFail; + } + + /* initialize msd instance */ + msdInstance->deviceHandle = deviceHandle; + msdInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + msdInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + msdInstance->controlPipe = (usb_host_pipe_handle)infoValue; + + msdInstance->msdCommand.cbwBlock.CBWSignature = USB_LONG_TO_LITTLE_ENDIAN(USB_HOST_MSD_CBW_SIGNATURE); + status = USB_HostMallocTransfer(msdInstance->hostHandle, &(msdInstance->msdCommand.transfer)); + if (status != kStatus_USB_Success) + { + msdInstance->msdCommand.transfer = NULL; +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + } + + *classHandle = msdInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostMsdSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status = kStatus_USB_Error; + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + status = USB_HostOpenDeviceInterface(msdInstance->deviceHandle, + interfaceHandle); /* notify host driver the interface is open */ + if (status != kStatus_USB_Success) + { + return status; + } + msdInstance->interfaceHandle = interfaceHandle; + + /* cancel transfers */ + if (msdInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->inPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + if (msdInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->outPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + + if (alternateSetting == 0) /* open interface directly */ + { + if (callbackFn != NULL) + { + status = USB_HostMsdOpenInterface(msdInstance); + callbackFn(callbackParam, NULL, 0, status); + } + } + else /* send setup transfer */ + { + /* malloc one transfer */ + if (USB_HostMallocTransfer(msdInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + msdInstance->controlCallbackFn = callbackFn; + msdInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->callbackFn = USB_HostMsdSetInterfaceCallback; + transfer->callbackParam = msdInstance; + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_SET_INTERFACE; + transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)msdInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket->wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + status = USB_HostSendSetup(msdInstance->hostHandle, msdInstance->controlPipe, transfer); + + if (status == kStatus_USB_Success) + { + msdInstance->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + } + } + + return status; +} + +usb_status_t USB_HostMsdDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + usb_status_t status; + + if (classHandle != NULL) + { + if (msdInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->inPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->inPipe); /* close pipe */ + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + } + if (msdInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->outPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->outPipe); /* close pipe */ + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + } + if ((msdInstance->controlPipe != NULL) && + (msdInstance->controlTransfer != NULL)) /* cancel control transfer if there is on-going control transfer */ + { + status = + USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->controlPipe, msdInstance->controlTransfer); + } + if (msdInstance->msdCommand.transfer) + { + USB_HostFreeTransfer(msdInstance->hostHandle, msdInstance->msdCommand.transfer); + } + USB_HostCloseDeviceInterface(deviceHandle, + msdInstance->interfaceHandle); /* notify host driver the interface is closed */ + USB_OsaMemoryFree(msdInstance); + } + else + { + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostMsdControl(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t pipeCallbackFn, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t *buffer, + uint16_t bufferLength, + uint8_t requestType, + uint8_t requestValue) +{ + usb_host_transfer_t *transfer; + + if (msdInstance == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(msdInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + msdInstance->controlCallbackFn = callbackFn; + msdInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = pipeCallbackFn; + transfer->callbackParam = msdInstance; + + transfer->setupPacket->bmRequestType = requestType; + transfer->setupPacket->bRequest = requestValue; + transfer->setupPacket->wValue = 0x0000; + transfer->setupPacket->wIndex = + ((usb_host_interface_t *)msdInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber; + transfer->setupPacket->wLength = bufferLength; + + if (USB_HostSendSetup(msdInstance->hostHandle, msdInstance->controlPipe, transfer) != + kStatus_USB_Success) /* call host driver api */ + { + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + msdInstance->controlTransfer = transfer; + + return kStatus_USB_Success; +} + +usb_status_t USB_HostMsdMassStorageReset(usb_host_class_handle classHandle, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + + return USB_HostMsdControl(msdInstance, USB_HostMsdMassResetCallback, callbackFn, callbackParam, NULL, 0, + (USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE), + USB_HOST_HID_MASS_STORAGE_RESET); +} + +usb_status_t USB_HostMsdGetMaxLun(usb_host_class_handle classHandle, + uint8_t *logicalUnitNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + + return USB_HostMsdControl( + msdInstance, USB_HostMsdControlCallback, callbackFn, callbackParam, logicalUnitNumber, 1, + (USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE), + USB_HOST_HID_GET_MAX_LUN); +} + +#endif /* USB_HOST_CONFIG_MSD */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd.h new file mode 100644 index 000000000..e7fce910d --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd.h @@ -0,0 +1,851 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _USB_HOST_MSD_H_ +#define _USB_HOST_MSD_H_ + +/******************************************************************************* + * MSD class private structure, enumeration, macro + ******************************************************************************/ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* CBW and CSW Macros */ +#define USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT (0x00U) +#define USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN (0x80U) +#define USB_HOST_MSD_CBW_SIGNATURE (0x43425355U) +#define USB_HOST_MSD_CSW_SIGNATURE (0x53425355U) + +/* UFI data bit macro */ +#define USB_HOST_UFI_BLOCK_DATA_VALID_LENGTH (10U) +#define USB_HOST_UFI_LOGICAL_UNIT_POSITION (5U) +#define USB_HOST_UFI_CBW_LENGTH (31U) +#define USB_HOST_UFI_CSW_LENGTH (13U) +#define USB_HOST_UFI_MODE_SENSE_PAGE_CONTROL_SHIFT (6U) +#define USB_HOST_UFI_MODE_SENSE_PAGE_CODE_SHIFT (0U) +#define USB_HOST_UFI_START_STOP_UNIT_LOEJ_SHIFT (1U) +#define USB_HOST_UFI_START_STOP_UNIT_START_SHIFT (0U) +#define USB_HOST_UFI_SEND_DIAGNOSTIC_SELF_TEST_SHIFT (2U) + +/******************************************************************************* + * MSD class public structure, enumeration, macro, function + ******************************************************************************/ +/*! + * @addtogroup usb_host_msc_drv + * @{ + */ + +/*! @brief retry time when transfer fail, when all the retries fail the transfer callback with error status */ +#define USB_HOST_MSD_RETRY_MAX_TIME (1U) +/*! @brief mass storage block size */ +#define USB_HOST_MSD_BLOCK_SIZE (512U) + +/*! @brief MSD class code */ +#define USB_HOST_MSD_CLASS_CODE (8U) +/*! @brief MSD sub-class code */ +#define USB_HOST_MSD_SUBCLASS_CODE_UFI (4U) +/*! @brief MSD sub-class code */ +#define USB_HOST_MSD_SUBCLASS_CODE_SCSI (6U) +/*! @brief MSD protocol code */ +#define USB_HOST_MSD_PROTOCOL_BULK (0x50U) + +/*! @brief MSD class-specific request (mass storage reset) */ +#define USB_HOST_HID_MASS_STORAGE_RESET (0xFFU) +/*! @brief MSD class-specific request (get maximum logical unit number) */ +#define USB_HOST_HID_GET_MAX_LUN (0xFEU) + +/*! @brief UFI command process status */ +typedef enum _usb_host_msd_command_status +{ + kMSD_CommandIdle = 0, + kMSD_CommandTransferCBW, + kMSD_CommandTransferData, + kMSD_CommandTransferCSW, + kMSD_CommandDone, + kMSD_CommandCancel, + kMSD_CommandErrorDone, +} usb_host_msd_command_status_t; + +/*! @brief MSC Bulk-Only command block wrapper (CBW) */ +typedef struct _usb_host_cbw +{ + uint32_t CBWSignature; /*!< Signature that helps identify this data packet as a CBW. The signature field shall + contain the value 43425355h (little endian), indicating a CBW */ + uint32_t + CBWTag; /*!< A Command Block Tag sent by the host. The device shall echo the contents of this field back to the + host in the dCSWTag field of the associated CSW */ + uint32_t CBWDataTransferLength; /*!< The number of bytes of data that the host expects to transfer on the Bulk-In or + Bulk-Out endpoint during the execution of this command */ + uint8_t CBWFlags; /*!< + Bit 7 Direction - the device shall ignore this bit if the dCBWDataTransferLength field is + zero, otherwise: + 0 = Data-Out from host to the device, + 1 = Data-In from the device to the host. + Bit 6 Obsolete. The host shall set this bit to zero. + Bits 5..0 Reserved - the host shall set these bits to zero. + */ + uint8_t CBWLun; /*!< The device Logical Unit Number (LUN) to which the command block is being sent */ + uint8_t CBWCBLength; /*!< The valid length of the CBWCB in bytes. This defines the valid length of the command + block. The only legal values are 1 through 16 (01h through 10h).*/ + uint8_t CBWCB[16]; /*!< The command block to be executed by the device*/ +} usb_host_cbw_t; + +/*! @brief MSC Bulk-Only command status wrapper (CSW) */ +typedef struct _usb_host_csw +{ + uint32_t CSWSignature; /*!< Signature that helps identify this data packet as a CSW. The signature field shall + contain the value 53425355h (little endian), indicating CSW.*/ + uint32_t CSWTag; /*!< The device shall set this field to the value received in the dCBWTag of the associated CBW*/ + uint32_t CSWDataResidue; /*!< the difference between the amount of data expected as stated in the + dCBWDataTransferLength and the actual amount of relevant data processed by the device.*/ + uint8_t CSWStatus; /*!< + bCSWStatus indicates the success or failure of the command. + 00h - Command passed. + 01h - Command Failed. + 02h - Phase error. + others - Reserved. + */ +} usb_host_csw_t; + +/*! @brief MSC UFI command information structure */ +typedef struct _usb_host_msd_command +{ + usb_host_cbw_t cbwBlock; /*!< CBW data block*/ + usb_host_csw_t cswBlock; /*!< CSW data block*/ + uint8_t *dataBuffer; /*!< Data buffer pointer*/ + uint32_t dataLength; /*!< Data buffer length*/ + uint32_t dataSofar; /*!< Successful transfer data length*/ + usb_host_transfer_t *transfer; /*!< The transfer is used for processing the UFI command*/ + uint8_t retryTime; /*!< The UFI command residual retry time, when it reduce to zero the UFI command fail */ + uint8_t dataDirection; /*!< The data direction, its value is USB_OUT or USB_IN*/ +} usb_host_msd_command_t; + +/*! @brief MSD instance structure, MSD usb_host_class_handle pointer to this structure */ +typedef struct _usb_host_msd_instance +{ + usb_host_handle hostHandle; /*!< This instance's related host handle*/ + usb_device_handle deviceHandle; /*!< This instance's related device handle*/ + usb_host_interface_handle interfaceHandle; /*!< This instance's related interface handle*/ + usb_host_pipe_handle controlPipe; /*!< This instance's related device control pipe*/ + usb_host_pipe_handle outPipe; /*!< MSD bulk out pipe*/ + usb_host_pipe_handle inPipe; /*!< MSD bulk in pipe*/ + transfer_callback_t commandCallbackFn; /*!< MSD UFI command callback function pointer*/ + void *commandCallbackParam; /*!< MSD UFI command callback parameter*/ + transfer_callback_t controlCallbackFn; /*!< MSD control transfer callback function pointer*/ + void *controlCallbackParam; /*!< MSD control transfer callback parameter*/ + usb_host_transfer_t *controlTransfer; /*!< Ongoing control transfer*/ + usb_host_msd_command_t msdCommand; /*!< Ongoing MSD UFI command information*/ + uint8_t commandStatus; /*!< UFI command process status, see command_status_t*/ + uint8_t internalResetRecovery; /*!< 1 - class driver internal mass storage reset recovery is on-going; 0 - + application call USB_HostMsdMassStorageReset to reset or there is no reset*/ +} usb_host_msd_instance_t; + +/*! @brief UFI standard sense data structure */ +typedef struct _usb_host_ufi_sense_data +{ + uint8_t errorCode; /*!< This field shall contain a value of 70h to indicate current errors*/ + uint8_t reserved1; /*!< Reserved field*/ + uint8_t senseKey; /*!< Provide a hierarchy of error or command result information*/ + uint8_t information[4]; /*!< This field is command-specific; it is typically used by some commands to return a + logical block address denoting where an error occurred*/ + uint8_t additionalSenseLength; /*!< The UFI device sets the value of this field to ten, to indicate that ten more + bytes of sense data follow this field*/ + uint8_t reserved2[4]; /*!< Reserved field*/ + uint8_t additionalSenseCode; /*!< Provide a hierarchy of error or command result information*/ + uint8_t additionalSenseCodeQualifier; /*!< Provide a hierarchy of error or command result information*/ + uint8_t reserved3[4]; /*!< Reserved field*/ +} usb_host_ufi_sense_data_t; + +/*! @brief UFI standard inquiry data structure */ +typedef struct _usb_host_ufi_inquiry_data +{ + uint8_t peripheralDeviceType; /*!< Identifies the device currently connected to the requested logical unit*/ + uint8_t removableMediaBit; /*!< This shall be set to one to indicate removable media*/ + uint8_t version; /*!< Version*/ + uint8_t responseDataFormat; /*!< A value of 01h shall be used for UFI device*/ + uint8_t additionalLength; /*!< Specify the length in bytes of the parameters*/ + uint8_t reserved1[3]; /*!< Reserved field*/ + uint8_t vendorInformation[8]; /*!< Contains 8 bytes of ASCII data identifying the vendor of the product*/ + uint8_t productIdentification[16]; /*!< Contains 16 bytes of ASCII data as defined by the vendor*/ + uint8_t productRevisionLevel[4]; /*!< Contains 4 bytes of ASCII data as defined by the vendor*/ +} usb_host_ufi_inquiry_data_t; + +/*! @brief UFI read capacity data structure */ +typedef struct _usb_host_ufi_read_capacity +{ + uint8_t lastLogicalBlockAddress[4]; /*!< The logical block number*/ + uint8_t blockLengthInBytes[4]; /*!< Block size*/ +} usb_host_ufi_read_capacity_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @name USB host MSD class APIs + * @{ + */ + +/*! + * @brief Initializes the MSD instance. + * + * This function allocates the resources for the MSD instance. + * + * @param[in] deviceHandle The device handle. + * @param[out] classHandle Return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +extern usb_status_t USB_HostMsdInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets the interface. + * + * This function binds the interface with the MSD instance. + * + * @param[in] classHandle The class handle. + * @param[in] interfaceHandle The interface handle. + * @param[in] alternateSetting The alternate setting value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + * @retval kStatus_USB_Success Callback return status, the command succeeded. + * @retval kStatus_USB_Busy Callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall Callback return status, the transfer is stalled by the device. + * @retval kStatus_USB_Error Callback return status, open pipe fail. See the USB_HostOpenPipe. + */ +extern usb_status_t USB_HostMsdSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Deinitializes the MSD instance. + * + * This function frees the resource for the MSD instance. + * + * @param[in] deviceHandle The device handle. + * @param[in] classHandle The class handle. + * + * @retval kStatus_USB_Success The device is de-initialized successfully. + */ +extern usb_status_t USB_HostMsdDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Mass storage reset. + * + * This function implements the mass storage reset request. + * + * @param[in] classHandle The class handle. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostMsdMassStorageReset(usb_host_class_handle classHandle, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Gets the maximum logical unit number. + * + * This function implements the get maximum LUN request. + * + * @param[in] classHandle The class handle. + * @param[out] logicalUnitNumber Return logical unit number value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy There is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSendSetup. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdGetMaxLun(usb_host_class_handle classHandle, + uint8_t *logicalUnitNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read (10). + * + * This function implements the UFI READ(10) command. This command requests that the UFI + * device transfer data to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Read block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRead10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read (12). + * + * This function implements the UFI READ(12) command and requests that the UFI + * device transfer data to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Read block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRead12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage write (10). + * + * This function implements the UFI WRITE(10) command and requests that the UFI device + * write the data transferred by the host to the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Write block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdWrite10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage write (12). + * + * This function implements the UFI WRITE(12) command and requests that the UFI device + * write the data transferred by the host to the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Write block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdWrite12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read capacity. + * + * This function implements the UFI READ CAPACITY command and allows the host to request + * capacities of the currently installed medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdReadCapacity(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage test unit ready. + * + * This function implements the UFI TEST UNIT READY command and + * checks if the UFI device is ready. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdTestUnitReady(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief mass storage request sense. + * + * This function implements the UFI REQUEST SENSE command, this command instructs + * the UFI device to transfer sense data to the host for the specified logical unit. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRequestSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage mode select. + * + * This function implements the UFI MODE SELECT command and allows the host + * to specify medium or device parameters to the UFI device. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdModeSelect(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage mode sense. + * + * This function implements the UFI MODE SENSE command and allows the UFI + * device to report medium or device parameters to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] pageControl The page control field specifies the type of mode parameters to return. + * @param[in] pageCode Buffer pointer. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdModeSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t pageControl, + uint8_t pageCode, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage inquiry. + * + * This function implements the UFI INQUIRY command and requests that information regarding + * parameters of the UFI device itself be sent to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdInquiry(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read format capacities. + * + * This function implements the UFI READ FORMAT CAPACITIES command and allows the host to request + * a list of the possible capacities that can be formatted on the currently installed medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdReadFormatCapacities(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage format unit. + * + * This function implements the UFI FORMAT UNIT command and the host sends this command to physically format one + * track of a diskette according to the selected options. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] trackNumber This specifies which track is to be formatted. + * @param[in] interLeave This specifies the interleave that shall be used for formatting. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdFormatUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t trackNumber, + uint16_t interLeave, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage prevents/allows a medium removal. + * + * This function implements the UFI PREVENT-ALLOW MEDIUM REMOVAL command and notifies the FUI device + * to enable or disable the removal of the medium in the logical unit. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] prevent Prevent or allow + * - 0: enable (allow) the removal of the medium + * - 1: disable (prevent) removal of the medium + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdPreventAllowRemoval(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t prevent, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage write and verify. + * + * This function implements the UFI WRITE AND VERIFY command and requests that the UFI device + * writes the data transferred by the host to the medium, then verifies the data on the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Write and verify block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdWriteAndVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage start stop unit. + * + * This function implements the UFI START-STOP UNIT command and instructs the UFI device + * to enable or disable media access operations . + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] loadEject A Load Eject (LoEj) bit of zero requests that no eject action be performed. A LoEj bit of + * one, with the + * Start bit cleared to zero, which instructs the UFI device to eject the media. + * @param[in] start A Start bit of one instructs the UFI device to enable media access operations. A Start bit + * of zero instructs the UFI device to disable media access operations. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdStartStopUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t loadEject, + uint8_t start, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage verify. + * + * This function implements the UFI VERIFY command and requests that the UFI device + * verify the data on the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] verificationLength The data length that need to be verified. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint16_t verificationLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage rezero. + * + * This function implements the UFI REZERO UNIT command. This command positions the head of + * the drive to the cylinder 0. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRezeroUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage seek(10). + * + * This function implements the UFI SEEK(10) command and requests that the UFI device + * seek to the specified Logical Block Address. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdSeek10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage send diagnostic. + * + * This function implements the UFI SEND DIAGNOSTIC command. This command requests the UFI device + * to do a reset or perform a self-test. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] selfTest 0 = perform special diagnostic test; 1 = perform default self-test. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer. + * @retval kStatus_USB_Busy The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdSendDiagnostic(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t selfTest, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* _USB_HOST_MSD_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd_ufi.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd_ufi.c new file mode 100644 index 000000000..9c65b2fb3 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/class/usb_host_msd_ufi.c @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_MSD) && (USB_HOST_CONFIG_MSD)) +#include "usb_host.h" +#include "usb_host_msd.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* UFI command code */ +#define UFI_FORMAT_UNIT (0x04U) +#define UFI_INQUIRY (0x12U) +#define UFI_START_STOP (0x1BU) +#define UFI_MODE_SELECT (0x55U) +#define UFI_MODE_SENSE (0x5AU) +#define UFI_MEDIUM_REMOVAL (0x1EU) +#define UFI_READ10 (0x28U) +#define UFI_READ12 (0xA8U) +#define UFI_READ_CAPACITY (0x25U) +#define UFI_READ_FORMAT_CAPACITY (0x23U) +#define UFI_REQUEST_SENSE (0x03U) +#define UFI_REZERO_UINT (0x01U) +#define UFI_SEEK (0x2BU) +#define UFI_SEND_DIAGNOSTIC (0x1DU) +#define UFI_TEST_UNIT_READY (0x00U) +#define UFI_VERIFY (0x2FU) +#define UFI_WRITE10 (0x2AU) +#define UFI_WRITE12 (0xAAU) +#define UFI_WRITE_VERIFY (0x2EU) + +#define GET_BYTE_FROM_LE_LONG(b, n) \ + ((uint8_t)((USB_LONG_TO_LITTLE_ENDIAN(b)) >> (n * 8))) /* get the byte from the long value */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +extern usb_status_t USB_HostMsdCommand(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t direction, + uint8_t byteValues[10]); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +usb_status_t USB_HostMsdRead10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ10, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdRead12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ12, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + GET_BYTE_FROM_LE_LONG(blockNumber, 3), + GET_BYTE_FROM_LE_LONG(blockNumber, 2), + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0)}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdWrite10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_WRITE10, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdWrite12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_WRITE12, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + GET_BYTE_FROM_LE_LONG(blockNumber, 3), + GET_BYTE_FROM_LE_LONG(blockNumber, 2), + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0)}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdReadCapacity(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ_CAPACITY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdTestUnitReady(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_TEST_UNIT_READY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdRequestSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_REQUEST_SENSE, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + (uint8_t)bufferLength, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdModeSelect(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_MODE_SELECT, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdModeSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t pageControl, + uint8_t pageCode, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_MODE_SENSE, (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + (uint8_t)(((uint32_t)pageCode << USB_HOST_UFI_MODE_SENSE_PAGE_CONTROL_SHIFT) | + ((uint32_t)pageCode << USB_HOST_UFI_MODE_SENSE_PAGE_CODE_SHIFT)), + 0x00, 0x00, 0x00, 0x00, GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdInquiry(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_INQUIRY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + (uint8_t)bufferLength, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdReadFormatCapacities(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ_FORMAT_CAPACITY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdFormatUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t trackNumber, + uint16_t interLeave, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_FORMAT_UNIT, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + trackNumber, + GET_BYTE_FROM_LE_LONG(interLeave, 1), + GET_BYTE_FROM_LE_LONG(interLeave, 0), + 0x00, + 0x00, + GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdPreventAllowRemoval(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t prevent, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_MEDIUM_REMOVAL, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + prevent, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdWriteAndVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_WRITE_VERIFY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdStartStopUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t loadEject, + uint8_t start, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_START_STOP, (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), 0x00, 0x00, + (uint8_t)(((uint32_t)loadEject << USB_HOST_UFI_START_STOP_UNIT_LOEJ_SHIFT) | + ((uint32_t)start << USB_HOST_UFI_START_STOP_UNIT_START_SHIFT)), + 0x00, 0x00, 0x00, 0x00, 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint16_t verificationLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_VERIFY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(verificationLength, 1), + GET_BYTE_FROM_LE_LONG(verificationLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdRezeroUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_REZERO_UINT, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdSeek10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_SEEK, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdSendDiagnostic(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t selfTest, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_REZERO_UINT, + (uint8_t)(((uint32_t)logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION) | + ((uint32_t)selfTest << USB_HOST_UFI_SEND_DIAGNOSTIC_SELF_TEST_SHIFT)), + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +#endif /* USB_HOST_CONFIG_MSD */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host.h new file mode 100644 index 000000000..d5cb2d471 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host.h @@ -0,0 +1,705 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _USB_HOST_H_ +#define _USB_HOST_H_ + +#include "usb.h" +#include "usb_misc.h" +#include "usb_spec.h" +#include "usb_host_framework.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +struct _usb_host_transfer; /* for cross reference */ + +/*! + * @addtogroup usb_host_drv + * @{ + */ + +/*! @brief USB host class handle type define */ +typedef void *usb_host_class_handle; + +/*! @brief USB host controller handle type define */ +typedef void *usb_host_controller_handle; + +/*! @brief USB host configuration handle type define */ +typedef void *usb_host_configuration_handle; + +/*! @brief USB host interface handle type define */ +typedef void *usb_host_interface_handle; + +/*! @brief USB host pipe handle type define */ +typedef void *usb_host_pipe_handle; + +/*! @brief Event codes for device attach/detach */ +typedef enum _usb_host_event +{ + kUSB_HostEventAttach = 1U, /*!< Device is attached */ + kUSB_HostEventDetach, /*!< Device is detached */ + kUSB_HostEventEnumerationDone, /*!< Device's enumeration is done and the device is supported */ + kUSB_HostEventNotSupported, /*!< Device's enumeration is done and the device is not supported */ +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + kUSB_HostEventNotSuspended, /*!< Suspend failed */ + kUSB_HostEventSuspended, /*!< Suspend successful */ + kUSB_HostEventNotResumed, /*!< Resume failed */ + kUSB_HostEventDetectResume, /*!< Detect resume signal */ + kUSB_HostEventResumed, /*!< Resume successful */ + kUSB_HostEventL1Sleeped, /*!< L1 Sleep successful,state transition was successful (ACK) */ + kUSB_HostEventL1SleepNYET, /*!< Device was unable to enter the L1 state at this time (NYET) */ + kUSB_HostEventL1SleepNotSupport, /*!< Device does not support the L1 state (STALL) */ + kUSB_HostEventL1SleepError, /*!< Device failed to respond or an error occurred */ + kUSB_HostEventL1NotResumed, /*!< Resume failed */ + kUSB_HostEventL1DetectResume, /*!< Detect resume signal */ + kUSB_HostEventL1Resumed, /*!< Resume successful */ +#endif +} usb_host_event_t; + +/*! @brief USB host device information code */ +typedef enum _usb_host_dev_info +{ + kUSB_HostGetDeviceAddress = 1U, /*!< Device's address */ + kUSB_HostGetDeviceHubNumber, /*!< Device's first hub address */ + kUSB_HostGetDevicePortNumber, /*!< Device's first hub port number */ + kUSB_HostGetDeviceSpeed, /*!< Device's speed */ + kUSB_HostGetDeviceHSHubNumber, /*!< Device's first high-speed hub address */ + kUSB_HostGetDeviceHSHubPort, /*!< Device's first high-speed hub number */ + kUSB_HostGetDeviceLevel, /*!< Device's hub level */ + kUSB_HostGetHostHandle, /*!< Device's host handle */ + kUSB_HostGetDeviceControlPipe, /*!< Device's control pipe handle */ + kUSB_HostGetDevicePID, /*!< Device's PID */ + kUSB_HostGetDeviceVID, /*!< Device's VID */ + kUSB_HostGetHubThinkTime, /*!< Device's hub total think time */ + kUSB_HostGetDeviceConfigIndex, /*!< Device's running zero-based config index */ + kUSB_HostGetConfigurationDes, /*!< Device's configuration descriptor pointer */ + kUSB_HostGetConfigurationLength, /*!< Device's configuration descriptor pointer */ +} usb_host_dev_info_t; + +/*! + * @brief Host callback function typedef. + * + * This callback function is used to notify application device attach/detach event. + * This callback pointer is passed when initializing the host. + * + * @param deviceHandle The device handle, which indicates the attached device. + * @param configurationHandle The configuration handle contains the attached device's configuration information. + * @param event_code The callback event code; See the enumeration host_event_t. + * + * @return A USB error code or kStatus_USB_Success. + * @retval kStatus_USB_Success Application handles the attached device successfully. + * @retval kStatus_USB_NotSupported Application don't support the attached device. + * @retval kStatus_USB_Error Application handles the attached device falsely. + */ +typedef usb_status_t (*host_callback_t)(usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode); + +/*! + * @brief Transfer callback function typedef. + * + * This callback function is used to notify the upper layer the result of the transfer. + * This callback pointer is passed when calling the send/receive APIs. + * + * @param param The parameter pointer, which is passed when calling the send/receive APIs. + * @param data The data buffer pointer. + * @param data_len The result data length. + * @param status A USB error code or kStatus_USB_Success. + */ +typedef void (*transfer_callback_t)(void *param, uint8_t *data, uint32_t dataLen, usb_status_t status); + +/*! + * @brief Host stack inner transfer callback function typedef. + * + * This callback function is used to notify the upper layer the result of a transfer. + * This callback pointer is passed when initializing the structure usb_host_transfer_t. + * + * @param param The parameter pointer, which is passed when calling the send/receive APIs. + * @param transfer The transfer information; See the structure usb_host_transfer_t. + * @param status A USB error code or kStatus_USB_Success. + */ +typedef void (*host_inner_transfer_callback_t)(void *param, struct _usb_host_transfer *transfer, usb_status_t status); + +/*! @brief USB host endpoint information structure */ +typedef struct _usb_host_ep +{ + usb_descriptor_endpoint_t *epDesc; /*!< Endpoint descriptor pointer*/ + uint8_t *epExtension; /*!< Endpoint extended descriptor pointer*/ + uint16_t epExtensionLength; /*!< Extended descriptor length*/ +} usb_host_ep_t; + +/*! @brief USB host interface information structure */ +typedef struct _usb_host_interface +{ + usb_host_ep_t epList[USB_HOST_CONFIG_INTERFACE_MAX_EP]; /*!< Endpoint array*/ + usb_descriptor_interface_t *interfaceDesc; /*!< Interface descriptor pointer*/ + uint8_t *interfaceExtension; /*!< Interface extended descriptor pointer*/ + uint16_t interfaceExtensionLength; /*!< Extended descriptor length*/ + uint8_t interfaceIndex; /*!< The interface index*/ + uint8_t alternateSettingNumber; /*!< The interface alternate setting value*/ + uint8_t epCount; /*!< Interface's endpoint number*/ +} usb_host_interface_t; + +/*! @brief USB host configuration information structure */ +typedef struct _usb_host_configuration +{ + usb_host_interface_t interfaceList[USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE]; /*!< Interface array*/ + usb_descriptor_configuration_t *configurationDesc; /*!< Configuration descriptor pointer*/ + uint8_t *configurationExtension; /*!< Configuration extended descriptor pointer*/ + uint16_t configurationExtensionLength; /*!< Extended descriptor length*/ + uint8_t interfaceCount; /*!< The configuration's interface number*/ +} usb_host_configuration_t; + +/*! @brief USB host pipe common structure */ +typedef struct _usb_host_pipe +{ + struct _usb_host_pipe *next; /*!< Link the idle pipes*/ + usb_device_handle deviceHandle; /*!< This pipe's device's handle*/ + uint16_t currentCount; /*!< For KHCI transfer*/ + uint16_t nakCount; /*!< Maximum NAK count*/ + uint16_t maxPacketSize; /*!< Maximum packet size*/ + uint16_t interval; /*!< FS/LS: frame unit; HS: micro-frame unit*/ + uint8_t open; /*!< 0 - closed, 1 - open*/ + uint8_t nextdata01; /*!< Data toggle*/ + uint8_t endpointAddress; /*!< Endpoint address*/ + uint8_t direction; /*!< Pipe direction*/ + uint8_t pipeType; /*!< Pipe type, for example USB_ENDPOINT_BULK*/ + uint8_t numberPerUframe; /*!< Transaction number per micro-frame*/ +} usb_host_pipe_t; + +/*! @brief USB host transfer structure */ +typedef struct _usb_host_transfer +{ + struct _usb_host_transfer *next; /*!< The next transfer structure*/ + uint8_t *transferBuffer; /*!< Transfer data buffer*/ + uint32_t transferLength; /*!< Transfer data length*/ + uint32_t transferSofar; /*!< Length transferred so far*/ + host_inner_transfer_callback_t callbackFn; /*!< Transfer callback function*/ + void *callbackParam; /*!< Transfer callback parameter*/ + usb_host_pipe_t *transferPipe; /*!< Transfer pipe pointer*/ + usb_setup_struct_t *setupPacket; /*!< Set up packet buffer*/ + uint8_t direction; /*!< Transfer direction; it's values are USB_OUT or USB_IN*/ + uint8_t setupStatus; /*!< Set up the transfer status*/ + union + { + uint32_t unitHead; /*!< xTD head for this transfer*/ + int32_t transferResult; /*!< KHCI transfer result */ + } union1; + + union + { + uint32_t unitTail; /*! 0U)) +/*! + * @brief Send a bus or device suspend request. + * + * This function is used to send a bus or device suspend request. + * + * @param[in] hostHandle The host handle. + * @param[in] deviceHandle The device handle. + * + * @retval kStatus_USB_Success Request successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Error There is no idle transfer. + * Or, the deviceHandle is invalid. + * Or, the request is invalid. + */ +extern usb_status_t USB_HostSuspendDeviceResquest(usb_host_handle hostHandle, usb_device_handle deviceHandle); + +/*! + * @brief Send a bus or device resume request. + * + * This function is used to send a bus or device resume request. + * + * @param[in] hostHandle The host handle. + * @param[in] deviceHandle The device handle. + * + * @retval kStatus_USB_Success Request successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Error There is no idle transfer. + * Or, the deviceHandle is invalid. + * Or, the request is invalid. + */ +extern usb_status_t USB_HostResumeDeviceResquest(usb_host_handle hostHandle, usb_device_handle deviceHandle); +#if ((defined(USB_HOST_CONFIG_LPM_L1)) && (USB_HOST_CONFIG_LPM_L1 > 0U)) +/*! + * @brief Send a bus or device suspend request. + * + * This function is used to send a bus or device suspend request. + * + * @param[in] hostHandle The host handle. + * @param[in] deviceHandle The device handle. + *@param[in] sleeptype Bus suspend or single device suspend. + * + * @retval kStatus_USB_Success Request successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Error There is no idle transfer. + * Or, the deviceHandle is invalid. + * Or, the request is invalid. + */ +extern usb_status_t USB_HostL1SleepDeviceResquest(usb_host_handle hostHandle, + usb_device_handle deviceHandle, + uint8_t sleeptype); + +/*! + * @brief Send a bus or device resume request. + * + * This function is used to send a bus or device resume request. + * + * @param[in] hostHandle The host handle. + * @param[in] deviceHandle The device handle. + * *@param[in] sleeptype Bus suspend or single device suspend. + * + * @retval kStatus_USB_Success Request successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Error There is no idle transfer. + * Or, the deviceHandle is invalid. + * Or, the request is invalid. + */ +extern usb_status_t USB_HostL1ResumeDeviceResquest(usb_host_handle hostHandle, + usb_device_handle deviceHandle, + uint8_t sleepType); +/*! + * @brief Update the lpm param. + * + * The function is used to configure the lpm token. + * + * @param[in] hostHandle The host handle. + * @param[in] lpmParam HIRD value and whether enable remotewakeup. + * + */ +extern usb_status_t USB_HostL1SleepDeviceResquestConfig(usb_host_handle hostHandle, uint8_t *lpmParam); +#endif +/*! + * @brief Update the hardware tick. + * + * The function is used to update the hardware tick. + * + * @param[in] hostHandle The host handle. + * @param[in] tick Current hardware tick(uint is ms). + * + */ +extern usb_status_t USB_HostUpdateHwTick(usb_host_handle hostHandle, uint64_t tick); + +#endif + +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* _USB_HOST_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_devices.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_devices.c new file mode 100644 index 000000000..b994c7cec --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_devices.c @@ -0,0 +1,1393 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_host_config.h" +#include "usb_host.h" +#include "usb_host_hci.h" +#include "usb_host_devices.h" + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) +#include "usb_host_hub.h" +#endif /* USB_HOST_CONFIG_HUB */ +#define HOST_ECHO +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief enumeration transfer callback function. + * + * @param param callback parameter. + * @param transfer the transfer. + * @param status transfer result status. + */ +static void USB_HostEnumerationTransferCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief process the new step state. + * + * @param deviceInstance device instance pointer. + * + * @return kStatus_USB_Success or error codes + */ +static usb_status_t USB_HostProcessState(usb_host_device_instance_t *deviceInstance); + +/*! + * @brief process the previous step transfer result. + * + * @param deviceInstance device instance pointer. + * + * @return kStatus_USB_Success or error codes + */ +static usb_status_t USB_HostProcessCallback(usb_host_device_instance_t *deviceInstance); + +/*! + * @brief notify the application event, the callback is registered when initializing host. + * + * @param deviceInstance device instance pointer. + * @param eventCode event code. + * + * @return kStatus_USB_Success or error codes + */ +static usb_status_t USB_HostNotifyDevice(usb_host_device_instance_t *deviceInstance, uint32_t eventCode); + +/*! + * @brief allocate one address. + * + * @param hostInstance host instance pointer. + * + * @return address, 0 is invalid. + */ +static uint8_t USB_HostAllocateDeviceAddress(usb_host_instance_t *hostInstance); + +/*! + * @brief release one address. + * + * @param hostInstance host instance pointer. + * @param address releasing address. + */ +static void USB_HostReleaseDeviceAddress(usb_host_instance_t *hostInstance, uint8_t address); + +/*! + * @brief release device resource. + * + * @param hostInstance host instance pointer. + * @param deviceInstance device instance pointer. + */ +static void USB_HostReleaseDeviceResource(usb_host_instance_t *hostInstance, + usb_host_device_instance_t *deviceInstance); + +/*! + * @brief parse device configuration descriptor. + * + * @param deviceHandle device handle. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostParseDeviceConfigurationDescriptor(usb_device_handle deviceHandle); + +/*! + * @brief remove device instance from host device list. + * + * @param hostHandle host instance handle. + * @param deviceHandle device handle. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostRemoveDeviceInstance(usb_host_handle hostHandle, usb_device_handle deviceHandle); + +/*! + * @brief control the bus. + * + * This function control the host bus. + * + * @param[in] hostHandle the host handle. + * @param[in] controlType the control code, please reference to bus_event_t. + * + * @retval kStatus_USB_Success control successfully. + * @retval kStatus_USB_InvalidHandle The hostHandle is a NULL pointer. + */ +static usb_status_t USB_HostControlBus(usb_host_handle hostHandle, uint8_t controlType); + +extern usb_status_t USB_HostStandardSetGetDescriptor(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); +extern usb_status_t USB_HostStandardSetAddress(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); +extern usb_status_t USB_HostCh9RequestCommon(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + uint8_t *buffer, + uint32_t bufferLen); + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +extern usb_status_t USB_HostHubDeviceEvent(usb_host_handle hostHandle, + usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode); + +extern uint32_t USB_HostHubGetHsHubNumber(usb_host_handle hostHandle, uint8_t parentHubNo); + +extern uint32_t USB_HostHubGetHsHubPort(usb_host_handle hostHandle, uint8_t parentHubNo, uint8_t parentPortNo); + +extern usb_status_t USB_HostHubRemovePort(usb_host_handle hostHandle, uint8_t hubNumber, uint8_t portNumber); + +#endif + +/******************************************************************************* + * Variables + ******************************************************************************/ + +extern usb_host_instance_t g_UsbHostInstance[USB_HOST_CONFIG_MAX_HOST]; + +/*! @brief enumeration step process array */ +static const usb_host_enum_process_entry_t s_EnumEntries[] = \ +{ + /* kStatus_dev_initial */ + { + 0, 0, NULL, + }, + /* kStatus_DEV_GetDes8 */ + { + kStatus_DEV_SetAddress, kStatus_DEV_GetDes8, USB_HostProcessCallback, + }, + /* kStatus_DEV_SetAddress */ + { + kStatus_DEV_GetDes, kStatus_DEV_SetAddress, USB_HostProcessCallback, + }, + /* kStatus_DEV_GetDes */ + { + kStatus_DEV_GetCfg9, kStatus_DEV_GetDes, NULL, + }, + /* kStatus_DEV_GetCfg9 */ + { + kStatus_DEV_GetCfg, kStatus_DEV_GetCfg9, USB_HostProcessCallback, + }, + /* kStatus_DEV_GetCfg */ + { + kStatus_DEV_SetCfg, kStatus_DEV_GetCfg9, USB_HostProcessCallback, + }, + /* kStatus_DEV_SetCfg */ + { + kStatus_DEV_EnumDone, kStatus_DEV_SetCfg, NULL, + }, +}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostEnumerationTransferCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + uint8_t nextStep = 0; + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)param; + + USB_HostFreeTransfer(deviceInstance->hostHandle, transfer); /* free transfer */ + + if (status == kStatus_USB_Success) + { + nextStep = 1; + } + else if (status == kStatus_USB_TransferStall) + { +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) + usb_echo("no response from device\r\n"); +#endif /* USB_HOST_CONFIG_COMPLIANCE_TEST */ + if (deviceInstance->stallRetries > 0) /* retry same transfer when stall */ + { + deviceInstance->stallRetries--; + } + else /* process next state when all retries stall */ + { + nextStep = 1; + } + } + else if (status == kStatus_USB_TransferCancel) + { + return; + } + else + { + if (deviceInstance->enumRetries > 0) /* next whole retry */ + { + deviceInstance->enumRetries--; + deviceInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES; + deviceInstance->configurationValue = 0; + deviceInstance->state = kStatus_DEV_GetDes8; + } + else + { +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) + usb_echo("Device No Response\r\n"); +#endif + return; + } + } + + if (nextStep == 1) + { + deviceInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES; + if (s_EnumEntries[deviceInstance->state - 1].process == NULL) + { + deviceInstance->state = s_EnumEntries[deviceInstance->state - 1].successState; /* next state */ + } + else + { + status = s_EnumEntries[deviceInstance->state - 1].process( + deviceInstance); /* process the previous state result */ + if (status == kStatus_USB_Success) /* process success */ + { + deviceInstance->state = s_EnumEntries[deviceInstance->state - 1].successState; + } + else if (status == kStatus_USB_Retry) /* need retry */ + { + deviceInstance->state = s_EnumEntries[deviceInstance->state - 1].retryState; + } + else if (status == kStatus_USB_NotSupported) /* device don't suport by the application */ + { + return; /* unrecoverable fail */ + } + else /* process error, next retry */ + { + if (deviceInstance->enumRetries > 0) /* next whole retry */ + { + deviceInstance->enumRetries--; + deviceInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES; + deviceInstance->configurationValue = 0; + deviceInstance->state = kStatus_DEV_GetDes8; + } + else + { +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) + usb_echo("Device No Response\r\n"); +#endif + return; /* unrecoverable fail */ + } + } + } + } + if (USB_HostProcessState(deviceInstance) != kStatus_USB_Success) /* process the new state */ + { +#ifdef HOST_ECHO + usb_echo("enumation setup error\r\n"); +#endif + return; + } +} + +static usb_status_t USB_HostProcessState(usb_host_device_instance_t *deviceInstance) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_process_descriptor_param_t getDescriptorParam; + usb_host_transfer_t *transfer; + + /* malloc transfer */ + if (deviceInstance->state != kStatus_DEV_EnumDone) + { + if (USB_HostMallocTransfer(deviceInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + transfer->callbackFn = USB_HostEnumerationTransferCallback; + transfer->callbackParam = deviceInstance; + + /* reset transfer fields */ + transfer->setupPacket->bmRequestType = 0x00; + transfer->setupPacket->wIndex = 0; + transfer->setupPacket->wLength = 0; + transfer->setupPacket->wValue = 0; + } + + switch (deviceInstance->state) + { + case kStatus_DEV_GetDes8: + case kStatus_DEV_GetDes: /* get descriptor state */ + getDescriptorParam.descriptorLength = sizeof(usb_descriptor_device_t); + if (deviceInstance->state == kStatus_DEV_GetDes8) + { + getDescriptorParam.descriptorLength = 8; + } + getDescriptorParam.descriptorBuffer = (uint8_t *)deviceInstance->deviceDescriptor; + getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_DEVICE; + getDescriptorParam.descriptorIndex = 0; + getDescriptorParam.languageId = 0; + + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR; + status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam); + break; + case kStatus_DEV_SetAddress: /* set address state */ + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_SET_ADDRESS; + status = USB_HostStandardSetAddress(deviceInstance, transfer, &deviceInstance->allocatedAddress); + break; + + case kStatus_DEV_GetCfg9: /* get 9 bytes configuration state */ + getDescriptorParam.descriptorBuffer = deviceInstance->enumBuffer; + getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_CONFIGURE; + getDescriptorParam.descriptorIndex = deviceInstance->configurationValue; + getDescriptorParam.descriptorLength = 9; + getDescriptorParam.languageId = 0; + + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR; + status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam); + break; + + case kStatus_DEV_GetCfg: /* get configuration state */ + getDescriptorParam.descriptorBuffer = deviceInstance->configurationDesc; + getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_CONFIGURE; + getDescriptorParam.descriptorIndex = deviceInstance->configurationValue; + getDescriptorParam.descriptorLength = deviceInstance->configurationLen; + getDescriptorParam.languageId = 0; + + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR; + status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam); + break; + + case kStatus_DEV_SetCfg: /* set configuration state */ + transfer->setupPacket->wValue = + USB_SHORT_TO_LITTLE_ENDIAN(deviceInstance->configuration.configurationDesc->bConfigurationValue); + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_SET_CONFIGURATION; + status = USB_HostCh9RequestCommon(deviceInstance, transfer, NULL, 0); + break; + + case kStatus_DEV_EnumDone: /* enumeration done state */ + status = USB_HostNotifyDevice(deviceInstance, + kUSB_HostEventEnumerationDone); /* notify device enumeration done */ + if (status == kStatus_USB_Success) + { + deviceInstance->state = kStatus_DEV_AppUsed; + } + break; + + default: + break; + } + + return status; +} + +static usb_status_t USB_HostProcessCallback(usb_host_device_instance_t *deviceInstance) +{ + usb_host_pipe_t *pipe = (usb_host_pipe_t *)deviceInstance->controlPipe; + usb_status_t status = kStatus_USB_Success; + usb_descriptor_configuration_t *configureDesc; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; + + switch (deviceInstance->state) + { + case kStatus_DEV_GetDes8: /* process get 8 bytes descriptor result */ + pipe->maxPacketSize = deviceInstance->deviceDescriptor->bMaxPacketSize0; + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + hostInstance->controllerTable->controllerIoctl( + hostInstance->controllerHandle, kUSB_HostUpdateControlPacketSize, deviceInstance->controlPipe); + break; + + case kStatus_DEV_SetAddress: /* process set address result */ + deviceInstance->setAddress = deviceInstance->allocatedAddress; + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + hostInstance->controllerTable->controllerIoctl( + hostInstance->controllerHandle, kUSB_HostUpdateControlEndpointAddress, deviceInstance->controlPipe); + break; + + case kStatus_DEV_GetDes: /* process set address result */ + /* NULL */ + break; + + case kStatus_DEV_GetCfg9: /* process get 9 bytes configuration result */ + configureDesc = (usb_descriptor_configuration_t *)&deviceInstance->enumBuffer[0]; + + deviceInstance->configurationLen = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(configureDesc->wTotalLength); + if (deviceInstance->configurationDesc != NULL) + { +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(deviceInstance->configurationDesc); +#else + USB_OsaMemoryFree(deviceInstance->configurationDesc); +#endif + deviceInstance->configurationDesc = NULL; + } + + /* for KHCI, the start address and the length should be 4 byte align */ + if ((deviceInstance->configurationLen & 0x03) != 0) + { +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + deviceInstance->configurationDesc = + (uint8_t *)SDK_Malloc((deviceInstance->configurationLen & 0xFFFCu) + 4, USB_CACHE_LINESIZE); +#else + deviceInstance->configurationDesc = + (uint8_t *)USB_OsaMemoryAllocate((deviceInstance->configurationLen & 0xFFFCu) + 4); +#endif + } + else + { +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + deviceInstance->configurationDesc = + (uint8_t *)SDK_Malloc(deviceInstance->configurationLen, USB_CACHE_LINESIZE); +#else + deviceInstance->configurationDesc = (uint8_t *)USB_OsaMemoryAllocate(deviceInstance->configurationLen); +#endif + } + + if (deviceInstance->configurationDesc == NULL) + { + return kStatus_USB_Error; + } + break; + + case kStatus_DEV_GetCfg: /* process get configuration result */ + if (((usb_descriptor_configuration_t *)deviceInstance->configurationDesc)->bMaxPower > + USB_HOST_CONFIG_MAX_POWER) + { + return kStatus_USB_Error; + } + deviceInstance->configurationValue++; + if (USB_HostParseDeviceConfigurationDescriptor(deviceInstance) != + kStatus_USB_Success) /* parse configuration descriptor */ + { + return kStatus_USB_Error; + } + + status = USB_HostNotifyDevice(deviceInstance, kUSB_HostEventAttach); + + if (status != kStatus_USB_Success) + { + /* next configuration */ + if (deviceInstance->configurationValue < deviceInstance->deviceDescriptor->bNumConfigurations) + { + return kStatus_USB_Retry; + } + else + { + USB_HostNotifyDevice(deviceInstance, + kUSB_HostEventNotSupported); /* notify application device is not supported */ + return kStatus_USB_NotSupported; + } + } + break; + + case kStatus_DEV_SetCfg: + /* NULL */ + break; + + default: + break; + } + + return status; +} + +static usb_status_t USB_HostNotifyDevice(usb_host_device_instance_t *deviceInstance, uint32_t eventCode) +{ + usb_host_instance_t *hostInstance; + usb_status_t status1 = kStatus_USB_Error; +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + usb_status_t status2 = kStatus_USB_Error; + uint8_t haveHub; + uint8_t haveNoHub; + uint8_t interfaceIndex; +#endif /* USB_HOST_CONFIG_HUB */ + + if (deviceInstance == NULL) + { + return kStatus_USB_InvalidHandle; + } + hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + haveHub = 0; + haveNoHub = 0; + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (((usb_descriptor_interface_t *)deviceInstance->configuration.interfaceList[interfaceIndex].interfaceDesc) + ->bInterfaceClass == USB_HOST_HUB_CLASS_CODE) + { + haveHub = 1; + } + else + { + haveNoHub = 1; + } + } + + if ((haveNoHub == 1) && (hostInstance->deviceCallback != NULL)) + { + /* call host callback function, function is initialized in USB_HostInit */ + status1 = hostInstance->deviceCallback(deviceInstance, &deviceInstance->configuration, eventCode); + } + if (haveHub) + { + status2 = USB_HostHubDeviceEvent(hostInstance, deviceInstance, &deviceInstance->configuration, + eventCode); /* notify hub event */ + } + if ((status1 == kStatus_USB_Success) || (status2 == kStatus_USB_Success)) /* the device is supported */ + { + return kStatus_USB_Success; + } + else if (eventCode == kUSB_HostEventAttach) /* attach event */ + { + status1 = kStatus_USB_NotSupported; + } + else + { + status1 = kStatus_USB_Error; + } +#else + if (hostInstance->deviceCallback != NULL) + { + /* call host callback function, function is initialized in USB_HostInit */ + status1 = hostInstance->deviceCallback(deviceInstance, &deviceInstance->configuration, eventCode); + } +#endif + return status1; +} + +static uint8_t USB_HostAllocateDeviceAddress(usb_host_instance_t *hostInstance) +{ + uint8_t address = 0; + uint8_t addressIndex; + uint8_t addressBitIndex; + for (addressIndex = 0; addressIndex < 8; ++addressIndex) /* find the idle address position byte */ + { + if (hostInstance->addressBitMap[addressIndex] != 0xFF) + { + break; + } + } + if (addressIndex < 8) + { + for (addressBitIndex = 0; addressBitIndex < 8; ++addressBitIndex) /* find the idle address position bit */ + { + if (!(hostInstance->addressBitMap[addressIndex] & (0x01u << addressBitIndex))) + { + hostInstance->addressBitMap[addressIndex] |= (0x01u << addressBitIndex); /* set the allocated bit */ + address = addressIndex * 8 + addressBitIndex + 1; /* the address minimum is 1 */ + break; + } + } + } + return address; +} + +static void USB_HostReleaseDeviceAddress(usb_host_instance_t *hostInstance, uint8_t address) +{ + USB_HostLock(); + hostInstance->addressBitMap[(uint32_t)(address - 1) >> 3] &= + (~(0x01u << (((uint32_t)address - 1) & 0x07U))); /* reset the allocated bit */ + USB_HostUnlock(); +} + +static usb_status_t USB_HostRemoveDeviceInstance(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_device_instance_t *currentInstance; + usb_host_device_instance_t *prevInstance; + if ((hostHandle == NULL) || (deviceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* search and remove device instance */ + prevInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + if (prevInstance == deviceHandle) + { + hostInstance->deviceList = prevInstance->next; + return kStatus_USB_Success; + } + else + { + currentInstance = prevInstance->next; + } + + while (currentInstance != NULL) + { + if (currentInstance == deviceHandle) + { + prevInstance->next = currentInstance->next; + return kStatus_USB_Success; + } + prevInstance = currentInstance; + currentInstance = currentInstance->next; + } + + return kStatus_USB_Success; +} + +static void USB_HostReleaseDeviceResource(usb_host_instance_t *hostInstance, usb_host_device_instance_t *deviceInstance) +{ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + uint8_t level = 0; +#endif + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + if (deviceInstance == hostInstance->suspendedDevice) + { + hostInstance->suspendedDevice = NULL; + } +#endif + /* release device's address */ + if (deviceInstance->setAddress != 0) + { + USB_HostReleaseDeviceAddress(hostInstance, deviceInstance->setAddress); + } + else + { + if (deviceInstance->allocatedAddress != 0) + { + USB_HostReleaseDeviceAddress(hostInstance, deviceInstance->allocatedAddress); + } + } + + /* close control pipe */ + if (deviceInstance->controlPipe != NULL) + { + USB_HostCancelTransfer(hostInstance, deviceInstance->controlPipe, NULL); + if (USB_HostClosePipe(hostInstance, deviceInstance->controlPipe) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + deviceInstance->controlPipe = NULL; + } + + /* free configuration buffer */ + if (deviceInstance->configurationDesc != NULL) + { +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(deviceInstance->configurationDesc); +#else + USB_OsaMemoryFree(deviceInstance->configurationDesc); +#endif + } + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + level = deviceInstance->level; +#endif +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(deviceInstance->deviceDescriptor); +#else + USB_OsaMemoryFree(deviceInstance->deviceDescriptor); +#endif + /* free device instance buffer */ + USB_OsaMemoryFree(deviceInstance); + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + /* enable controller attach if root hub */ + if (level == 1) + { + USB_HostControlBus(hostInstance, kUSB_HostBusEnableAttach); + } +#else + /* enable controller attach */ + USB_HostControlBus(hostInstance, kUSB_HostBusEnableAttach); +#endif +} + +static usb_status_t USB_HostParseDeviceConfigurationDescriptor(usb_device_handle deviceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + uint32_t endPos; + usb_descriptor_union_t *unionDes; + usb_host_interface_t *interfaceParse = NULL; + usb_host_ep_t *epParse; + uint8_t *buffer; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + + buffer = (uint8_t *)&deviceInstance->configuration; + /* clear the previous parse result, note: end_pos means buffer index here*/ + for (endPos = 0; endPos < sizeof(usb_host_configuration_t); endPos++) + { + buffer[endPos] = 0; + } + for (endPos = 0; endPos < USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE; ++endPos) + { + deviceInstance->interfaceStatus[endPos] = 0; + } + + /* parse configuration descriptor */ + unionDes = (usb_descriptor_union_t *)deviceInstance->configurationDesc; + endPos = (uint32_t)(deviceInstance->configurationDesc + deviceInstance->configurationLen); + + if ((unionDes->common.bLength == USB_DESCRIPTOR_LENGTH_CONFIGURE) && + (unionDes->common.bDescriptorType == USB_DESCRIPTOR_TYPE_CONFIGURE)) + { + /* configuration descriptor */ + deviceInstance->configuration.configurationDesc = (usb_descriptor_configuration_t *)unionDes; + deviceInstance->configuration.configurationExtensionLength = 0; + deviceInstance->configuration.configurationExtension = NULL; + deviceInstance->configuration.interfaceCount = 0; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPos) + { + if (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE) + { + if (deviceInstance->configuration.configurationExtension == NULL) + { + deviceInstance->configuration.configurationExtension = (uint8_t *)unionDes; + } + if ((unionDes->common.bDescriptorType == 0x00) || + (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + deviceInstance->configuration.configurationExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + + /* interface descriptor */ + deviceInstance->configuration.interfaceCount = 0; + while ((uint32_t)unionDes < endPos) + { + if (unionDes->common.bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE) + { + if (unionDes->interface.bAlternateSetting == 0x00) + { + if (deviceInstance->configuration.interfaceCount >= USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE) + { +#if (((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) || defined(HOST_ECHO)) + usb_echo( + "Unsupported Device attached\r\n too many interfaces in one configuration, please increase " + "the USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE value\n"); +#endif + return kStatus_USB_Error; + } + interfaceParse = + &deviceInstance->configuration.interfaceList[deviceInstance->configuration.interfaceCount]; + deviceInstance->configuration.interfaceCount++; + interfaceParse->alternateSettingNumber = 0; + interfaceParse->epCount = 0; + interfaceParse->interfaceDesc = &unionDes->interface; + interfaceParse->interfaceExtensionLength = 0; + interfaceParse->interfaceExtension = NULL; + interfaceParse->interfaceIndex = unionDes->interface.bInterfaceNumber; + if (unionDes->common.bLength == 0x00) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPos) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) + { + if (interfaceParse->interfaceExtension == NULL) + { + interfaceParse->interfaceExtension = (uint8_t *)unionDes; + } + if ((unionDes->common.bDescriptorType == 0x00) || + (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + interfaceParse->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + + /* endpoint descriptor */ + if (interfaceParse->interfaceDesc->bNumEndpoints != 0) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) || + (interfaceParse->interfaceDesc->bNumEndpoints > USB_HOST_CONFIG_INTERFACE_MAX_EP)) + { +#ifdef HOST_ECHO + usb_echo("interface descriptor error\n"); +#endif + return kStatus_USB_Error; + } + for (; interfaceParse->epCount < interfaceParse->interfaceDesc->bNumEndpoints; + (interfaceParse->epCount)++) + { + if (((uint32_t)unionDes >= endPos) || + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) + { +#ifdef HOST_ECHO + usb_echo("endpoint descriptor error\n"); +#endif + return kStatus_USB_Error; + } + epParse = (usb_host_ep_t *)&interfaceParse->epList[interfaceParse->epCount]; + epParse->epDesc = (usb_descriptor_endpoint_t *)unionDes; + epParse->epExtensionLength = 0; + epParse->epExtension = NULL; + if (unionDes->common.bLength == 0x00) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPos) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE)) + { + if (epParse->epExtension == NULL) + { + epParse->epExtension = (uint8_t *)unionDes; + } + if ((unionDes->common.bDescriptorType == 0x00) || + (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + epParse->epExtensionLength += unionDes->common.bLength; + unionDes = + (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + } + } + } + else + { + if (interfaceParse == NULL) + { + return kStatus_USB_Error; /* in normal situation this cannot reach */ + } + interfaceParse->alternateSettingNumber++; + if (interfaceParse->interfaceExtension == NULL) + { + interfaceParse->interfaceExtension = (uint8_t *)unionDes; + } + if (unionDes->common.bLength == 0x00) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + interfaceParse->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPos) + { + if (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE) + { + if ((unionDes->common.bDescriptorType == 0x00) || + (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + interfaceParse->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + } + } + else + { + return kStatus_USB_Error; + } + } + } + + for (endPos = 0; endPos < deviceInstance->configuration.interfaceCount; ++endPos) + { + deviceInstance->interfaceStatus[endPos] = kStatus_interface_Attached; + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostAttachDevice(usb_host_handle hostHandle, + uint8_t speed, + uint8_t hubNumber, + uint8_t portNumber, + uint8_t level, + usb_device_handle *deviceHandle) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_device_instance_t *newInstance; +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + usb_host_device_instance_t *currentInstance; +#endif + uint8_t address; + usb_host_pipe_init_t pipeInit; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + +/* check whether is the device attached? */ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + currentInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + while (currentInstance != NULL) + { + if ((currentInstance->hubNumber == hubNumber) && (currentInstance->portNumber == portNumber)) + { + *deviceHandle = NULL; +#ifdef HOST_ECHO + usb_echo("device has attached\r\n"); +#endif + return kStatus_USB_Busy; + } + else + { + currentInstance = currentInstance->next; + } + } +#else + if (hostInstance->deviceList != NULL) + { + *deviceHandle = NULL; + usb_echo("device has attached\r\n"); + return kStatus_USB_Busy; + } +#endif + + /* Allocate new device instance */ + newInstance = (usb_host_device_instance_t *)USB_OsaMemoryAllocate(sizeof(usb_host_device_instance_t)); + if (newInstance == NULL) + { +#ifdef HOST_ECHO + usb_echo("allocate dev instance fail\r\n"); +#endif + return kStatus_USB_AllocFail; + } + + /* new instance fields init */ + newInstance->hostHandle = hostHandle; + newInstance->speed = speed; + newInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES; + newInstance->enumRetries = USB_HOST_CONFIG_ENUMERATION_MAX_RETRIES; + newInstance->setAddress = 0; + newInstance->deviceAttachState = kStatus_device_Attached; +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + newInstance->deviceDescriptor = + (usb_descriptor_device_t *)SDK_Malloc(sizeof(usb_descriptor_device_t) + 9, USB_CACHE_LINESIZE); +#else + newInstance->deviceDescriptor = + (usb_descriptor_device_t *)USB_OsaMemoryAllocate(sizeof(usb_descriptor_device_t) + 9); +#endif + if (newInstance->deviceDescriptor == NULL) + { +#ifdef HOST_ECHO + usb_echo("allocate newInstance->deviceDescriptor fail\r\n"); +#endif +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(newInstance->deviceDescriptor); +#else + USB_OsaMemoryFree(newInstance->deviceDescriptor); +#endif + USB_OsaMemoryFree(newInstance); + return kStatus_USB_AllocFail; + } + newInstance->enumBuffer = (uint8_t *)((uint8_t *)newInstance->deviceDescriptor + sizeof(usb_descriptor_device_t)); +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + newInstance->hubNumber = hubNumber; + newInstance->portNumber = portNumber; + newInstance->level = level; + + if ((speed != USB_SPEED_HIGH) && (level > 1)) + { + newInstance->hsHubNumber = USB_HostHubGetHsHubNumber(hostHandle, hubNumber); + newInstance->hsHubPort = USB_HostHubGetHsHubPort(hostHandle, hubNumber, portNumber); + } + else + { + newInstance->hsHubNumber = hubNumber; + newInstance->hsHubPort = portNumber; + } +#endif /* USB_HOST_CONFIG_HUB */ + + USB_HostLock(); + /* allocate address && insert to the dev list */ + address = USB_HostAllocateDeviceAddress(hostInstance); + if (address == 0) + { +#ifdef HOST_ECHO + usb_echo("allocate address fail\r\n"); +#endif + USB_HostUnlock(); +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(newInstance->deviceDescriptor); +#else + USB_OsaMemoryFree(newInstance->deviceDescriptor); +#endif + USB_OsaMemoryFree(newInstance); + return kStatus_USB_Error; + } + newInstance->allocatedAddress = address; + + newInstance->next = (usb_host_device_instance_t *)hostInstance->deviceList; + hostInstance->deviceList = newInstance; + newInstance->state = kStatus_DEV_Initial; + USB_HostUnlock(); + + /* open control pipe */ + pipeInit.devInstance = newInstance; + pipeInit.pipeType = USB_ENDPOINT_CONTROL; + pipeInit.direction = 0; + pipeInit.endpointAddress = 0; + pipeInit.interval = 0; + pipeInit.maxPacketSize = 8; + pipeInit.numberPerUframe = 0; + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + if (USB_HostOpenPipe(hostHandle, &newInstance->controlPipe, &pipeInit) != kStatus_USB_Success) + { + /* don't need release resource, resource is released when detach */ + *deviceHandle = newInstance; +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(newInstance->deviceDescriptor); +#else + USB_OsaMemoryFree(newInstance->deviceDescriptor); +#endif + USB_OsaMemoryFree(newInstance); + return kStatus_USB_Error; + } + + /* start enumeration */ + newInstance->state = kStatus_DEV_GetDes8; + USB_HostProcessState(newInstance); /* process enumeration state machine */ + + *deviceHandle = newInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostDetachDevice(usb_host_handle hostHandle, uint8_t hubNumber, uint8_t portNumber) +{ + usb_host_device_instance_t *deviceInstance; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + USB_HostLock(); +/* search for device instance handle */ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + while (deviceInstance != NULL) + { + if ((deviceInstance->hubNumber == hubNumber) && (deviceInstance->portNumber == portNumber)) + { + break; + } + deviceInstance = deviceInstance->next; + } +#else + deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; +#endif + USB_HostUnlock(); + if (deviceInstance != NULL) + { + return USB_HostDetachDeviceInternal(hostHandle, deviceInstance); /* device instance detach */ + } + return kStatus_USB_Success; +} + +usb_status_t USB_HostDetachDeviceInternal(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + if ((hostHandle == NULL) || (deviceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + deviceInstance->deviceAttachState = kStatus_device_Detached; /* mark the device is detached from host */ + + if (deviceInstance->state >= kStatus_DEV_Initial) /* device instance is valid */ + { + /* detach internally */ + if (deviceInstance->state < kStatus_DEV_AppUsed) /* enumeration is not done */ + { + if (deviceInstance->controlPipe != NULL) + { + USB_HostCancelTransfer(hostInstance, deviceInstance->controlPipe, NULL); + } + + /* remove device instance from host */ + USB_HostRemoveDeviceInstance(hostInstance, deviceInstance); + USB_HostReleaseDeviceResource(hostInstance, deviceInstance); + } + else /* enumeration has be done and notified application */ + { + USB_HostNotifyDevice(deviceInstance, kUSB_HostEventDetach); /* notify application device detach */ + } + } + + return kStatus_USB_Success; +} + +uint8_t USB_HostGetDeviceAttachState(usb_device_handle deviceHandle) +{ + return deviceHandle ? ((usb_host_device_instance_t *)deviceHandle)->deviceAttachState : 0x0; +} + +usb_status_t USB_HostValidateDevice(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_device_instance_t *searchDev; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + /* search for the device */ + searchDev = (usb_host_device_instance_t *)((usb_host_instance_t *)hostHandle)->deviceList; + while ((searchDev != NULL) && ((usb_device_handle)searchDev != deviceHandle)) + { + searchDev = searchDev->next; + } + + if (searchDev) + { + return kStatus_USB_Success; + } + return kStatus_USB_Error; +} + +static usb_status_t USB_HostControlBus(usb_host_handle hostHandle, uint8_t controlType) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, + &controlType); + + return status; +} + +usb_status_t USB_HostOpenDeviceInterface(usb_device_handle deviceHandle, usb_host_interface_handle interfaceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_instance_t *hostInstance = NULL; + uint8_t interfaceIndex; + uint8_t index = 0; + + if ((deviceHandle == NULL) || (interfaceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; + USB_HostLock(); + /* check host_instance valid? */ + for (; index < USB_HOST_CONFIG_MAX_HOST; ++index) + { + if ((g_UsbHostInstance[index].occupied == 1) && + ((usb_host_instance_t *)(&g_UsbHostInstance[index]) == (hostInstance))) + { + break; + } + } + if (index >= USB_HOST_CONFIG_MAX_HOST) + { + USB_HostUnlock(); + return kStatus_USB_Error; + } + + /* check deviceHandle valid? */ + if (USB_HostValidateDevice(hostInstance, deviceHandle) != kStatus_USB_Success) + { + USB_HostUnlock(); + return kStatus_USB_Error; + } + + /* search interface and set the interface as opened */ + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (&deviceInstance->configuration.interfaceList[interfaceIndex] == interfaceHandle) + { + deviceInstance->interfaceStatus[interfaceIndex] = kStatus_interface_Opened; + break; + } + } + USB_HostUnlock(); + + return kStatus_USB_Success; +} + +usb_status_t USB_HostCloseDeviceInterface(usb_device_handle deviceHandle, usb_host_interface_handle interfaceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_instance_t *hostInstance = NULL; + uint8_t interfaceIndex; + uint8_t removeLabel = 1; + uint8_t index = 0; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; + USB_HostLock(); + /* check host_instance valid? */ + for (; index < USB_HOST_CONFIG_MAX_HOST; ++index) + { + if ((g_UsbHostInstance[index].occupied == 1) && + ((usb_host_instance_t *)(&g_UsbHostInstance[index]) == (hostInstance))) + { + break; + } + } + if (index >= USB_HOST_CONFIG_MAX_HOST) + { + USB_HostUnlock(); + return kStatus_USB_Error; + } + + /* check deviceHandle valid? */ + if (USB_HostValidateDevice(hostInstance, deviceHandle) != kStatus_USB_Success) + { + USB_HostUnlock(); + return kStatus_USB_Error; + } + + if (interfaceHandle != NULL) + { + /* search interface and set the interface as detached */ + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (&deviceInstance->configuration.interfaceList[interfaceIndex] == interfaceHandle) + { + deviceInstance->interfaceStatus[interfaceIndex] = kStatus_interface_Detached; + break; + } + } + } + + if (deviceInstance->deviceAttachState == kStatus_device_Detached) /* device is removed from host */ + { + removeLabel = 1; + /* check all the interfaces of the device are not opened */ + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (deviceInstance->interfaceStatus[interfaceIndex] == kStatus_interface_Opened) + { + removeLabel = 0; + break; + } + } + if (removeLabel == 1) + { + /* remove device instance from host */ + USB_HostRemoveDeviceInstance(hostInstance, deviceInstance); + } + USB_HostUnlock(); + + if (removeLabel == 1) + { + USB_HostReleaseDeviceResource((usb_host_instance_t *)deviceInstance->hostHandle, + deviceInstance); /* release device resource */ + } + } + else + { + USB_HostUnlock(); + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostRemoveDevice(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + uint8_t interfaceIndex = 0; +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + uint8_t level = 0; + uint8_t devHubNo; + uint8_t devPortNo; +#endif + + if ((hostHandle == NULL) || (deviceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + if (deviceInstance->hostHandle != hostHandle) + { + return kStatus_USB_InvalidParameter; + } + + if (USB_HostValidateDevice(hostInstance, deviceInstance) == kStatus_USB_Success) /* device is valid */ + { +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + devHubNo = deviceInstance->hubNumber; + devPortNo = deviceInstance->portNumber; + level = deviceInstance->level; +#endif + + deviceInstance->deviceAttachState = kStatus_device_Detached; + if (deviceInstance->state >= kStatus_DEV_Initial) /* device is valid */ + { + if (deviceInstance->state < kStatus_DEV_AppUsed) /* enumeration is not done or application don't use */ + { + /* detach internally */ + USB_HostDetachDeviceInternal(hostHandle, deviceHandle); + } + else /* application use the device */ + { + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; + ++interfaceIndex) + { + if (deviceInstance->interfaceStatus[interfaceIndex] == kStatus_interface_Opened) + { +#ifdef HOST_ECHO + usb_echo("error: there is class instance that is not deinited\r\n"); +#endif + break; + } + } + /* remove device instance from host */ + USB_HostRemoveDeviceInstance(hostInstance, deviceInstance); + USB_HostReleaseDeviceResource(hostInstance, deviceInstance); /* release resource */ + } + } + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + if (level == 1) + { + USB_HostControlBus(hostHandle, kUSB_HostBusReset); /* reset controller port */ + USB_HostControlBus(hostHandle, kUSB_HostBusRestart); /* restart controller port */ + } + else + { + USB_HostHubRemovePort(hostHandle, devHubNo, devPortNo); /* reset hub port */ + } +#else + USB_HostControlBus(hostHandle, kUSB_HostBusReset); /* reset controller port */ + USB_HostControlBus(hostHandle, kUSB_HostBusRestart); /* restart controller port */ +#endif /* USB_HOST_CONFIG_HUB */ + } + + return kStatus_USB_Success; +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_devices.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_devices.h new file mode 100644 index 000000000..9d06ba26e --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_devices.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _USB_HOST_DEV_MNG_H_ +#define _USB_HOST_DEV_MNG_H_ + +#include "usb_host.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! + * @addtogroup usb_host_drv + * @{ + */ +/*! @brief States of device instances enumeration */ +typedef enum _usb_host_device_enumeration_status +{ + kStatus_DEV_Notinit = 0, /*!< Device is invalid */ + kStatus_DEV_Initial, /*!< Device has been processed by host driver */ + kStatus_DEV_GetDes8, /*!< Enumeration process: get 8 bytes' device descriptor */ + kStatus_DEV_SetAddress, /*!< Enumeration process: set device address */ + kStatus_DEV_GetDes, /*!< Enumeration process: get device descriptor */ + kStatus_DEV_GetCfg9, /*!< Enumeration process: get 9 bytes' configuration descriptor */ + kStatus_DEV_GetCfg, /*!< Enumeration process: get configuration descriptor */ + kStatus_DEV_SetCfg, /*!< Enumeration process: set configuration */ + kStatus_DEV_EnumDone, /*!< Enumeration is done */ + kStatus_DEV_AppUsed, /*!< This device has been used by application */ +} usb_host_device_enumeration_status_t; + +/*! @brief States of device's interface */ +typedef enum _usb_host_interface_state +{ + kStatus_interface_Attached = 1, /*!< Interface's default status */ + kStatus_interface_Opened, /*!< Interface is used by application */ + kStatus_interface_Detached, /*!< Interface is not used by application */ +} usb_host_interface_state_t; + +/*! @brief States of device */ +typedef enum _usb_host_device_state +{ + kStatus_device_Detached = 0, /*!< Device is used by application */ + kStatus_device_Attached, /*!< Device's default status */ +} usb_host_device_state_t; + +/*! @brief Device instance */ +typedef struct _usb_host_device_instance +{ + struct _usb_host_device_instance *next; /*!< Next device, or NULL */ + usb_host_handle hostHandle; /*!< Host handle */ + usb_host_configuration_t configuration; /*!< Parsed configuration information for the device */ + usb_descriptor_device_t *deviceDescriptor; /*!< Standard device descriptor */ + usb_host_pipe_handle controlPipe; /*!< Device's control pipe */ + uint8_t *configurationDesc; /*!< Configuration descriptor pointer */ + uint16_t configurationLen; /*!< Configuration descriptor length */ + uint16_t configurationValue; /*!< Configuration index */ + uint8_t interfaceStatus[USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE]; /*!< Interfaces' status, please reference to + #usb_host_interface_state_t */ + uint8_t *enumBuffer; /*!< Buffer for enumeration */ + uint8_t state; /*!< Device state for enumeration */ + uint8_t enumRetries; /*!< Re-enumeration when error in control transfer */ + uint8_t stallRetries; /*!< Re-transfer when stall */ + uint8_t speed; /*!< Device speed */ + uint8_t allocatedAddress; /*!< Temporary address for the device. When set address request succeeds, setAddress is + a value, 1 - 127 */ + uint8_t setAddress; /*!< The address has been set to the device successfully, 1 - 127 */ + uint8_t deviceAttachState; /*!< See the usb_host_device_state_t */ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + /* hub related */ + uint8_t hubNumber; /*!< Device's first connected hub address (root hub = 0) */ + uint8_t portNumber; /*!< Device's first connected hub's port no (1 - 8) */ + uint8_t hsHubNumber; /*!< Device's first connected high-speed hub's address (1 - 8) */ + uint8_t hsHubPort; /*!< Device's first connected high-speed hub's port no (1 - 8) */ + uint8_t level; /*!< Device's level (root device = 0) */ +#endif +} usb_host_device_instance_t; + +typedef struct _usb_host_enum_process_entry +{ + uint8_t successState; /*!< When the last step is successful, the next state value */ + uint8_t retryState; /*!< When the last step need retry, the next state value */ + usb_status_t (*process)(usb_host_device_instance_t *deviceInstance); /*!< When the last step transfer is done, the + function is used to process the transfer + data */ +} usb_host_enum_process_entry_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Calls this function when device attach. + * + * @param hostHandle Host instance handle. + * @param speed Device speed. + * @param hubNumber Device hub no. root device's hub no. is 0. + * @param portNumber Device port no. root device's port no. is 0. + * @param level Device level. root device's level is 1. + * @param deviceHandle Return device handle. + * + * @return kStatus_USB_Success or error codes. + */ +extern usb_status_t USB_HostAttachDevice(usb_host_handle hostHandle, + uint8_t speed, + uint8_t hubNumber, + uint8_t portNumber, + uint8_t level, + usb_device_handle *deviceHandle); + +/*! + * @brief Call this function when device detaches. + * + * @param hostHandle Host instance handle. + * @param hubNumber Device hub no. root device's hub no. is 0. + * @param portNumber Device port no. root device's port no. is 0. + * + * @return kStatus_USB_Success or error codes. + */ +extern usb_status_t USB_HostDetachDevice(usb_host_handle hostHandle, uint8_t hubNumber, uint8_t portNumber); + +/*! + * @brief Call this function when device detaches. + * + * @param hostHandle Host instance handle. + * @param deviceHandle Device handle. + * + * @return kStatus_USB_Success or error codes. + */ +extern usb_status_t USB_HostDetachDeviceInternal(usb_host_handle hostHandle, usb_device_handle deviceHandle); + +/*! + * @brief Gets the device attach/detach state. + * + * @param deviceHandle Device handle. + * + * @return 0x01 - attached; 0x00 - detached. + */ +extern uint8_t USB_HostGetDeviceAttachState(usb_device_handle deviceHandle); + +/*! + * @brief Determine whether the device is attached. + * + * @param hostHandle Host instance pointer. + * @param deviceHandle Device handle. + * + * @return kStatus_USB_Success or error codes. + */ +extern usb_status_t USB_HostValidateDevice(usb_host_handle hostHandle, usb_device_handle deviceHandle); + +/*! @}*/ +#endif /* _USB_HOST_DEV_MNG_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_ehci.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_ehci.c new file mode 100644 index 000000000..efbe042c5 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_ehci.c @@ -0,0 +1,4796 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI > 0U)) +#include "usb_host.h" +#include "usb_host_hci.h" +#include "usb_host_devices.h" +#include "fsl_device_registers.h" +#include "usb_host_ehci.h" +#include "usb_phy.h" +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) +#include "usb_host.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#if defined(USB_STACK_USE_DEDICATED_RAM) && (USB_STACK_USE_DEDICATED_RAM > 0U) + +#error The SOC does not suppoort dedicated RAM case. + +#endif + +#define USB_HOST_EHCI_BANDWIDTH_DELAY (3500U) +#define USB_HOST_EHCI_BANDWIDTH_HUB_LS_SETUP (333U) +#define USB_HOST_EHCI_BANDWIDTH_FRAME_TOTOAL_TIME (900U) + +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) +#define USB_HOST_EHCI_TEST_DESCRIPTOR_LENGTH (18U) +#define USB_HOST_EHCI_PORTSC_PTC_J_STATE (0x01U) +#define USB_HOST_EHCI_PORTSC_PTC_K_STATE (0x02U) +#define USB_HOST_EHCI_PORTSC_PTC_SE0_NAK (0x03U) +#define USB_HOST_EHCI_PORTSC_PTC_PACKET (0x04U) +#define USB_HOST_EHCI_PORTSC_PTC_FORCE_ENABLE_HS (0x05U) +#define USB_HOST_EHCI_PORTSC_PTC_FORCE_ENABLE_FS (0x06U) +#define USB_HOST_EHCI_PORTSC_PTC_FORCE_ENABLE_LS (0x07U) +#endif + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief compute data bandwidth time. + * + * @param speed data speed. + * @param pipeType data type. + * @param direction data direction. + * @param dataLength data length. + * + *@return time value. + */ +static uint32_t USB_HostBandwidthComputeTime(uint8_t speed, uint8_t pipeType, uint8_t direction, uint32_t dataLength); + +/*! + * @brief compute current allocated bandwidth when ehci work as full-speed or low-speed host. + * + * @param ehciInstance ehci instance pointer. + * @param frameIndex frame index. + * @param frameBandwidths return frame bandwidth data. + */ +static void USB_HostBandwidthFslsHostComputeCurrent(usb_host_ehci_instance_t *ehciInstance, + uint16_t frameIndex, + uint16_t *frameBandwidth); + +/*! + * @brief compute current hub's allocated FS/LS bandwidth when ehci work as hi-speed host. + * + * @param ehciInstance ehci instance pointer. + * @param hubNumber hub address. + * @param frameIndex frame index. + * @param frameBandwidths return frame bandwidth data. + */ +static void USB_HostBandwidthHsHostComputeCurrentFsls(usb_host_ehci_instance_t *ehciInstance, + uint32_t hubNumber, + uint16_t frameIndex, + uint8_t frameBandwidths[8]); + +/*! + * @brief compute current allocated HS bandwidth when ehci work as hi-speed host. + * + * @param ehciInstance ehci instance pointer. + * @param frameIndex frame index. + * @param frameBandwidths return frame bandwidth data. + */ +static void USB_HostBandwidthHsHostComputeCurrentHsAll(usb_host_ehci_instance_t *ehciInstance, + uint16_t frameIndex, + uint8_t frameBandwidths[8]); + +/*! + * @brief allocate HS bandwidth when host work as high-speed host. + * + * @param ehciInstance ehci instance pointer. + * @param uframeInterval micro-frame interval. + * @param timeData time for allocating. + * @param uframe_index_out return start uframe index. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostBandwidthHsHostAllocateHsCommon(usb_host_ehci_instance_t *ehciInstance, + uint16_t uframeInterval, + uint16_t timeData, + uint16_t *uframeIndexOut); + +/*! + * @brief allocate HS interrupt bandwidth when host work as high-speed host. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostBandwidthHsHostAllocateInterrupt(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer); + +/*! + * @brief allocate bandwidth when host work as full-speed or low-speed host. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostBandwidthFslsHostAllocate(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer); + +/*! + * @brief get the 2 power value of uint8_t. + * + * @param value input uint8_t value. + */ +static uint8_t USB_HostEhciGet2PowerValue(uint8_t value); + +/*! + * @brief memory zero. + * + * @param buffer buffer pointer. + * @param length buffer length. + */ +static void USB_HostEhciZeroMem(uint32_t *buffer, uint32_t length); + +/*! + * @brief host ehci delay. + * + * @param ehciIpBase ehci ip base address. + * @param ms millisecond. + */ +static void USB_HostEhciDelay(USBHS_Type *ehciIpBase, uint32_t ms); + +/*! + * @brief host ehci start async schedule. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciStartAsync(usb_host_ehci_instance_t *ehciInstance); + +/*! + * @brief host ehci stop async schedule. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciStopAsync(usb_host_ehci_instance_t *ehciInstance); + +/*! + * @brief host ehci start periodic schedule. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciStartPeriodic(usb_host_ehci_instance_t *ehciInstance); + +/*! + * @brief host ehci stop periodic schedule. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciStopPeriodic(usb_host_ehci_instance_t *ehciInstance); + +/*! + * @brief initialize the qtd for one transfer. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * @param transfer transfer information. + * + *@return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciQhQtdListInit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + usb_host_transfer_t *transfer); + +/*! + * @brief release the qtd list. + * + * @param ehciInstance ehci instance pointer. + * @param ehciQtdStart qtd list start pointer. + * @param ehciQtdEnd qtd list end pointer. + * + *@return the transfer's length. + */ +static uint32_t USB_HostEhciQtdListRelease(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_qtd_t *ehciQtdStart, + usb_host_ehci_qtd_t *ehciQtdEnd); + +/*! + * @brief de-initialize qh's linking qtd list. + * 1. remove qtd from qh; 2. remove transfer from qh; 3. release qtd; 4. transfer callback. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe. + * + *@return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciQhQtdListDeinit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer); + +/*! + * @brief de-initialize transfer's linking qtd list. + * 1. stop this qh schedule; 2. remove qtd from qh; 3. remove transfer from qh; 4. release qtd; 5. transfer callback; 6. + *start this qh schedule. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * @param transfer transfer information. + * + *@return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciTransferQtdListDeinit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + usb_host_transfer_t *transfer); + +/*! + * @brief initialize QH when opening one control, bulk or interrupt pipe. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciQhInit(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer); + +/*! + * @brief de-initialize QH when closing one control, bulk or interrupt pipe. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciQhDeinit(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer); + +/*! + * @brief add qh to one frame entry. + * + * @param ehciInstance ehci instance pointer. + * @param entryPointerValue entry pointer value. + * @param framePos frame index. + * @param uframeInterval micro-frame interval. + */ +static void USB_HostEhciAddQhToFrame(usb_host_ehci_instance_t *ehciInstance, + uint32_t entryPointerValue, + uint16_t framePos, + uint16_t uframeInterval); + +/*! + * @brief remove entry from frame list. + * + * @param ehciInstance ehci instance pointer. + * @param entryPointerValue entry pointer value. + * @param framePos frame index. + */ +static void USB_HostEhciRemoveFromFrame(usb_host_ehci_instance_t *ehciInstance, + uint32_t entryPointerValue, + uint16_t framePos); + +#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)) +/*! + * @brief add sitd array to the frame list. + * + * @param ehciInstance ehci instance pointer. + * @param entryPointerValue entry pointer value. + * @param startEntryPointer sitd entry pointer. + */ +static void USB_HostEhciLinkSitd(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + void *startEntryPointer); + +/*! + * @brief initialize sitd array for one transfer. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * @param transfer transfer information. + */ +static usb_status_t USB_HostEhciSitdArrayInit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + usb_host_transfer_t *transfer); + +/*! + * @brief release sitd list. + * + * @param ehciInstance ehci instance pointer. + * @param startSitdPointer start sitd pointer. + * @param endSitdPointer end sitd pointer. + * + * @return transfer's result length. + */ +static uint32_t USB_HostEhciSitdArrayRelease(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_sitd_t *startSitdPointer, + usb_host_ehci_sitd_t *endSitdPointer); + +/*! + * @brief de-initialize sitd list. + * 1. remove transfer; 2. remove sitd from frame list and release sitd; 3. transfer callback + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciSitdArrayDeinit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer); +#endif /* USB_HOST_CONFIG_EHCI_MAX_SITD */ + +#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) +/*! + * @brief compute the frame index when inserting itd. + * + * @param ehciInstance ehci instance pointer. + * @param lastLinkUframe last inserted micro-frame. + * @param startUframe start micro-frame. + * @param uframeInterval micro-frame interval. + * + * @return frame index + */ +static uint32_t USB_HostEhciGetItdLinkFrame(usb_host_ehci_instance_t *ehciInstance, + uint32_t lastLinkUframe, + uint16_t startUframe, + uint16_t uframeInterval); + +/*! + * @brief initialize itd list for one transfer. + * 1. initialize itd list; 2. insert itd to frame list. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * @param transfer transfer information. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciItdArrayInit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + usb_host_transfer_t *transfer); + +/*! + * @brief release itd list. + * + * @param ehciInstance ehci instance pointer. + * @param startItdPointer start itd pointer. + * @param endItdPointer end itd pointer. + * + * @return transfer's result length. + */ +static uint32_t USB_HostEhciItdArrayRelease(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_itd_t *startItdPointer, + usb_host_ehci_itd_t *endItdPointer); + +/*! + * @brief de-initialize itd list. + * 1. remove transfer; 2. remove itd from frame list and release itd; 3. transfer callback + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciItdArrayDeinit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer); +#endif /* USB_HOST_CONFIG_EHCI_MAX_ITD */ + +/*! + * @brief open control or bulk pipe. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciOpenControlBulk(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer); + +/*! + * @brief close control or bulk pipe. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciCloseControlBulk(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer); + +/*! + * @brief open interrupt pipe. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciOpenInterrupt(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer); + +/*! + * @brief close interrupt pipe. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciCloseInterrupt(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer); + +#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \ + ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) +/*! + * @brief open iso pipe. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciOpenIso(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer); + +/*! + * @brief close iso pipe. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciCloseIso(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer); + +/*! + * @brief allocate HS iso bandwidth when host work as high-speed host. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostBandwidthHsHostAllocateIso(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer); + +#endif + +/*! + * @brief reset ehci ip. + * + * @param ehciInstance ehci instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciResetIP(usb_host_ehci_instance_t *ehciInstance); + +/*! + * @brief start ehci ip. + * + * @param ehciInstance ehci instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciStartIP(usb_host_ehci_instance_t *ehciInstance); + +/*! + * @brief cancel pipe's transfers. + * + * @param ehciInstance ehci instance pointer. + * @param ehciPipePointer ehci pipe pointer. + * @param transfer the canceling transfer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciCancelPipe(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + usb_host_transfer_t *transfer); + +/*! + * @brief control ehci bus. + * + * @param ehciInstance ehci instance pointer. + * @param bus_control control code. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciControlBus(usb_host_ehci_instance_t *ehciInstance, uint8_t busControl); + +/*! + * @brief ehci transaction done process function. + * + * @param ehciInstance ehci instance pointer. + */ +void USB_HostEhciTransactionDone(usb_host_ehci_instance_t *ehciInstance); + +/*! + * @brief ehci port change interrupt process function. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciPortChange(usb_host_ehci_instance_t *ehciInstance); + +/*! + * @brief ehci timer0 interrupt process function. + * cancel control/bulk transfer that time out. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciTimer0(usb_host_ehci_instance_t *ehciInstance); + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) +/*! + * @brief ehci timer1 interrupt process function. + * cancel control/bulk transfer that time out. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciTimer1(usb_host_ehci_instance_t *ehciInstance); +#endif + +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) +/*! + * @brief suspend bus. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciSuspendBus(usb_host_ehci_instance_t *ehciInstance); + +/*! + * @brief resume bus. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciResumeBus(usb_host_ehci_instance_t *ehciInstance); + +extern usb_status_t USB_HostStandardSetGetDescriptor(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); +#endif /* USB_HOST_CONFIG_COMPLIANCE_TEST */ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* EHCI controller driver instances. */ +#if (USB_HOST_CONFIG_EHCI == 1U) +USB_RAM_ADDRESS_ALIGNMENT(4096) +USB_CONTROLLER_DATA static uint8_t s_UsbHostEhciFrameList1[USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE * 4]; + +static uint8_t usbHostEhciFramListStatus[1] = {0}; + +USB_RAM_ADDRESS_ALIGNMENT(64) USB_CONTROLLER_DATA static usb_host_ehci_data_t s_UsbHostEhciData1; +#define USB_HOST_EHCI_DATA_ARRAY \ + { \ + &s_UsbHostEhciData1 \ + } +#elif (USB_HOST_CONFIG_EHCI == 2U) +USB_RAM_ADDRESS_ALIGNMENT(4096) +USB_CONTROLLER_DATA static uint8_t s_UsbHostEhciFrameList1[USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE * 4]; +USB_RAM_ADDRESS_ALIGNMENT(4096) +USB_CONTROLLER_DATA static uint8_t s_UsbHostEhciFrameList2[USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE * 4]; +static uint8_t usbHostEhciFramListStatus[2] = {0, 0}; + +USB_RAM_ADDRESS_ALIGNMENT(64) USB_CONTROLLER_DATA static usb_host_ehci_data_t s_UsbHostEhciData1; +USB_RAM_ADDRESS_ALIGNMENT(64) USB_CONTROLLER_DATA static usb_host_ehci_data_t s_UsbHostEhciData2; +#define USB_HOST_EHCI_DATA_ARRAY \ + { \ + &s_UsbHostEhciData1, &s_UsbHostEhciData2 \ + } +#else +#error "Please increase the instance count." +#endif + +static uint8_t s_SlotMaxBandwidth[8] = {125, 125, 125, 125, 125, 125, 50, 0}; +static uint8_t s_SlotMaxBandwidthHs[8] = {100, 100, 100, 100, 100, 100, 100, 100}; + +/******************************************************************************* + * Code + ******************************************************************************/ +/*! + * @brief EHCI NC get USB NC bass address. + * + * This function is used to get USB NC bass address. + * + * @param[in] controllerId EHCI controller ID; See the #usb_controller_index_t. + * + * @retval USB NC bass address. + */ +#if (defined(USB_HOST_CONFIG_LOW_POWER_MODE) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) +void *USB_EhciNCGetBase(uint8_t controllerId) +{ + void *usbNCBase = NULL; +#if ((defined FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + uint32_t instance; + uint32_t newinstance = 0; + uint32_t usbnc_base_temp[] = USBNC_BASE_ADDRS; + uint32_t usbnc_base[] = USBNC_BASE_ADDRS; + + if (controllerId < kUSB_ControllerEhci0) + { + return NULL; + } + + controllerId = controllerId - kUSB_ControllerEhci0; + + for (instance = 0; instance < (sizeof(usbnc_base_temp) / sizeof(usbnc_base_temp[0])); instance++) + { + if (usbnc_base_temp[instance]) + { + usbnc_base[newinstance++] = usbnc_base_temp[instance]; + } + } + if (controllerId > newinstance) + { + return NULL; + } + + usbNCBase = (void *)usbnc_base[controllerId]; +#endif + return usbNCBase; +} +#endif +#endif + +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) + +usb_status_t USB_HostEhciTestSetMode(usb_host_ehci_instance_t *ehciInstance, uint32_t testMode) +{ + uint32_t ehciPortSC; + + ehciPortSC = ehciInstance->ehciIpBase->PORTSC1; + ehciPortSC &= ~((uint32_t)USBHS_PORTSC1_PTC_MASK); /* clear test mode bits */ + ehciPortSC |= (testMode << USBHS_PORTSC1_PTC_SHIFT); /* set test mode bits */ + ehciInstance->ehciIpBase->PORTSC1 = ehciPortSC; + return kStatus_USB_Success; +} + +static void USB_HostEhciTestSuspendResume(usb_host_ehci_instance_t *ehciInstance) +{ + uint8_t timeCount; + timeCount = 15; /* 15s */ + while (timeCount--) + { + USB_HostEhciDelay(ehciInstance->ehciIpBase, 1000U); + } + USB_HostEhciSuspendBus(ehciInstance); + timeCount = 15; /* 15s */ + while (timeCount--) + { + USB_HostEhciDelay(ehciInstance->ehciIpBase, 1000U); + } + + USB_HostEhciResumeBus(ehciInstance); +} + +static void USB_HostEhciTestCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + USB_HostFreeTransfer(param, transfer); +} + +static void USB_HostEhciTestSingleStepGetDeviceDesc(usb_host_ehci_instance_t *ehciInstance, + usb_device_handle deviceHandle) +{ + usb_host_process_descriptor_param_t getDescriptorParam; + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_transfer_t *transfer; + uint8_t timeCount; + + /* disable periodic shedule */ + USB_HostEhciStopPeriodic(ehciInstance); + + timeCount = 15; /* 15s */ + while (timeCount--) + { + USB_HostEhciDelay(ehciInstance->ehciIpBase, 1000U); + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(ehciInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return; + } + + getDescriptorParam.descriptorLength = sizeof(usb_descriptor_device_t); + getDescriptorParam.descriptorLength = 18; + getDescriptorParam.descriptorBuffer = (uint8_t *)&deviceInstance->deviceDescriptor; + getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_DEVICE; + getDescriptorParam.descriptorIndex = 0; + getDescriptorParam.languageId = 0; + transfer->callbackFn = USB_HostEhciTestCallback; + transfer->callbackParam = ehciInstance->hostHandle; + transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR; + transfer->setupPacket->wIndex = 0; + transfer->setupPacket->wLength = 0; + transfer->setupPacket->wValue = 0; + USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam); +} + +static usb_status_t USB_HostEhciSingleStepQtdListInit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + usb_host_transfer_t *transfer, + uint8_t setupPhase) +{ + volatile usb_host_ehci_qh_t *vltQhPointer; + usb_host_ehci_qtd_t *qtdPointer = NULL; + volatile uint32_t *entryPointer; + uint32_t qtdNumber; + uint32_t dataLength; + uint32_t dataAddress; + uint8_t index; + + /* compute the qtd number */ + qtdNumber = 1; + + vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; + /* get qtd list */ + USB_HostEhciLock(); + if (qtdNumber <= ehciInstance->ehciQtdNumber) + { + ehciInstance->ehciQtdNumber -= qtdNumber; + qtdPointer = NULL; + do + { + if (qtdPointer != NULL) + { + qtdPointer->nextQtdPointer = (uint32_t)ehciInstance->ehciQtdHead; + } + qtdPointer = ehciInstance->ehciQtdHead; + ehciInstance->ehciQtdHead = (usb_host_ehci_qtd_t *)qtdPointer->nextQtdPointer; + qtdPointer->nextQtdPointer = 0; + } while (--qtdNumber); + } + else + { + USB_HostEhciUnlock(); + return kStatus_USB_Error; + } + USB_HostEhciUnlock(); + + /* int qTD */ + if (setupPhase == 1) /* setup transaction qtd init */ + { + qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + /* dt: need set; ioc: 0; C_Page: 0; PID Code: SETUP; Status: Active */ + qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0; + qtdPointer->transferResults[0] = + ((0x00000000 << EHCI_HOST_QTD_DT_SHIFT) | (8 << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) | + (EHCI_HOST_PID_SETUP << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK)); + dataAddress = (uint32_t)(transfer->setupPacket); + qtdPointer->transferResults[1] = dataAddress; /* current offset is set too */ + /* set buffer pointer no matter data length */ + for (index = 0; index < 4; ++index) + { + qtdPointer->bufferPointers[index] = ((dataAddress + (index + 1) * 4 * 1024) & 0xFFFFF000); + } + } + else if (setupPhase == 2) /* data transaction qtd */ + { + dataLength = transfer->transferLength; + if (dataLength != 0) + { + qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + /* dt: need set; ioc: 0; C_Page: 0; PID Code: IN/OUT; Status: Active */ + qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0; + + qtdPointer->transferResults[0] = + ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (dataLength << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) | + (EHCI_HOST_PID_IN << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK)); + + dataAddress = (uint32_t)(transfer->transferBuffer); + qtdPointer->transferResults[1] = dataAddress; /* current offset is set too */ + /* set buffer pointer no matter data length */ + for (index = 0; index < 4; ++index) + { + qtdPointer->bufferPointers[index] = ((dataAddress + (index + 1) * 4 * 1024) & 0xFFFFF000); + } + } + } + else if (setupPhase == 3) + { + /* status transaction qtd */ + qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + /* dt: dont care; ioc: 1; C_Page: 0; PID Code: IN/OUT; Status: Active */ + qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0; + + qtdPointer->transferResults[0] = + ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (EHCI_HOST_PID_OUT << EHCI_HOST_QTD_PID_CODE_SHIFT) | + (EHCI_HOST_QTD_IOC_MASK) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK)); + + qtdPointer->nextQtdPointer |= EHCI_HOST_T_INVALID_VALUE; + } + qtdPointer->nextQtdPointer |= EHCI_HOST_T_INVALID_VALUE; + qtdPointer->transferResults[0] |= EHCI_HOST_QTD_IOC_MASK; /* set IOC */ + + /* save qtd to transfer */ + transfer->union1.unitHead = (uint32_t)qtdPointer; + transfer->union2.unitTail = (uint32_t)qtdPointer; + /* link transfer to qh */ + transfer->next = NULL; + if (vltQhPointer->ehciTransferHead == NULL) + { + transfer->next = NULL; + vltQhPointer->ehciTransferHead = vltQhPointer->ehciTransferTail = transfer; + } + else + { + transfer->next = NULL; + vltQhPointer->ehciTransferTail->next = transfer; + vltQhPointer->ehciTransferTail = transfer; + } + + USB_HostEhciLock(); + /* link qtd to qh (link to end) */ + entryPointer = &(vltQhPointer->nextQtdPointer); + dataAddress = *entryPointer; /* dataAddress variable means entry value here */ + while ((dataAddress) && (!(dataAddress & EHCI_HOST_T_INVALID_VALUE))) + { + entryPointer = (volatile uint32_t *)dataAddress; + dataAddress = *entryPointer; + } + *entryPointer = (uint32_t)qtdPointer; + USB_HostEhciUnlock(); + USB_HostEhciStartAsync(ehciInstance); + + return kStatus_USB_Success; +} + +static void USB_HostEhciTestSingleStepGetDeviceDescData(usb_host_ehci_instance_t *ehciInstance, + usb_device_handle deviceHandle) +{ + static uint8_t buffer[USB_HOST_EHCI_TEST_DESCRIPTOR_LENGTH]; + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_transfer_t *transfer; + uint8_t timeCount; + + USB_HostEhciStopPeriodic(ehciInstance); + + if (USB_HostMallocTransfer(ehciInstance->hostHandle, &transfer) != kStatus_USB_Success) + { + return; + } + transfer->callbackFn = USB_HostEhciTestCallback; + transfer->callbackParam = ehciInstance->hostHandle; + transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR; + transfer->setupPacket->wLength = USB_SHORT_TO_LITTLE_ENDIAN(USB_HOST_EHCI_TEST_DESCRIPTOR_LENGTH); + transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN((uint16_t)((uint16_t)USB_DESCRIPTOR_TYPE_DEVICE << 8)); + transfer->setupPacket->wIndex = 0; + USB_HostEhciSingleStepQtdListInit(ehciInstance, (usb_host_ehci_pipe_t *)(deviceInstance->controlPipe), transfer, 1); + + timeCount = 15; /* 15s */ + while (timeCount--) + { + USB_HostEhciDelay(ehciInstance->ehciIpBase, 1000U); + } + + if (USB_HostMallocTransfer(ehciInstance->hostHandle, &transfer) != kStatus_USB_Success) + { + return; + } + transfer->callbackFn = USB_HostEhciTestCallback; + transfer->callbackParam = ehciInstance->hostHandle; + transfer->transferBuffer = buffer; + transfer->transferLength = USB_HOST_EHCI_TEST_DESCRIPTOR_LENGTH; + USB_HostEhciSingleStepQtdListInit(ehciInstance, (usb_host_ehci_pipe_t *)(deviceInstance->controlPipe), transfer, 2); + + if (USB_HostMallocTransfer(ehciInstance->hostHandle, &transfer) != kStatus_USB_Success) + { + return; + } + transfer->callbackFn = USB_HostEhciTestCallback; + transfer->callbackParam = ehciInstance->hostHandle; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + USB_HostEhciSingleStepQtdListInit(ehciInstance, (usb_host_ehci_pipe_t *)(deviceInstance->controlPipe), transfer, 3); + + timeCount = 15; /* 15s */ + while (timeCount--) + { + USB_HostEhciDelay(ehciInstance->ehciIpBase, 1000U); + } + + usb_echo("test_single_step_get_dev_desc_data finished\r\n"); + + return; +} + +void USB_HostEhciTestModeInit(usb_device_handle deviceHandle) +{ + uint32_t productId; + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_ehci_instance_t *ehciInstance = + (usb_host_ehci_instance_t *)(((usb_host_instance_t *)(deviceInstance->hostHandle))->controllerHandle); + + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDevicePID, &productId); + + usb_echo("usb host ehci test mode init product id:0x%x\r\n", productId); + + switch (productId) + { + case 0x0101U: + USB_HostEhciTestSetMode(ehciInstance, USB_HOST_EHCI_PORTSC_PTC_SE0_NAK); + break; + case 0x0102U: + USB_HostEhciTestSetMode(ehciInstance, USB_HOST_EHCI_PORTSC_PTC_J_STATE); + break; + case 0x0103U: + USB_HostEhciTestSetMode(ehciInstance, USB_HOST_EHCI_PORTSC_PTC_K_STATE); + break; + case 0x0104U: + USB_HostEhciTestSetMode(ehciInstance, USB_HOST_EHCI_PORTSC_PTC_PACKET); + break; + case 0x0105U: + usb_echo("set test mode FORCE_ENALBE_HS\r\n"); + USB_HostEhciTestSetMode(ehciInstance, USB_HOST_EHCI_PORTSC_PTC_FORCE_ENABLE_HS); + break; + case 0x0106U: + USB_HostEhciTestSuspendResume(ehciInstance); + break; + case 0x0107U: + usb_echo("start test SINGLE_STEP_GET_DEV_DESC\r\n"); + USB_HostEhciTestSingleStepGetDeviceDesc(ehciInstance, deviceHandle); + break; + case 0x0108U: + usb_echo("start test SINGLE_STEP_GET_DEV_DESC_DATA\r\n"); + USB_HostEhciTestSingleStepGetDeviceDescData(ehciInstance, deviceHandle); + break; + default: + break; + } + + return; +} + +static void USB_HostEhciSuspendBus(usb_host_ehci_instance_t *ehciInstance) +{ + uint32_t ehciPortSC; + + USB_HostEhciLock(); + ehciPortSC = ehciInstance->ehciIpBase->PORTSC1; + if (ehciPortSC & USBHS_PORTSC1_PE_MASK) + { + ehciPortSC = ehciInstance->ehciIpBase->PORTSC1; + ehciPortSC &= (uint32_t)(~EHCI_PORTSC1_W1_BITS); + ehciInstance->ehciIpBase->PORTSC1 = (ehciPortSC | USBHS_PORTSC1_SUSP_MASK); + } + USB_HostEhciUnlock(); +} + +static void USB_HostEhciResumeBus(usb_host_ehci_instance_t *ehciInstance) +{ + uint32_t ehciPortSC; + + USB_HostEhciLock(); + /* Resume port */ + ehciPortSC = ehciInstance->ehciIpBase->PORTSC1; + if (ehciPortSC & USBHS_PORTSC1_PE_MASK) + { + ehciPortSC &= (uint32_t)(~EHCI_PORTSC1_W1_BITS); + ehciInstance->ehciIpBase->PORTSC1 = (ehciPortSC | USBHS_PORTSC1_FPR_MASK); + } + USB_HostEhciUnlock(); +} +#endif + +static uint32_t USB_HostBandwidthComputeTime(uint8_t speed, uint8_t pipeType, uint8_t direction, uint32_t dataLength) +{ + uint32_t result = (3167 + ((1000 * dataLength) * 7U * 8U / 6U)) / 1000; + + if (pipeType == USB_ENDPOINT_ISOCHRONOUS) /* iso */ + { + if (speed == USB_SPEED_HIGH) + { + result = 38 * 8 * 2083 + 2083 * result + USB_HOST_EHCI_BANDWIDTH_DELAY; + } + else if (speed == USB_SPEED_FULL) + { + if (direction == USB_IN) + { + result = 7268000 + 83540 * result + USB_HOST_EHCI_BANDWIDTH_DELAY; + } + else + { + result = 6265000 + 83540 * result + USB_HOST_EHCI_BANDWIDTH_DELAY; + } + } + else + { + } + } + else /* interrupt */ + { + if (speed == USB_SPEED_HIGH) + { + result = 55 * 8 * 2083 + 2083 * result + USB_HOST_EHCI_BANDWIDTH_DELAY; + } + else if (speed == USB_SPEED_FULL) + { + result = 9107000 + 83540 * result + USB_HOST_EHCI_BANDWIDTH_DELAY; + } + else if (speed == USB_SPEED_LOW) + { + if (direction == USB_IN) + { + result = 64060000 + 2000 * USB_HOST_EHCI_BANDWIDTH_HUB_LS_SETUP + 676670 * result + + USB_HOST_EHCI_BANDWIDTH_DELAY; + } + else + { + result = 6265000 + 83540 * result + USB_HOST_EHCI_BANDWIDTH_DELAY; + } + } + else + { + } + } + + result /= 1000000; + if (result == 0) + { + result = 1; + } + + return result; +} + +static void USB_HostBandwidthFslsHostComputeCurrent(usb_host_ehci_instance_t *ehciInstance, + uint16_t frameIndex, + uint16_t *frameBandwidth) +{ + usb_host_ehci_pipe_t *ehciPipePointer; + + /* clear the bandwidth */ + *frameBandwidth = 0; + + ehciPipePointer = ehciInstance->ehciRunningPipeList; + while (ehciPipePointer != NULL) + { + /* only compute iso and interrupt pipe */ + if ((ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_ISOCHRONOUS) || + (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT)) + { + /* does pipe allocate bandwidth in frameIndex frame? note: interval is power of 2. */ + if ((frameIndex >= ehciPipePointer->startFrame) && + (!((uint32_t)(frameIndex - ehciPipePointer->startFrame) & + (uint32_t)(ehciPipePointer->pipeCommon.interval - 1)))) + { + *frameBandwidth += ehciPipePointer->dataTime; + } + } + ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next; + } +} + +static void USB_HostBandwidthHsHostComputeCurrentFsls(usb_host_ehci_instance_t *ehciInstance, + uint32_t hubNumber, + uint16_t frameIndex, + uint8_t frameBandwidths[8]) +{ + usb_host_ehci_pipe_t *ehciPipePointer; + uint8_t index; + uint32_t deviceInfo; + + for (index = 0; index < 8; ++index) + { + frameBandwidths[index] = 0; + } + + ehciPipePointer = ehciInstance->ehciRunningPipeList; + while (ehciPipePointer != NULL) + { + /* only compute iso and interrupt pipe */ + if ((ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_ISOCHRONOUS) || + (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT)) + { + /* compute FS/LS bandwidth that blong to same high-speed hub, because FS/LS bandwidth is allocated from + * first parent high-speed hub */ + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, + kUSB_HostGetDeviceHSHubNumber, &deviceInfo); + if (deviceInfo != hubNumber) + { + ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next; + continue; + } + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, + &deviceInfo); + if (deviceInfo == USB_SPEED_HIGH) + { + ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next; + continue; + } + + /* does pipe allocate bandwidth in frameIndex frame? note: interval is power of 2. */ + if ((frameIndex >= ehciPipePointer->startFrame) && + (!((uint32_t)(frameIndex - ehciPipePointer->startFrame) & + (uint32_t)(ehciPipePointer->pipeCommon.interval - 1)))) + { + if (ehciPipePointer->pipeCommon.pipeType == + USB_ENDPOINT_ISOCHRONOUS) /* iso bandwidth is allocated once */ + { + frameBandwidths[ehciPipePointer->startUframe + 1] += ehciPipePointer->dataTime; + } + else /* iso bandwidth is allocated three times */ + { + frameBandwidths[ehciPipePointer->startUframe + 1] += ehciPipePointer->dataTime; + frameBandwidths[ehciPipePointer->startUframe + 2] += ehciPipePointer->dataTime; + frameBandwidths[ehciPipePointer->startUframe + 3] += ehciPipePointer->dataTime; + } + } + } + ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next; + } + + for (index = 0; index < 7; ++index) /* */ + { + if (frameBandwidths[index] > s_SlotMaxBandwidth[index]) + { + frameBandwidths[index + 1] += (frameBandwidths[index] - s_SlotMaxBandwidth[index]); + frameBandwidths[index] = s_SlotMaxBandwidth[index]; + } + } +} + +static void USB_HostBandwidthHsHostComputeCurrentHsAll(usb_host_ehci_instance_t *ehciInstance, + uint16_t frameIndex, + uint8_t frameBandwidths[8]) +{ + usb_host_ehci_pipe_t *ehciPipePointer; + uint8_t index; + uint32_t deviceInfo; + uint16_t frameInterval; + + for (index = 0; index < 8; ++index) + { + frameBandwidths[index] = 0; + } + + ehciPipePointer = ehciInstance->ehciRunningPipeList; + while (ehciPipePointer != NULL) + { + /* only compute iso and interrupt pipe */ + if ((ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_ISOCHRONOUS) || + (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT)) + { + frameInterval = ehciPipePointer->pipeCommon.interval; + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, + &deviceInfo); + if (deviceInfo == USB_SPEED_HIGH) /* high-speed data bandwidth */ + { + /* frameInterval means micro-frame here */ + if (frameIndex >= ehciPipePointer->startFrame) + { + if ((frameInterval > 8) && + (frameIndex * 8 - ehciPipePointer->startFrame * 8 >= ehciPipePointer->startUframe)) + { + if (!((uint32_t)(frameIndex * 8 - ehciPipePointer->startFrame * 8 - + ehciPipePointer->startUframe) & + (uint32_t)(frameInterval - 1))) + { + frameBandwidths[ehciPipePointer->startUframe] += ehciPipePointer->dataTime; + } + } + else + { + for (index = ehciPipePointer->startUframe; index < 8; index += frameInterval) + { + frameBandwidths[index] += ehciPipePointer->dataTime; + } + } + } + } + else /* full-speed split bandwidth */ + { + if ((frameIndex >= ehciPipePointer->startFrame) && + (!((uint32_t)(frameIndex - ehciPipePointer->startFrame) & (uint32_t)(frameInterval - 1)))) + { + for (index = 0; index < 8; ++index) + { + if ((uint32_t)(ehciPipePointer->uframeSmask) & + (uint32_t)(0x01 << index)) /* start-split micro-frames */ + { + frameBandwidths[index] += ehciPipePointer->startSplitTime; + } + if ((uint32_t)(ehciPipePointer->uframeCmask) & + (uint32_t)(0x01 << index)) /* complete-split micro-frames */ + { + frameBandwidths[index] += ehciPipePointer->completeSplitTime; + } + } + } + } + } + ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next; + } + +#if 0 + for (index = 0; index < 7; ++index) /* */ + { + if (frameBandwidths[index] > s_SlotMaxBandwidthHs[index]) + { + frameBandwidths[index + 1] += (frameBandwidths[index] - s_SlotMaxBandwidthHs[index]); + frameBandwidths[index] = s_SlotMaxBandwidthHs[index]; + } + } +#endif +} + +/*! + * @brief allocate HS bandwidth when host work as high-speed host. + * + * @param ehciInstance ehci instance pointer. + * @param uframeInterval micro-frame interval. + * @param timeData time for allocating. + * @param uframeIndexOut return start uframe index. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostBandwidthHsHostAllocateHsCommon(usb_host_ehci_instance_t *ehciInstance, + uint16_t uframeInterval, + uint16_t timeData, + uint16_t *uframeIndexOut) +{ + uint16_t uframeIntervalIndex; + uint16_t uframeIndex; + uint16_t frameIndex; + uint8_t frameTimes[8]; + + frameIndex = 0; + USB_HostBandwidthHsHostComputeCurrentHsAll( + ehciInstance, frameIndex, frameTimes); /* compute the allocated bandwidths in the frameIndex frame */ + for (uframeIntervalIndex = 0; (uframeIntervalIndex < uframeInterval); ++uframeIntervalIndex) /* start micro-frame */ + { + /* for all the micro-frame in interval uframeInterval */ + for (uframeIndex = uframeIntervalIndex; uframeIndex < (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE * 8); + uframeIndex += uframeInterval) + { + if (frameIndex != (uframeIndex >> 3)) + { + frameIndex = (uframeIndex >> 3); + USB_HostBandwidthHsHostComputeCurrentHsAll( + ehciInstance, frameIndex, + frameTimes); /* compute the allocated bandwidths in the new frameIndex frame */ + } + if (frameTimes[uframeIndex & 0x0007] + timeData > + s_SlotMaxBandwidthHs[(uframeIndex & 0x0007)]) /* micro-frame has enough idle bandwidth? */ + { + break; /* fail */ + } + } + if (uframeIndex >= (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE * 8)) /* success? */ + { + break; + } + } + + if (uframeIntervalIndex < uframeInterval) + { + *uframeIndexOut = (uframeIntervalIndex); + return kStatus_USB_Success; + } + else + { + return kStatus_USB_Error; + } +} + +#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \ + ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) + +static usb_status_t USB_HostBandwidthHsHostAllocateIso(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer) +{ + usb_status_t status; + uint32_t deviceInfo; + uint32_t hubNumber; + uint16_t uframeIntervalIndex = 0; + uint16_t frameIntervalIndex = 0; + uint16_t frameIndex; + uint16_t timeCompleteSplit; + uint16_t timeStartSplit; + uint32_t timeData; + uint8_t SsCsNumber = 0; + uint16_t frameInterval; + uint8_t frameTimes[8]; + uint8_t allocateOk = 1; + uint8_t index; + + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, + &deviceInfo); + + timeData = USB_HostBandwidthComputeTime( + deviceInfo, USB_ENDPOINT_ISOCHRONOUS, ehciPipePointer->pipeCommon.direction, + ehciPipePointer->pipeCommon.maxPacketSize * ehciPipePointer->pipeCommon.numberPerUframe); + /* pipe is high-speed */ + if (deviceInfo == USB_SPEED_HIGH) + { + uframeIntervalIndex = 0; + status = USB_HostBandwidthHsHostAllocateHsCommon(ehciInstance, ehciPipePointer->uframeInterval, timeData, + &uframeIntervalIndex); + if (status == kStatus_USB_Success) + { + ehciPipePointer->startFrame = (uframeIntervalIndex / 8); + ehciPipePointer->startUframe = (uframeIntervalIndex & 0x0007); + ehciPipePointer->dataTime = timeData; + + return kStatus_USB_Success; + } + } + else /* pipe is full-speed or low-speed */ + { + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetHubThinkTime, + &deviceInfo); /* deviceInfo variable means hub think time */ + timeData += (deviceInfo * 7 / (6 * 12)); + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHSHubNumber, + &hubNumber); + frameInterval = ehciPipePointer->pipeCommon.interval; + + /* compute start-split and complete-split bandwidth */ + if (ehciPipePointer->pipeCommon.direction == USB_OUT) + { + timeStartSplit = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_ISOCHRONOUS, USB_OUT, + ehciPipePointer->pipeCommon.maxPacketSize); + timeCompleteSplit = 0; + } + else + { + timeStartSplit = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_ISOCHRONOUS, USB_IN, 1); + timeCompleteSplit = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_ISOCHRONOUS, USB_IN, + ehciPipePointer->pipeCommon.maxPacketSize); + } + /* note: bandwidth must put in one frame */ + for (uframeIntervalIndex = 0; uframeIntervalIndex <= 5; ++uframeIntervalIndex) /* uframe interval */ + { + for (frameIntervalIndex = 0; frameIntervalIndex < frameInterval; ++frameIntervalIndex) /* frame interval */ + { + allocateOk = 1; + for (frameIndex = frameIntervalIndex; frameIndex < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE; + frameIndex += frameInterval) /* check all the frames */ + { + /* compute start-split and complete-split number */ + SsCsNumber = (ehciPipePointer->pipeCommon.maxPacketSize + 187) / + 188; /* ss number for iso out; cs number for iso in */ + if (ehciPipePointer->pipeCommon.direction == USB_OUT) /* ISO OUT */ + { + if (uframeIntervalIndex + SsCsNumber > 8) + { + allocateOk = 0; + } + } + else + { + if (uframeIntervalIndex + 2 + SsCsNumber > + 8) /* ISO IN: there are two micro-frame interval between start-split and complete-split */ + { + allocateOk = 0; + } + } + if (allocateOk) + { + /* allocate start-split and complete-split bandwidth */ + USB_HostBandwidthHsHostComputeCurrentHsAll(ehciInstance, frameIndex, frameTimes); + if (ehciPipePointer->pipeCommon.direction == USB_OUT) /* ISO OUT */ + { + index = uframeIntervalIndex; + for (; index < (uframeIntervalIndex + SsCsNumber); ++index) + { + if (frameTimes[index] + timeStartSplit > s_SlotMaxBandwidthHs[index]) + { + allocateOk = 0; + break; + } + } + } + else /* ISO IN */ + { + index = uframeIntervalIndex; + if (frameTimes[index] + timeStartSplit > s_SlotMaxBandwidthHs[index]) + { + allocateOk = 0; + } + if (allocateOk) + { + index = + uframeIntervalIndex + + 2; /* there are two micro-frames interval between start-split and complete-split */ + for (; index < (uframeIntervalIndex + 2 + SsCsNumber); ++index) + { + if (frameTimes[index] + timeCompleteSplit > s_SlotMaxBandwidthHs[index]) + { + allocateOk = 0; + break; + } + } + } + } + } + + /* allocate data bandwidth */ + if (allocateOk) + { + USB_HostBandwidthHsHostComputeCurrentFsls(ehciInstance, hubNumber, frameIndex, frameTimes); + index = uframeIntervalIndex + 1; /* timeData bandwidth start position */ + /* iso must occupy all the uframe bandwidth */ + { + deviceInfo = timeData; /* note: deviceInfo variable means bandwidth here */ + while ((index < 8) && (deviceInfo > s_SlotMaxBandwidth[index])) + { + if (frameTimes[index] > 0) + { + allocateOk = 0; + break; + } + else + { + deviceInfo -= s_SlotMaxBandwidth[index]; + } + ++index; + } + } + } + if (allocateOk) + { + /* data bandwidth can be put in the frame? */ + index = uframeIntervalIndex + 1; /* timeData bandwidth start position */ + frameTimes[index] += timeData; + for (; index < 7; ++index) + { + if (frameTimes[index] > s_SlotMaxBandwidth[index]) + { + frameTimes[index + 1] += (frameTimes[index] - s_SlotMaxBandwidth[index]); + frameTimes[index] = s_SlotMaxBandwidth[index]; + } + else + { + break; + } + } + if (frameTimes[index] > s_SlotMaxBandwidth[index]) + { + allocateOk = 0; + } + } + + if (allocateOk) + { + break; + } + } + if (allocateOk) + { + break; + } + } + if (allocateOk) + { + break; + } + } + + if (allocateOk) + { + ehciPipePointer->startFrame = frameIntervalIndex; + ehciPipePointer->startUframe = uframeIntervalIndex; + ehciPipePointer->dataTime = timeData; + ehciPipePointer->startSplitTime = timeStartSplit; + ehciPipePointer->completeSplitTime = timeCompleteSplit; + if (ehciPipePointer->pipeCommon.direction == USB_OUT) + { + index = uframeIntervalIndex; + for (; index < (uframeIntervalIndex + SsCsNumber); ++index) + { + ehciPipePointer->uframeSmask = (uint32_t)ehciPipePointer->uframeSmask | (uint32_t)(0x01 << index); + } + } + else + { + index = uframeIntervalIndex; + ehciPipePointer->uframeSmask = (uint32_t)ehciPipePointer->uframeSmask | (uint32_t)(0x01 << index); + index = uframeIntervalIndex + 2; + for (; index < (uframeIntervalIndex + 2 + SsCsNumber); ++index) + { + ehciPipePointer->uframeCmask = (uint32_t)ehciPipePointer->uframeCmask | (uint32_t)(0x01 << index); + } + } + + return kStatus_USB_Success; + } + } + + return kStatus_USB_Error; +} + +#endif + +static usb_status_t USB_HostBandwidthHsHostAllocateInterrupt(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer) +{ + usb_status_t status; + uint32_t deviceInfo; + uint32_t hubNumber; + uint16_t uframeIntervalIndex = 0; + uint16_t frameIntervalIndex = 0; + uint16_t frameIndex; + uint16_t timeCompleteSplit; + uint16_t timeStartSplit; + uint32_t timeData; + uint8_t SsCsNumber; + uint16_t frameInterval; + uint8_t frameTimes[8]; + uint8_t allocateOk = 1; + uint8_t index; + + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, + &deviceInfo); + + timeData = USB_HostBandwidthComputeTime( + deviceInfo, USB_ENDPOINT_INTERRUPT, ehciPipePointer->pipeCommon.direction, + ehciPipePointer->pipeCommon.maxPacketSize * ehciPipePointer->pipeCommon.numberPerUframe); + /* pipe is high-speed */ + if (deviceInfo == USB_SPEED_HIGH) + { + uframeIntervalIndex = 0; + status = USB_HostBandwidthHsHostAllocateHsCommon(ehciInstance, ehciPipePointer->uframeInterval, timeData, + &uframeIntervalIndex); + if (status == kStatus_USB_Success) + { + ehciPipePointer->startFrame = (uframeIntervalIndex / 8); + ehciPipePointer->startUframe = (uframeIntervalIndex & 0x0007); + /* for HS interrupt start transaction position */ + if (ehciPipePointer->uframeInterval >= 8) + { + ehciPipePointer->uframeSmask = (0x01 << ehciPipePointer->startUframe); + } + else + { + ehciPipePointer->uframeSmask = 0x00u; + for (index = ehciPipePointer->startUframe; index < 8; index += ehciPipePointer->uframeInterval) + { + ehciPipePointer->uframeSmask |= (0x01U << index); + } + } + ehciPipePointer->dataTime = timeData; + + return kStatus_USB_Success; + } + } + else /* pipe is full-speed or low-speed */ + { + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetHubThinkTime, + &deviceInfo); + timeData += (deviceInfo * 7 / (6 * 12)); + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHSHubNumber, + &hubNumber); + frameInterval = ehciPipePointer->pipeCommon.interval; + SsCsNumber = 3; /* complete split number */ + + /* compute start-split and complete-split bandwidth */ + if (ehciPipePointer->pipeCommon.direction == USB_OUT) + { + timeStartSplit = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_OUT, + ehciPipePointer->pipeCommon.maxPacketSize) + + USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_OUT, 1); + timeCompleteSplit = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_OUT, 0); + } + else + { + timeStartSplit = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_IN, 1); + timeCompleteSplit = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_IN, + ehciPipePointer->pipeCommon.maxPacketSize) + + USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_IN, 0); + } + /* note: bandwidth must put in one frame */ + for (uframeIntervalIndex = 0; uframeIntervalIndex <= 4; ++uframeIntervalIndex) /* uframe interval */ + { + for (frameIntervalIndex = 0; frameIntervalIndex < frameInterval; ++frameIntervalIndex) /* frame interval */ + { + allocateOk = 1; + for (frameIndex = frameIntervalIndex; frameIndex < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE; + frameIndex += frameInterval) /* check all the frames */ + { + /* allocate data bandwidth */ + USB_HostBandwidthHsHostComputeCurrentFsls(ehciInstance, hubNumber, frameIndex, frameTimes); + index = uframeIntervalIndex + 1; + for (; index <= (uframeIntervalIndex + 3); ++index) /* data bandwidth number is 3. + uframeIntervalIndex don't exceed 4, so + index cannot exceed 7 */ + { + if (frameTimes[index] + timeData > s_SlotMaxBandwidth[index]) + { + allocateOk = 0; + break; + } + } + + if (allocateOk) + { + USB_HostBandwidthHsHostComputeCurrentHsAll(ehciInstance, frameIndex, frameTimes); + /* allocate start_split bandwidth */ + if (frameTimes[uframeIntervalIndex] + timeStartSplit > + s_SlotMaxBandwidthHs[uframeIntervalIndex]) + { + allocateOk = 0; + } + if (allocateOk) + { + /* allocate complete_split bandwidth */ + index = uframeIntervalIndex + 2; + /* complete-split number is normal 3. When uframeIntervalIndex is 4, complete-split number + * is 2. */ + for (; (index <= (uframeIntervalIndex + 1 + SsCsNumber)) && (index < 8); ++index) + { + if (frameTimes[index] + timeCompleteSplit > s_SlotMaxBandwidthHs[index]) + { + allocateOk = 0; + break; + } + } + } + } + + if (!allocateOk) + { + break; /* allocate fail */ + } + } + if (allocateOk) + { + break; + } + } + if (allocateOk) + { + break; + } + } + + if (allocateOk) + { + ehciPipePointer->startFrame = frameIntervalIndex; + ehciPipePointer->startUframe = uframeIntervalIndex; + ehciPipePointer->uframeSmask = (0x01 << ehciPipePointer->startUframe); + ehciPipePointer->uframeCmask = 0; + index = uframeIntervalIndex + 2; + for (; (index <= (uframeIntervalIndex + 1 + SsCsNumber)) && (index < 8); ++index) + { + ehciPipePointer->uframeCmask = (uint32_t)ehciPipePointer->uframeCmask | (uint32_t)(0x01 << index); + } + ehciPipePointer->dataTime = timeData; + ehciPipePointer->startSplitTime = timeStartSplit; + ehciPipePointer->completeSplitTime = timeCompleteSplit; + + return kStatus_USB_Success; + } + } + + return kStatus_USB_BandwidthFail; +} + +static usb_status_t USB_HostBandwidthFslsHostAllocate(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer) +{ + uint32_t FslsTime = 0; + uint32_t speed = 0; + uint16_t uframeIntervalIndex; + uint16_t frameIndex; + uint16_t frameInterval; + uint16_t frameTime; + + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetHubThinkTime, + &FslsTime); + FslsTime += (FslsTime * 7 / (6 * 12)); + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, &speed); + FslsTime = FslsTime + USB_HostBandwidthComputeTime(speed, ehciPipePointer->pipeCommon.pipeType, + ehciPipePointer->pipeCommon.direction, + ehciPipePointer->pipeCommon.maxPacketSize); + + frameInterval = ehciPipePointer->pipeCommon.interval; + for (uframeIntervalIndex = 0; uframeIntervalIndex < ehciPipePointer->uframeInterval; + ++uframeIntervalIndex) /* uframeIntervalIndex can exceed 8 */ + { + for (frameIndex = (uframeIntervalIndex >> 3); frameIndex < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE; + frameIndex += frameInterval) + { + USB_HostBandwidthFslsHostComputeCurrent(ehciInstance, frameIndex, &frameTime); + if (frameTime + FslsTime > USB_HOST_EHCI_BANDWIDTH_FRAME_TOTOAL_TIME) + { + break; + } + } + if (frameIndex >= USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE) + { + break; + } + } + if (uframeIntervalIndex < ehciPipePointer->uframeInterval) + { + ehciPipePointer->startFrame = (uframeIntervalIndex >> 3); + ehciPipePointer->startUframe = (uframeIntervalIndex & 0x0007); + ehciPipePointer->uframeSmask = 0; /* useless */ + ehciPipePointer->uframeCmask = 0; + ehciPipePointer->dataTime = FslsTime; + + return kStatus_USB_Success; + } + + return kStatus_USB_BandwidthFail; +} + +static uint8_t USB_HostEhciGet2PowerValue(uint8_t value) +{ + if ((value == 0) || (value == 1)) + { + return value; + } + if (value & 0xf0) + { + if (value & 0x80) + { + return 128; + } + else if (value & 0x40) + { + return 64; + } + else if (value & 0x20) + { + return 32; + } + else + { + return 16; + } + } + else + { + if (value & 0x08) + { + return 8; + } + else if (value & 0x04) + { + return 4; + } + else if (value & 0x02) + { + return 2; + } + else + { + return 1; + } + } +} + +static void USB_HostEhciZeroMem(uint32_t *buffer, uint32_t length) +{ + /* note: the zero unit is uint32_t */ + while (length--) + { + *buffer = 0; + buffer++; + } +} + +static void USB_HostEhciDelay(USBHS_Type *ehciIpBase, uint32_t ms) +{ + /* note: the max delay time cannot exceed half of max value (0x4000) */ + int32_t sofStart; + int32_t SofEnd; + uint32_t distance; + + sofStart = (int32_t)(ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE); + + do + { + SofEnd = (int32_t)(ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE); + distance = (uint32_t)(SofEnd - sofStart + EHCI_MAX_UFRAME_VALUE + 1); + } while ((distance & EHCI_MAX_UFRAME_VALUE) < (ms * 8)); /* compute the distance between sofStart and SofEnd */ +} + +static void USB_HostEhciStartAsync(usb_host_ehci_instance_t *ehciInstance) +{ + uint32_t stateSync; + + if (!(ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK)) + { + /* the status must be same when change USBCMD->ASE */ + do + { + stateSync = ((ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK) | + (ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_ASE_MASK)); + } while ((stateSync == USBHS_USBSTS_AS_MASK) || (stateSync == USBHS_USBCMD_ASE_MASK)); + + ehciInstance->ehciIpBase->ASYNCLISTADDR = (uint32_t)(ehciInstance->shedFirstQh); + ehciInstance->ehciIpBase->USBCMD |= USBHS_USBCMD_ASE_MASK; + while (!(ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK)) + { + } + } +} + +static void USB_HostEhciStopAsync(usb_host_ehci_instance_t *ehciInstance) +{ + uint32_t stateSync; + + /* the status must be same when change USBCMD->ASE */ + do + { + stateSync = ((ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK) | + (ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_ASE_MASK)); + } while ((stateSync == USBHS_USBSTS_AS_MASK) || (stateSync == USBHS_USBCMD_ASE_MASK)); + + ehciInstance->ehciIpBase->USBCMD &= (uint32_t)(~(uint32_t)USBHS_USBCMD_ASE_MASK); /* disable async schedule */ + while (ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK) + { + } +} + +static void USB_HostEhciStartPeriodic(usb_host_ehci_instance_t *ehciInstance) +{ + uint32_t stateSync; + + if (!(ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_PS_MASK)) + { + /* the status must be same when change USBCMD->PSE */ + do + { + stateSync = ((ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_PS_MASK) | + (ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_PSE_MASK)); + } while ((stateSync == USBHS_USBSTS_PS_MASK) || (stateSync == USBHS_USBCMD_PSE_MASK)); + ehciInstance->ehciIpBase->PERIODICLISTBASE = (uint32_t)(ehciInstance->ehciFrameList); + if (!(ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_PSE_MASK)) + { + ehciInstance->ehciIpBase->USBCMD |= USBHS_USBCMD_PSE_MASK; /* start periodic schedule */ + } + while (!(ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_PS_MASK)) + { + } + } + return; +} + +static void USB_HostEhciStopPeriodic(usb_host_ehci_instance_t *ehciInstance) +{ + uint32_t stateSync; + + /* the status must be same when change USBCMD->PSE */ + do + { + stateSync = ((ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_PS_MASK) | + (ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_PSE_MASK)); + } while ((stateSync == USBHS_USBSTS_PS_MASK) || (stateSync == USBHS_USBCMD_PSE_MASK)); + + ehciInstance->ehciIpBase->USBCMD &= (~USBHS_USBCMD_PSE_MASK); /* stop periodic schedule */ + while (ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_PS_MASK) + { + } +} + +static usb_status_t USB_HostEhciQhQtdListInit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + usb_host_transfer_t *transfer) +{ + volatile usb_host_ehci_qh_t *vltQhPointer; + usb_host_ehci_qtd_t *qtdPointer = NULL; + usb_host_ehci_qtd_t *BaseQtdPointer = NULL; + volatile uint32_t *entryPointer; + uint32_t qtdNumber; + uint32_t dataLength; + uint32_t dataAddress; + uint32_t endAddress; + uint8_t index; + + /* compute the qtd number */ + if (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_CONTROL) + { + /* assume setup data don't exceed one qtd data size, one qtd can transfer least 16k data */ + if (transfer->transferLength == 0) + { + qtdNumber = 2; + } + else + { + qtdNumber = 3; + } + } + else + { + qtdNumber = + (((transfer->transferLength) & 0xFFFFC000U) >> 14) + (((transfer->transferLength) & 0x00003FFF) ? 1 : 0); + } + + vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; + /* get qtd list */ + USB_HostEhciLock(); + if (qtdNumber <= ehciInstance->ehciQtdNumber) + { + ehciInstance->ehciQtdNumber -= qtdNumber; + BaseQtdPointer = ehciInstance->ehciQtdHead; + qtdPointer = NULL; + do + { + if (qtdPointer != NULL) + { + qtdPointer->nextQtdPointer = (uint32_t)ehciInstance->ehciQtdHead; + } + qtdPointer = ehciInstance->ehciQtdHead; + ehciInstance->ehciQtdHead = (usb_host_ehci_qtd_t *)qtdPointer->nextQtdPointer; + qtdPointer->nextQtdPointer = 0; + } while (--qtdNumber); + if (ehciInstance->ehciQtdNumber == 0) + { + ehciInstance->ehciQtdTail = NULL; + } + } + else + { + USB_HostEhciUnlock(); + return kStatus_USB_Error; + } + USB_HostEhciUnlock(); + + /* int qTD list */ + if (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_CONTROL) + { + /* setup transaction qtd */ + qtdPointer = BaseQtdPointer; + qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + /* dt: need set; ioc: 0; C_Page: 0; PID Code: SETUP; Status: Active */ + qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0; + qtdPointer->transferResults[0] = + ((0x00000000 << EHCI_HOST_QTD_DT_SHIFT) | (8 << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) | + (EHCI_HOST_PID_SETUP << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK)); + dataAddress = ((uint32_t)transfer->setupPacket); + qtdPointer->transferResults[1] = dataAddress; /* current offset is set too */ + /* set buffer pointer no matter data length */ + for (index = 0; index < 4; ++index) + { + qtdPointer->bufferPointers[index] = ((dataAddress + (index + 1) * 4 * 1024) & 0xFFFFF000U); + } + + /* data transaction qtd */ + dataLength = transfer->transferLength; + if (dataLength != 0) + { + qtdPointer = (usb_host_ehci_qtd_t *)(qtdPointer->nextQtdPointer); + + qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + /* dt: need set; ioc: 0; C_Page: 0; PID Code: IN/OUT; Status: Active */ + qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0; + if (transfer->direction == USB_OUT) + { + qtdPointer->transferResults[0] = + ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (dataLength << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) | + (EHCI_HOST_PID_OUT << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK)); + } + else + { + qtdPointer->transferResults[0] = + ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (dataLength << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) | + (EHCI_HOST_PID_IN << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK)); + } + + dataAddress = (uint32_t)transfer->transferBuffer; + qtdPointer->transferResults[1] = dataAddress; /* current offset is set too */ + /* set buffer pointer no matter data length */ + for (index = 0; index < 4; ++index) + { + qtdPointer->bufferPointers[index] = ((dataAddress + (index + 1) * 4 * 1024) & 0xFFFFF000U); + } + } + + /* status transaction qtd */ + qtdPointer = (usb_host_ehci_qtd_t *)(qtdPointer->nextQtdPointer); + qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + /* dt: dont care; ioc: 1; C_Page: 0; PID Code: IN/OUT; Status: Active */ + qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0; + if ((dataLength == 0) || (transfer->direction == USB_OUT)) + { + qtdPointer->transferResults[0] = + ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (EHCI_HOST_PID_IN << EHCI_HOST_QTD_PID_CODE_SHIFT) | + (EHCI_HOST_QTD_IOC_MASK) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK)); + } + else + { + qtdPointer->transferResults[0] = + ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (EHCI_HOST_PID_OUT << EHCI_HOST_QTD_PID_CODE_SHIFT) | + (EHCI_HOST_QTD_IOC_MASK) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK)); + } + qtdPointer->nextQtdPointer |= EHCI_HOST_T_INVALID_VALUE; + } + else + { + dataLength = transfer->transferLength; + dataAddress = (uint32_t)transfer->transferBuffer; + qtdPointer = BaseQtdPointer; + while (1) + { + endAddress = dataAddress + (16 * 1024); + if (endAddress > (uint32_t)(transfer->transferBuffer + transfer->transferLength)) + { + endAddress = (uint32_t)(transfer->transferBuffer + transfer->transferLength); + } + + qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + /* dt: set; ioc: 0; C_Page: 0; PID Code: IN/OUT; Status: Active */ + qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0; + if (transfer->direction == USB_OUT) + { + qtdPointer->transferResults[0] = + (((endAddress - dataAddress) << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) | + ((uint32_t)ehciPipePointer->pipeCommon.nextdata01 << EHCI_HOST_QTD_DT_SHIFT) | + (EHCI_HOST_QTD_CERR_MAX_VALUE << EHCI_HOST_QTD_CERR_SHIFT) | + (EHCI_HOST_PID_OUT << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK)); + } + else + { + qtdPointer->transferResults[0] = + (((endAddress - dataAddress) << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) | + ((uint32_t)ehciPipePointer->pipeCommon.nextdata01 << EHCI_HOST_QTD_DT_SHIFT) | + (EHCI_HOST_QTD_CERR_MAX_VALUE << EHCI_HOST_QTD_CERR_SHIFT) | + (EHCI_HOST_PID_IN << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK)); + } + qtdPointer->transferResults[1] = dataAddress; /* current offset is set too */ + /* set buffer pointer no matter data length */ + for (index = 0; index < 4; ++index) + { + qtdPointer->bufferPointers[index] = ((dataAddress + (index + 1) * 4 * 1024) & 0xFFFFF000U); + } + dataAddress = endAddress; /* for next qtd */ + + if (qtdPointer->nextQtdPointer == 0) + { + break; + } + qtdPointer = (usb_host_ehci_qtd_t *)(qtdPointer->nextQtdPointer); + } + + qtdPointer->nextQtdPointer |= EHCI_HOST_T_INVALID_VALUE; + qtdPointer->transferResults[0] |= EHCI_HOST_QTD_IOC_MASK; /* last one set IOC */ + } + + /* save qtd to transfer */ + transfer->union1.unitHead = (uint32_t)BaseQtdPointer; + transfer->union2.unitTail = (uint32_t)qtdPointer; + /* link transfer to qh */ + transfer->next = NULL; + if (vltQhPointer->ehciTransferHead == NULL) + { + transfer->next = NULL; + vltQhPointer->ehciTransferHead = vltQhPointer->ehciTransferTail = transfer; + } + else + { + transfer->next = NULL; + vltQhPointer->ehciTransferTail->next = transfer; + vltQhPointer->ehciTransferTail = transfer; + } + + USB_HostEhciLock(); + /* link qtd to qh (link to end) */ + entryPointer = &(vltQhPointer->nextQtdPointer); + dataAddress = *entryPointer; /* dataAddress variable means entry value here */ + while ((dataAddress) && (!(dataAddress & EHCI_HOST_T_INVALID_VALUE))) + { + entryPointer = (volatile uint32_t *)dataAddress; + dataAddress = *entryPointer; + } + *entryPointer = (uint32_t)BaseQtdPointer; + USB_HostEhciUnlock(); + USB_HostEhciStartAsync(ehciInstance); + + return kStatus_USB_Success; +} + +static uint32_t USB_HostEhciQtdListRelease(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_qtd_t *ehciQtdStart, + usb_host_ehci_qtd_t *ehciQtdEnd) +{ + uint32_t length = 0; + usb_host_ehci_qtd_t *qtdPointer; + + ehciQtdEnd->nextQtdPointer = 0; + + /* compute remaining length */ + qtdPointer = ehciQtdStart; + while (qtdPointer != ehciQtdEnd) + { + length += + ((qtdPointer->transferResults[0] & EHCI_HOST_QTD_TOTAL_BYTES_MASK) >> EHCI_HOST_QTD_TOTAL_BYTES_SHIFT); + qtdPointer = (usb_host_ehci_qtd_t *)qtdPointer->nextQtdPointer; + } + qtdPointer = ehciQtdEnd; + length += ((qtdPointer->transferResults[0] & EHCI_HOST_QTD_TOTAL_BYTES_MASK) >> EHCI_HOST_QTD_TOTAL_BYTES_SHIFT); + + /* put releasing qtd to idle qtd list */ + USB_HostEhciLock(); + if (ehciInstance->ehciQtdNumber == 0) + { + ehciInstance->ehciQtdHead = ehciQtdStart; + ehciInstance->ehciQtdTail = ehciQtdEnd; + } + else + { + ehciInstance->ehciQtdTail->nextQtdPointer = (uint32_t)ehciQtdStart; + ehciInstance->ehciQtdTail = ehciQtdEnd; + } + + while (ehciQtdStart != ehciQtdEnd) + { + ehciInstance->ehciQtdNumber++; + ehciQtdStart = (usb_host_ehci_qtd_t *)ehciQtdStart->nextQtdPointer; + } + ehciInstance->ehciQtdNumber++; + USB_HostEhciUnlock(); + + return length; +} + +static usb_status_t USB_HostEhciQhQtdListDeinit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer) +{ + volatile usb_host_ehci_qh_t *vltQhPointer; + usb_host_transfer_t *transfer; + usb_host_transfer_t *nextTransfer; + uint8_t needStop = 0; + + vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; + + USB_HostEhciLock(); /* this API is called from APP, the host task may occupy to access the same resource */ + /* remove qtd from qh */ + if ((!((uint32_t)vltQhPointer->nextQtdPointer & EHCI_HOST_T_INVALID_VALUE)) || + (!((uint32_t)vltQhPointer->currentQtdPointer & EHCI_HOST_T_INVALID_VALUE))) + { + /* need stop async schedule */ + if ((!(vltQhPointer->horizontalLinkPointer & EHCI_HOST_T_INVALID_VALUE)) && + (ehciPipePointer->pipeCommon.pipeType != USB_ENDPOINT_INTERRUPT)) + { + needStop = 1; + } + if (needStop) + { + USB_HostEhciStopAsync(ehciInstance); + } + vltQhPointer->currentQtdPointer = EHCI_HOST_T_INVALID_VALUE; /* invalid current qtd */ + vltQhPointer->nextQtdPointer = EHCI_HOST_T_INVALID_VALUE; /* invalid next qtd */ + vltQhPointer->transferOverlayResults[0] &= (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */ + if (needStop) + { + USB_HostEhciStartAsync(ehciInstance); + } + } + + /* remove transfer from the QH transfer list */ + transfer = vltQhPointer->ehciTransferHead; + vltQhPointer->ehciTransferHead = vltQhPointer->ehciTransferTail = NULL; + USB_HostEhciUnlock(); + + /* release qtd and transfer callback*/ + while (transfer != NULL) + { + nextTransfer = transfer->next; /* the transfer is released when call back */ + transfer->transferSofar = + USB_HostEhciQtdListRelease(ehciInstance, (usb_host_ehci_qtd_t *)(transfer->union1.unitHead), + (usb_host_ehci_qtd_t *)(transfer->union2.unitTail)); + transfer->transferSofar = (transfer->transferLength < transfer->transferSofar) ? + 0 : + (transfer->transferLength - transfer->transferSofar); + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferCancel); + transfer = nextTransfer; + } + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostEhciTransferQtdListDeinit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + usb_host_transfer_t *transfer) +{ + volatile usb_host_ehci_qh_t *vltQhPointer; + usb_host_transfer_t *preSearchTransfer; + uint32_t qhNextQtdValue; + uint32_t qtdPointerEntry; + uint32_t *searchQtdEntryPointer; + + vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; + + USB_HostEhciLock(); /* this API is called from APP, the host task may occupy to access the same resource */ + /* remove qtd from qh */ + qhNextQtdValue = (uint32_t)vltQhPointer->currentQtdPointer; + qtdPointerEntry = *((uint32_t *)qhNextQtdValue + 2); /* note: qtdPointerEntry means qtd status */ + if ((qhNextQtdValue & EHCI_HOST_T_INVALID_VALUE) || (!(qtdPointerEntry & EHCI_HOST_QTD_STATUS_ACTIVE_MASK))) + { + qhNextQtdValue = (uint32_t)vltQhPointer->nextQtdPointer; + } + if (!(qhNextQtdValue & EHCI_HOST_T_INVALID_VALUE)) /* there is pending qtd in the qh */ + { + /* this qh don't schedule temporarily */ + if (ehciPipePointer->pipeCommon.pipeType != USB_ENDPOINT_INTERRUPT) + { + USB_HostEhciStopAsync(ehciInstance); + } + vltQhPointer->currentQtdPointer |= EHCI_HOST_T_INVALID_VALUE; /* invalid current qtd */ + vltQhPointer->nextQtdPointer |= EHCI_HOST_T_INVALID_VALUE; /* invalid next qtd */ + if (ehciPipePointer->pipeCommon.pipeType != USB_ENDPOINT_INTERRUPT) + { + USB_HostEhciStartAsync(ehciInstance); + } + + /* remove qtd from qh one by one */ + qtdPointerEntry = transfer->union1.unitHead; + while (1) + { + /* search qh's qtd list for qtdPointerEntry */ + searchQtdEntryPointer = &qhNextQtdValue; + while (!((*searchQtdEntryPointer) & EHCI_HOST_T_INVALID_VALUE)) + { + if ((*searchQtdEntryPointer) == qtdPointerEntry) + { + *searchQtdEntryPointer = *((uint32_t *)qtdPointerEntry); /* remove the qtd from qh */ + break; + } + else + { + searchQtdEntryPointer = (uint32_t *)(*searchQtdEntryPointer); + } + } + if (qtdPointerEntry == transfer->union2.unitTail) + { + break; + } + qtdPointerEntry = *((uint32_t *)qtdPointerEntry); + } + } + + /* remove transfer from the QH transfer list */ + preSearchTransfer = vltQhPointer->ehciTransferHead; + if (preSearchTransfer == transfer) + { + vltQhPointer->ehciTransferHead = preSearchTransfer->next; + } + else + { + while (preSearchTransfer != NULL) + { + if (preSearchTransfer->next == transfer) + { + preSearchTransfer->next = transfer->next; + break; + } + else + { + preSearchTransfer = preSearchTransfer->next; + } + } + } + USB_HostEhciUnlock(); + + /* release qtd and callback */ + transfer->transferSofar = + USB_HostEhciQtdListRelease(ehciInstance, (usb_host_ehci_qtd_t *)(transfer->union1.unitHead), + (usb_host_ehci_qtd_t *)(transfer->union2.unitTail)); + transfer->transferSofar = + (transfer->transferLength < transfer->transferSofar) ? 0 : (transfer->transferLength - transfer->transferSofar); + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferCancel); + + /* start this qh schedule */ + vltQhPointer->transferOverlayResults[0] &= (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */ + if ((qhNextQtdValue != 0) && (!(qhNextQtdValue & EHCI_HOST_T_INVALID_VALUE))) + { + vltQhPointer->nextQtdPointer = qhNextQtdValue; + } + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostEhciQhInit(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer) +{ + usb_host_ehci_qh_t *qhPointer = NULL; + uint32_t address, speed, portNumber, hubNumber; + uint32_t controlBits1 = 0; + uint32_t controlBits2 = 0; + /* get qh */ + USB_HostEhciLock(); + if (ehciInstance->ehciQhList != NULL) + { + qhPointer = (usb_host_ehci_qh_t *)ehciInstance->ehciQhList; + ehciInstance->ehciQhList = + (usb_host_ehci_qh_t *)(ehciInstance->ehciQhList->horizontalLinkPointer & EHCI_HOST_POINTER_ADDRESS_MASK); + } + USB_HostEhciUnlock(); + if (qhPointer == NULL) + { +#ifdef HOST_EHCO + usb_echo("get qh error\r\n"); +#endif + return kStatus_USB_Error; + } + ehciPipePointer->ehciQh = (void *)qhPointer; + + /* initialize qh */ + USB_HostEhciZeroMem((uint32_t *)qhPointer, sizeof(usb_host_ehci_qh_t) / 4); + qhPointer->horizontalLinkPointer = EHCI_HOST_T_INVALID_VALUE; + qhPointer->currentQtdPointer = EHCI_HOST_T_INVALID_VALUE; + qhPointer->nextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + qhPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + qhPointer->ehciPipePointer = ehciPipePointer; + qhPointer->timeOutLabel = 0; + qhPointer->timeOutValue = USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE; + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, &speed); + /* initialize staticEndpointStates[0] */ + if (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT) + { + /* Software should set the RL field to zero if the queue head is an interrupt endpoint. */ + controlBits1 |= ((0U << EHCI_HOST_QH_RL_SHIFT) & EHCI_HOST_QH_RL_MASK); + } + else + { + if (ehciPipePointer->pipeCommon.nakCount >= 16) + { + controlBits1 |= ((15U << EHCI_HOST_QH_RL_SHIFT) & EHCI_HOST_QH_RL_MASK); + } + else + { + controlBits1 |= + (((uint32_t)ehciPipePointer->pipeCommon.nakCount << EHCI_HOST_QH_RL_SHIFT) & EHCI_HOST_QH_RL_MASK); + } + } + if (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_CONTROL) + { + if (speed != USB_SPEED_HIGH) + { + controlBits1 |= (1 << EHCI_HOST_QH_C_SHIFT); + } + controlBits1 |= (1 << EHCI_HOST_QH_DTC_SHIFT); + } + controlBits1 |= ((uint32_t)ehciPipePointer->pipeCommon.maxPacketSize << EHCI_HOST_QH_MAX_PACKET_LENGTH_SHIFT); + controlBits1 |= (speed << EHCI_HOST_QH_EPS_SHIFT); + controlBits1 |= ((uint32_t)ehciPipePointer->pipeCommon.endpointAddress << EHCI_HOST_QH_ENDPT_SHIFT); + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceAddress, + &address); + controlBits1 |= (address << EHCI_HOST_QH_DEVICE_ADDRESS_SHIFT); + qhPointer->staticEndpointStates[0] = controlBits1; + if (speed == USB_SPEED_HIGH) + { + controlBits2 |= ((uint32_t)ehciPipePointer->pipeCommon.numberPerUframe << EHCI_HOST_QH_MULT_SHIFT); + } + else + { + controlBits2 |= (0x00000001U << EHCI_HOST_QH_MULT_SHIFT); + } + /*initialize staticEndpointStates[1] */ + if (speed != USB_SPEED_HIGH) + { + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHSHubNumber, + &hubNumber); + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHSHubPort, + &portNumber); + } + else + { + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHubNumber, + &hubNumber); + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDevicePortNumber, + &portNumber); + } + controlBits2 |= (portNumber << EHCI_HOST_QH_PORT_NUMBER_SHIFT); + controlBits2 |= (hubNumber << EHCI_HOST_QH_HUB_ADDR_SHIFT); + controlBits2 |= ((uint32_t)ehciPipePointer->uframeCmask << EHCI_HOST_QH_UFRAME_CMASK_SHIFT); + controlBits2 |= ((uint32_t)ehciPipePointer->uframeSmask << EHCI_HOST_QH_UFRAME_SMASK_SHIFT); + qhPointer->staticEndpointStates[1] = controlBits2; + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostEhciQhDeinit(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer) +{ + usb_host_ehci_qh_t *qhPointer; + + qhPointer = (usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; + /* de-initialize qtd from qh */ + USB_HostEhciQhQtdListDeinit(ehciInstance, ehciPipePointer); + + /* release QH */ + USB_HostEhciLock(); + qhPointer->horizontalLinkPointer = (uint32_t)ehciInstance->ehciQhList; + ehciInstance->ehciQhList = qhPointer; + USB_HostEhciUnlock(); + + return kStatus_USB_Success; +} + +static void USB_HostEhciAddQhToFrame(usb_host_ehci_instance_t *ehciInstance, + uint32_t entryPointerValue, + uint16_t framePos, + uint16_t uframeInterval) +{ + volatile uint32_t *frameEntryPointer; + uint32_t frameEntryValue; + + /* search for the inserting point by interval */ + frameEntryPointer = (volatile uint32_t *)(&((uint32_t *)ehciInstance->ehciFrameList)[framePos]); + while (frameEntryPointer) + { + frameEntryValue = *frameEntryPointer; + if (frameEntryValue & EHCI_HOST_T_INVALID_VALUE) + { + /* insert into the end */ + *((uint32_t *)entryPointerValue) = EHCI_HOST_T_INVALID_VALUE; + *frameEntryPointer = (entryPointerValue | EHCI_HOST_POINTER_TYPE_QH); + break; + } + + if ((frameEntryValue & EHCI_HOST_POINTER_ADDRESS_MASK) == entryPointerValue) + { + return; /* has inserted */ + } + if (((frameEntryValue & EHCI_HOST_POINTER_TYPE_MASK) == EHCI_HOST_POINTER_TYPE_QH) && + (((usb_host_ehci_qh_t *)(frameEntryValue & EHCI_HOST_POINTER_ADDRESS_MASK)) + ->ehciPipePointer->uframeInterval <= uframeInterval)) + { + /* insert into this point */ + *((uint32_t *)entryPointerValue) = frameEntryValue; + *frameEntryPointer = (entryPointerValue | EHCI_HOST_POINTER_TYPE_QH); + return; + } + else + { + frameEntryPointer = (volatile uint32_t *)(frameEntryValue & EHCI_HOST_POINTER_ADDRESS_MASK); + } + } +} + +static void USB_HostEhciRemoveFromFrame(usb_host_ehci_instance_t *ehciInstance, + uint32_t entryPointerValue, + uint16_t framePos) +{ + volatile uint32_t *frameEntryPointer; + uint32_t frameEntryValue; + + /* search for the qh/itd/sitd entry */ + frameEntryPointer = (volatile uint32_t *)(&((uint32_t *)ehciInstance->ehciFrameList)[framePos]); + + while (frameEntryPointer) + { + frameEntryValue = *frameEntryPointer; + if (frameEntryValue & EHCI_HOST_T_INVALID_VALUE) + { + return; + } + + if ((frameEntryValue & EHCI_HOST_POINTER_ADDRESS_MASK) == entryPointerValue) + { + /* remove the entry */ + *frameEntryPointer = *((uint32_t *)entryPointerValue); + break; + } + else + { + frameEntryPointer = (volatile uint32_t *)(frameEntryValue & EHCI_HOST_POINTER_ADDRESS_MASK); + } + } +} + +#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)) +static void USB_HostEhciLinkSitd(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + void *startEntryPointer) +{ + usb_host_ehci_iso_t *isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh; + usb_host_ehci_sitd_t *sitdPointer; + uint32_t distance; + uint32_t frameInterval; + int32_t shouldLinkFrame; + int32_t currentFrame; + + frameInterval = (ehciPipePointer->uframeInterval >> 3); + + if (isoPointer->lastLinkFrame == 0xFFFF) /* first link */ + { + currentFrame = ((ehciInstance->ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE) >> 3); + currentFrame = ((uint32_t)(currentFrame + USB_HOST_EHCI_ISO_BOUNCE_FRAME_NUMBER) & + (EHCI_MAX_UFRAME_VALUE >> 3)); /* add USB_HOST_EHCI_ISO_BOUNCE_FRAME_NUMBER */ + /* frame should align with interval */ + currentFrame -= ehciPipePointer->startFrame; + currentFrame = + ((uint32_t)(currentFrame + frameInterval - 1) & (~(frameInterval - 1))); /* frameInterval is power of 2 */ + currentFrame += ehciPipePointer->startFrame; + } + else + { + shouldLinkFrame = isoPointer->lastLinkFrame + frameInterval; /* continuous next should link frame */ + if (shouldLinkFrame > (int32_t)(EHCI_MAX_UFRAME_VALUE >> 3)) + { + shouldLinkFrame = shouldLinkFrame - ((EHCI_MAX_UFRAME_VALUE >> 3) + 1); + } + currentFrame = ((ehciInstance->ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE) >> 3); + distance = ((shouldLinkFrame - currentFrame + (EHCI_MAX_UFRAME_VALUE >> 3) + 1) & + (EHCI_MAX_UFRAME_VALUE >> 3)); /* get the distance from shouldLinkFrame to currentFrame */ + /* shouldLinkFrame has add frameInterval, think about the align with interval, so here add (frameInterval * + * 2) */ + if ((distance <= (USB_HOST_EHCI_ISO_BOUNCE_FRAME_NUMBER + frameInterval * 2)) && (distance > 0)) + { + currentFrame = shouldLinkFrame; + } + else /* re-link */ + { + currentFrame = + ((uint32_t)(currentFrame + USB_HOST_EHCI_ISO_BOUNCE_FRAME_NUMBER) & (EHCI_MAX_UFRAME_VALUE >> 3)); + if (currentFrame > (int32_t)(EHCI_MAX_UFRAME_VALUE >> 3)) + { + currentFrame = currentFrame - ((EHCI_MAX_UFRAME_VALUE >> 3) + 1); + } + /* frame should align with interval */ + currentFrame -= ehciPipePointer->startFrame; + currentFrame = ((uint32_t)(currentFrame + frameInterval - 1) & (~(frameInterval - 1))); + currentFrame += ehciPipePointer->startFrame; + } + } + if (currentFrame >= (int32_t)USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE) /* frame turn around */ + { + shouldLinkFrame = + (currentFrame - USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE); /* shouldLinkFrame means inserted frame position */ + } + else + { + shouldLinkFrame = currentFrame; /* shouldLinkFrame means inserted frame position */ + } + + sitdPointer = (usb_host_ehci_sitd_t *)startEntryPointer; + while (sitdPointer) + { + sitdPointer->frameEntryIndex = shouldLinkFrame; + /* add to frame list head */ + sitdPointer->nextLinkPointer = ((uint32_t *)ehciInstance->ehciFrameList)[shouldLinkFrame]; + ((uint32_t *)ehciInstance->ehciFrameList)[shouldLinkFrame] = + ((uint32_t)sitdPointer | EHCI_HOST_POINTER_TYPE_SITD); + if (sitdPointer->nextSitdIndex == 0xFF) /* 0xFF is invalid value */ + { + break; + } + sitdPointer = &(ehciInstance->ehciSitdIndexBase[sitdPointer->nextSitdIndex]); /* next sitd */ + + shouldLinkFrame += frameInterval; + currentFrame += frameInterval; + if (shouldLinkFrame >= (int32_t)USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE) + { + shouldLinkFrame = (shouldLinkFrame - USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE); + } + } + + if (currentFrame > (int32_t)(EHCI_MAX_UFRAME_VALUE >> 3)) + { + currentFrame = currentFrame - ((EHCI_MAX_UFRAME_VALUE >> 3) + 1); + } + isoPointer->lastLinkFrame = currentFrame; /* save the last link frame value */ +} + +static usb_status_t USB_HostEhciSitdArrayInit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + usb_host_transfer_t *transfer) +{ + usb_host_ehci_iso_t *isoPointer; + uint32_t sitdNumber = 0; + usb_host_ehci_sitd_t *sitdPointer; + uint32_t dataLength = 0; + uint32_t sitdLength = 0; + uint32_t dataBufferValue; + uint32_t hubNumber; + uint32_t portNumber; + uint32_t address; + uint32_t tmp; + uint8_t index; + + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceAddress, + &address); + + sitdNumber = ((transfer->transferLength - 1 + (ehciPipePointer->pipeCommon.maxPacketSize)) / + (ehciPipePointer->pipeCommon.maxPacketSize)); + /* get sitd array */ + tmp = ehciPipePointer - ehciInstance->ehciPipeIndexBase; /* pipe index */ + /* USB_HostEhciLock(); */ + if (ehciInstance->ehciSitdNumber >= sitdNumber) + { + sitdPointer = ehciInstance->ehciSitdList; + transfer->union1.unitHead = (uint32_t)sitdPointer; + for (index = 1; index < sitdNumber; ++index) + { + sitdPointer->nextSitdIndex = + (((usb_host_ehci_sitd_t *)sitdPointer->nextLinkPointer) - ehciInstance->ehciSitdIndexBase); + sitdPointer = (usb_host_ehci_sitd_t *)sitdPointer->nextLinkPointer; + } + sitdPointer->nextSitdIndex = 0xFF; + ehciInstance->ehciSitdList = (usb_host_ehci_sitd_t *)sitdPointer->nextLinkPointer; + ehciInstance->ehciSitdNumber -= sitdNumber; + } + else + { + /* USB_HostEhciUnlock(); */ + return kStatus_USB_Error; + } + /* USB_HostEhciUnlock(); */ + transfer->union2.unitTail = (uint32_t)sitdPointer; + /* initialize sitd array */ + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHubNumber, + &hubNumber); + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDevicePortNumber, + &portNumber); + sitdPointer = (usb_host_ehci_sitd_t *)transfer->union1.unitHead; + dataLength = transfer->transferLength; + while (sitdNumber--) + { + USB_HostEhciZeroMem((uint32_t *)sitdPointer, 7); + sitdLength = dataLength; + if (sitdLength > ehciPipePointer->pipeCommon.maxPacketSize) + { + sitdLength = ehciPipePointer->pipeCommon.maxPacketSize; + } + dataBufferValue = (uint32_t)(transfer->transferBuffer + (transfer->transferLength - dataLength)); + dataLength -= sitdLength; /* update left data length */ + sitdPointer->transferResults[1] = dataBufferValue; + sitdPointer->transferResults[2] = ((dataBufferValue + 4 * 1024) & 0xFFFFF000U); + sitdPointer->endpointStates[0] = + (((uint32_t)ehciPipePointer->pipeCommon.direction << EHCI_HOST_SITD_DIRECTION_SHIFT) | + (portNumber << EHCI_HOST_SITD_PORT_NUMBER_SHIFT) | (hubNumber << EHCI_HOST_SITD_HUB_ADDR_SHIFT) | + ((uint32_t)ehciPipePointer->pipeCommon.endpointAddress << EHCI_HOST_SITD_ENDPT_SHIFT) | + (address << EHCI_HOST_SITD_DEVICE_ADDRESS_SHIFT)); + sitdPointer->transferResults[0] = + ((sitdLength << EHCI_HOST_SITD_TOTAL_BYTES_SHIFT) | (EHCI_HOST_SITD_STATUS_ACTIVE_MASK)); + + if (ehciInstance->firstDeviceSpeed == USB_SPEED_HIGH) + { + sitdPointer->endpointStates[1] = (((uint32_t)ehciPipePointer->uframeCmask << EHCI_HOST_SITD_CMASK_SHIFT) | + ((uint32_t)ehciPipePointer->uframeSmask << EHCI_HOST_SITD_SMASK_SHIFT)); + + tmp = (sitdLength + 187) / 188; + if (tmp > 1) + { + sitdPointer->transferResults[2] |= (0x01 << EHCI_HOST_SITD_TP_SHIFT); /* for iso split */ + } + else + { + sitdPointer->transferResults[2] |= (0x00 << EHCI_HOST_SITD_TP_SHIFT); /* for iso split */ + } + sitdPointer->transferResults[2] |= (tmp << EHCI_HOST_SITD_TCOUNT_SHIFT); /* for iso split */ + } + + sitdPointer->backPointer = EHCI_HOST_T_INVALID_VALUE; + + sitdPointer = (ehciInstance->ehciSitdIndexBase + sitdPointer->nextSitdIndex); + } + sitdPointer = (usb_host_ehci_sitd_t *)transfer->union2.unitTail; + sitdPointer->transferResults[0] |= (1U << EHCI_HOST_SITD_IOC_SHIFT); /* last set IOC */ + + /* link transfer to usb_host_ehci_iso_t transfer list */ + isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh; + USB_HostEhciLock(); + if (isoPointer->ehciTransferHead == NULL) + { + transfer->next = NULL; + isoPointer->ehciTransferHead = isoPointer->ehciTransferTail = transfer; + } + else + { + transfer->next = NULL; + isoPointer->ehciTransferTail->next = transfer; + isoPointer->ehciTransferTail = transfer; + } + USB_HostEhciUnlock(); + + /* link itd to frame list (note: initialize frameEntryIndex)*/ + USB_HostEhciLinkSitd(ehciInstance, ehciPipePointer, (void *)transfer->union1.unitHead); + + return kStatus_USB_Success; +} + +static uint32_t USB_HostEhciSitdArrayRelease(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_sitd_t *startSitdPointer, + usb_host_ehci_sitd_t *endSitdPointer) +{ + usb_host_ehci_sitd_t *sitdPointer = startSitdPointer; + uint32_t leftLength = 0; + /* remove itd from frame list */ + while (1) + { + /* record the transfer's result length */ + leftLength += + ((sitdPointer->transferResults[0] & EHCI_HOST_SITD_TOTAL_BYTES_MASK) >> EHCI_HOST_SITD_TOTAL_BYTES_SHIFT); + USB_HostEhciRemoveFromFrame(ehciInstance, (uint32_t)sitdPointer, + sitdPointer->frameEntryIndex); /* remove from the inserted frame list */ + + /* release itd */ + /* USB_HostEhciLock(); */ + sitdPointer->nextLinkPointer = (uint32_t)ehciInstance->ehciSitdList; + ehciInstance->ehciSitdList = sitdPointer; + ehciInstance->ehciSitdNumber++; + /* USB_HostEhciUnlock(); */ + + if (sitdPointer == endSitdPointer) + { + break; + } + + sitdPointer = &(ehciInstance->ehciSitdIndexBase[sitdPointer->nextSitdIndex]); + } + + return leftLength; +} + +static usb_status_t USB_HostEhciSitdArrayDeinit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer) +{ + usb_host_ehci_iso_t *isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh; + usb_host_transfer_t *transfer; + usb_host_transfer_t *nextTransfer; + + /* firstly remove the transfer (because host task may occupy to access the resource) */ + USB_HostEhciLock(); + transfer = isoPointer->ehciTransferHead; + isoPointer->ehciTransferHead = isoPointer->ehciTransferTail = NULL; + USB_HostEhciUnlock(); + + while (transfer != NULL) + { + nextTransfer = transfer->next; + /* remove sitd from frame list and release itd */ + transfer->transferSofar = + transfer->transferLength - USB_HostEhciSitdArrayRelease(ehciInstance, + (usb_host_ehci_sitd_t *)transfer->union1.unitHead, + (usb_host_ehci_sitd_t *)transfer->union2.unitTail); + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferCancel); + /* next transfer */ + transfer = nextTransfer; + } + + return kStatus_USB_Success; +} +#endif /* USB_HOST_CONFIG_EHCI_MAX_SITD */ + +#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) +static uint32_t USB_HostEhciGetItdLinkFrame(usb_host_ehci_instance_t *ehciInstance, + uint32_t lastLinkUframe, + uint16_t startUframe, + uint16_t uframeInterval) +{ + int32_t shouldLinkUframe; + int32_t currentUframe; + int32_t distance; + + if (lastLinkUframe != 0xFFFF) + { + shouldLinkUframe = lastLinkUframe + uframeInterval; + if (shouldLinkUframe > (int32_t)EHCI_MAX_UFRAME_VALUE) + { + shouldLinkUframe = shouldLinkUframe - (EHCI_MAX_UFRAME_VALUE + 1); + } + currentUframe = (ehciInstance->ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE); + distance = ((shouldLinkUframe - currentUframe + EHCI_MAX_UFRAME_VALUE + 1) & + EHCI_MAX_UFRAME_VALUE); /* get the distance */ + /* shouldLinkUframe has add uframeInterval, think about the align with interval, so here add (uframeInterval + * * 2) */ + if ((distance <= (int32_t)(USB_HOST_EHCI_ISO_BOUNCE_UFRAME_NUMBER + (uframeInterval * 3))) && (distance > 2)) + { + currentUframe = shouldLinkUframe; + } + else /* re-link */ + { + currentUframe = + ((uint32_t)(currentUframe + USB_HOST_EHCI_ISO_BOUNCE_UFRAME_NUMBER) & EHCI_MAX_UFRAME_VALUE); + if (currentUframe > (int32_t)EHCI_MAX_UFRAME_VALUE) + { + currentUframe = currentUframe - (EHCI_MAX_UFRAME_VALUE + 1); + } + /* uframe should align with interval */ + currentUframe -= startUframe; + currentUframe = ((uint32_t)(currentUframe + uframeInterval) & + (~((uint32_t)uframeInterval - 1))); /* uframeInterval is power of 2 */ + currentUframe += startUframe; + } + } + else + { + currentUframe = (ehciInstance->ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE); + currentUframe = ((uint32_t)(currentUframe + USB_HOST_EHCI_ISO_BOUNCE_UFRAME_NUMBER) & EHCI_MAX_UFRAME_VALUE); + /* uframe should align with interval */ + currentUframe -= startUframe; + currentUframe = ((uint32_t)(currentUframe + uframeInterval) & + (~((uint32_t)uframeInterval - 1))); /* uframeInterval is power of 2 */ + currentUframe += startUframe; + } + + return currentUframe; +} + +static usb_status_t USB_HostEhciItdArrayInit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + usb_host_transfer_t *transfer) +{ + usb_host_ehci_iso_t *isoPointer; + usb_host_ehci_itd_t *itdPointer = NULL; + usb_host_ehci_itd_t *itdHead = NULL; + usb_host_ehci_itd_t *tmpItdPointer; + uint32_t dataLength; /* the remaining data for sending */ + uint32_t transactionLength; /* the initializing transaction descriptor data length */ + uint32_t itdBufferValue; + uint32_t itdBufferBaseValue; /* for calculating PG value */ + uint32_t address; + uint32_t lastShouldLinkUframe; + uint32_t linkUframe; + uint32_t minDataPerItd = ehciPipePointer->pipeCommon.numberPerUframe * ehciPipePointer->pipeCommon.maxPacketSize; + uint8_t maxItdNumber; + uint8_t index = 0; + + isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh; + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceAddress, + &address); + + /* max needed itd number, the actual needed number may be less because micro-frame interval may be less than 8 */ + maxItdNumber = ((transfer->transferLength - 1 + minDataPerItd) / minDataPerItd); + if (ehciPipePointer->uframeInterval < 8) + { + maxItdNumber = ((maxItdNumber * ehciPipePointer->uframeInterval + 7) / 8) + 1; + } + if (maxItdNumber > ehciInstance->ehciItdNumber) + { + return kStatus_USB_Error; + } + + /* link transfer to usb_host_ehci_iso_t transfer list */ + transfer->next = NULL; + /* USB_HostEhciLock(); */ + if (isoPointer->ehciTransferHead == NULL) + { + isoPointer->ehciTransferHead = isoPointer->ehciTransferTail = transfer; + } + else + { + isoPointer->ehciTransferTail->next = transfer; + isoPointer->ehciTransferTail = transfer; + } + /* USB_HostEhciUnlock(); */ + + dataLength = transfer->transferLength; + transfer->union1.unitHead = (uint32_t)NULL; + /* get the link micro-frame */ + lastShouldLinkUframe = USB_HostEhciGetItdLinkFrame( + ehciInstance, isoPointer->lastLinkFrame, + (uint16_t)((ehciPipePointer->startFrame << 3) + ehciPipePointer->startUframe), ehciPipePointer->uframeInterval); + if (lastShouldLinkUframe > EHCI_MAX_UFRAME_VALUE) + { + linkUframe = lastShouldLinkUframe - (EHCI_MAX_UFRAME_VALUE + 1); + } + else + { + linkUframe = lastShouldLinkUframe; + } + itdHead = ehciInstance->ehciItdList; + while (dataLength) + { + /* get one idle itd */ + tmpItdPointer = ehciInstance->ehciItdList; + ehciInstance->ehciItdList = (usb_host_ehci_itd_t *)tmpItdPointer->nextLinkPointer; + ehciInstance->ehciItdNumber -= 1; + if (tmpItdPointer == NULL) + { + return kStatus_USB_Error; /* this should not reach */ + } + tmpItdPointer->nextItdPointer = NULL; + + /* use the itd */ + if (transfer->union1.unitHead == (uint32_t)NULL) /* first itd */ + { + transfer->union1.unitHead = (uint32_t)tmpItdPointer; + } + else /* link itd list */ + { + itdPointer->nextItdPointer = tmpItdPointer; + } + itdPointer = tmpItdPointer; + + /* itd has been set to all zero when releasing */ + itdBufferBaseValue = itdBufferValue = + (uint32_t)(transfer->transferBuffer + (transfer->transferLength - dataLength)); + for (index = 0; index < 7; ++index) + { + itdPointer->bufferPointers[index] = ((itdBufferBaseValue + (index * 4 * 1024)) & 0xFFFFF000U); + } + /* initialize iTD common fields */ + itdPointer->bufferPointers[0] |= + (((uint32_t)ehciPipePointer->pipeCommon.endpointAddress << EHCI_HOST_ITD_ENDPT_SHIFT) | + (address << EHCI_HOST_ITD_DEVICE_ADDRESS_SHIFT)); + itdPointer->bufferPointers[1] |= + (((uint32_t)ehciPipePointer->pipeCommon.direction << EHCI_HOST_ITD_DIRECTION_SHIFT) | + ((uint32_t)ehciPipePointer->pipeCommon.maxPacketSize << EHCI_HOST_ITD_MAX_PACKET_SIZE_SHIFT)); + itdPointer->bufferPointers[2] |= (ehciPipePointer->pipeCommon.numberPerUframe); + /* initialize transaction descriptors */ + for (index = (linkUframe & 0x0007); index < 8; index += ehciPipePointer->uframeInterval) + { + transactionLength = ((dataLength > minDataPerItd) ? minDataPerItd : dataLength); + /* initialize the uframeIndex's transaction descriptor in itd */ + itdPointer->transactions[index] = + ((EHCI_HOST_ITD_STATUS_ACTIVE_MASK) | (transactionLength << EHCI_HOST_ITD_TRANSACTION_LEN_SHIFT) | + ((((itdBufferValue & 0xFFFFF000U) - (itdBufferBaseValue & 0xFFFFF000U)) >> + EHCI_HOST_ITD_BUFFER_POINTER_SHIFT) + << EHCI_HOST_ITD_PG_SHIFT) | + (itdBufferValue & EHCI_HOST_ITD_TRANSACTION_OFFSET_MASK)); + dataLength -= transactionLength; + itdBufferValue += transactionLength; + if (dataLength <= 0) + { + break; + } + } + } + + transfer->union2.unitTail = (uint32_t)itdPointer; + itdPointer->transactions[index] |= (1 << EHCI_HOST_ITD_IOC_SHIFT); /* last set IOC */ + + itdPointer = itdHead; + /* link itd to frame list (note: initialize frameEntryIndex)*/ + while (itdPointer) + { + itdPointer->frameEntryIndex = linkUframe >> 3; + /* add to frame head */ + itdPointer->nextLinkPointer = ((uint32_t *)ehciInstance->ehciFrameList)[linkUframe >> 3]; + ((uint32_t *)ehciInstance->ehciFrameList)[linkUframe >> 3] = + ((uint32_t)itdPointer | EHCI_HOST_POINTER_TYPE_ITD); + itdPointer = itdPointer->nextItdPointer; + if (itdPointer == NULL) + { + break; + } + + linkUframe += ehciPipePointer->uframeInterval; + lastShouldLinkUframe += ehciPipePointer->uframeInterval; + if (linkUframe >= (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE << 3)) + { + linkUframe = (linkUframe - (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE << 3)); + } + } + + if (lastShouldLinkUframe > EHCI_MAX_UFRAME_VALUE) + { + lastShouldLinkUframe = lastShouldLinkUframe - (EHCI_MAX_UFRAME_VALUE + 1); + } + isoPointer->lastLinkFrame = lastShouldLinkUframe; + + return kStatus_USB_Success; +} + +static uint32_t USB_HostEhciItdArrayRelease(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_itd_t *startItdPointer, + usb_host_ehci_itd_t *endItdPointer) +{ + usb_host_ehci_itd_t *itdPointer = startItdPointer; + uint8_t index; + uint32_t doneLength = 0; + + /* remove itd from frame list */ + while (1) + { + /* record the transfer's result length */ + for (index = 0; index < 8; ++index) + { + doneLength += ((itdPointer->transactions[index] & EHCI_HOST_ITD_TRANSACTION_LEN_MASK) >> + EHCI_HOST_ITD_TRANSACTION_LEN_SHIFT); + } + + USB_HostEhciRemoveFromFrame(ehciInstance, (uint32_t)itdPointer, + itdPointer->frameEntryIndex); /* remove from the inserted frame list */ + + /* release itd */ + /* USB_HostEhciLock(); */ + USB_HostEhciZeroMem((uint32_t *)itdPointer, sizeof(usb_host_ehci_itd_t) >> 2); + itdPointer->nextLinkPointer = (uint32_t)ehciInstance->ehciItdList; + ehciInstance->ehciItdList = itdPointer; + ehciInstance->ehciItdNumber++; + /* USB_HostEhciUnlock(); */ + + if (itdPointer == endItdPointer) + { + break; + } + itdPointer = itdPointer->nextItdPointer; + } + + return doneLength; +} + +static usb_status_t USB_HostEhciItdArrayDeinit(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer) +{ + usb_host_ehci_iso_t *isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh; + usb_host_transfer_t *transfer; + usb_host_transfer_t *nextTransfer; + uint32_t doneLength = 0; + + /* firstly remove the transfer (because host task may occupy to access the resource) */ + USB_HostEhciLock(); + transfer = isoPointer->ehciTransferHead; + isoPointer->ehciTransferHead = isoPointer->ehciTransferTail = NULL; + USB_HostEhciUnlock(); + + while (transfer != NULL) + { + nextTransfer = transfer->next; + doneLength = 0; + /* remove itd from frame list and release itd */ + doneLength = USB_HostEhciItdArrayRelease(ehciInstance, (usb_host_ehci_itd_t *)transfer->union1.unitHead, + (usb_host_ehci_itd_t *)transfer->union2.unitTail); + + /* transfer callback */ + if (ehciPipePointer->pipeCommon.direction == USB_OUT) + { + doneLength = transfer->transferLength; + } + transfer->transferSofar = doneLength; + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferCancel); + + /* next transfer */ + transfer = nextTransfer; + } + + return kStatus_USB_Success; +} +#endif /* USB_HOST_CONFIG_EHCI_MAX_ITD */ + +static usb_status_t USB_HostEhciOpenControlBulk(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer) +{ + usb_host_ehci_qh_t *qhPointer; + + if (USB_HostEhciQhInit(ehciInstance, ehciPipePointer) != kStatus_USB_Success) /* initialize control/bulk qh */ + { + return kStatus_USB_Error; + } + + qhPointer = (usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; + + /* add qh to async */ + qhPointer->horizontalLinkPointer = ehciInstance->shedFirstQh->horizontalLinkPointer; + ehciInstance->shedFirstQh->horizontalLinkPointer = ((uint32_t)qhPointer | EHCI_HOST_POINTER_TYPE_QH); + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostEhciCloseControlBulk(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer) +{ + volatile usb_host_ehci_qh_t *vltPrevQhPointer; + uint32_t horizontalLinkValue; + + /* remove qh from async schedule */ + if ((ehciInstance->shedFirstQh->horizontalLinkPointer & EHCI_HOST_POINTER_ADDRESS_MASK) == + (uint32_t)ehciPipePointer->ehciQh) /* the removing qh is the first qh in the async list */ + { + USB_HostEhciStopAsync(ehciInstance); + ehciInstance->shedFirstQh->horizontalLinkPointer = + ((usb_host_ehci_qh_t *)ehciPipePointer->ehciQh)->horizontalLinkPointer; + USB_HostEhciStartAsync(ehciInstance); + } + else + { + /* search for the removing qh from the async list */ + vltPrevQhPointer = ehciInstance->shedFirstQh; + while (vltPrevQhPointer != NULL) + { + horizontalLinkValue = vltPrevQhPointer->horizontalLinkPointer; + if ((horizontalLinkValue & EHCI_HOST_T_INVALID_VALUE) || + ((horizontalLinkValue & EHCI_HOST_POINTER_ADDRESS_MASK) == (uint32_t)ehciPipePointer->ehciQh) || + ((horizontalLinkValue & EHCI_HOST_POINTER_ADDRESS_MASK) == (uint32_t)ehciInstance->shedFirstQh)) + { + break; + } + + vltPrevQhPointer = (volatile usb_host_ehci_qh_t *)(horizontalLinkValue & EHCI_HOST_POINTER_ADDRESS_MASK); + } + + /* remove the qh from async list */ + if ((vltPrevQhPointer != NULL) && (!(horizontalLinkValue & EHCI_HOST_T_INVALID_VALUE)) && + ((horizontalLinkValue & EHCI_HOST_POINTER_ADDRESS_MASK) == (uint32_t)ehciPipePointer->ehciQh)) + { + USB_HostEhciStopAsync(ehciInstance); + vltPrevQhPointer->horizontalLinkPointer = + ((usb_host_ehci_qh_t *)ehciPipePointer->ehciQh)->horizontalLinkPointer; + USB_HostEhciStartAsync(ehciInstance); + } + } + ((usb_host_ehci_qh_t *)ehciPipePointer->ehciQh)->horizontalLinkPointer = + EHCI_HOST_T_INVALID_VALUE; /* invalid next qh link */ + return USB_HostEhciQhDeinit(ehciInstance, ehciPipePointer); /* de-initialize qh and release qh */ +} + +static usb_status_t USB_HostEhciOpenInterrupt(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer) +{ + usb_status_t status = kStatus_USB_Success; + uint32_t frameIndex; + + /* allocate bandwidth */ + if (ehciInstance->firstDeviceSpeed == USB_SPEED_HIGH) + { + status = USB_HostBandwidthHsHostAllocateInterrupt(ehciInstance, ehciPipePointer); /* host works as high-speed */ + } + else + { + status = USB_HostBandwidthFslsHostAllocate(ehciInstance, + ehciPipePointer); /* host works as full-speed or low-speed */ + } + + if (status != kStatus_USB_Success) + { + return status; + } + if (USB_HostEhciQhInit(ehciInstance, ehciPipePointer) != kStatus_USB_Success) + { + return kStatus_USB_Error; + } + + /* insert QH to frame list */ + for (frameIndex = ehciPipePointer->startFrame; frameIndex < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE; + frameIndex += ((ehciPipePointer->uframeInterval + 7) / 8)) + { + USB_HostEhciAddQhToFrame(ehciInstance, (uint32_t)ehciPipePointer->ehciQh, frameIndex, + ehciPipePointer->uframeInterval); + } + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostEhciCloseInterrupt(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer) +{ + uint32_t frameIndex; + + /* remove from frame list */ + for (frameIndex = ehciPipePointer->startFrame; frameIndex < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE; + frameIndex += ((ehciPipePointer->uframeInterval + 7) / 8)) + { + USB_HostEhciRemoveFromFrame(ehciInstance, (uint32_t)ehciPipePointer->ehciQh, frameIndex); + } + ((usb_host_ehci_qh_t *)ehciPipePointer->ehciQh)->horizontalLinkPointer |= + EHCI_HOST_T_INVALID_VALUE; /* invalid next qh link */ + + return USB_HostEhciQhDeinit(ehciInstance, ehciPipePointer); /* de-initilaze qh and release qh */ +} + +#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \ + ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) + +static usb_status_t USB_HostEhciOpenIso(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer) +{ + usb_host_ehci_iso_t *isoPointer; + usb_status_t status = kStatus_USB_Success; + + if (ehciInstance->firstDeviceSpeed == USB_SPEED_HIGH) + { + status = USB_HostBandwidthHsHostAllocateIso( + ehciInstance, ehciPipePointer); /* allocate iso bandwidth when host works as high-speed */ + } + else + { + status = USB_HostBandwidthFslsHostAllocate( + ehciInstance, ehciPipePointer); /* allocate iso bandwidth when host works as full-speed or low-speed */ + } + + if (status != kStatus_USB_Success) + { + return status; + } + + /* get usb_host_ehci_iso_t */ + if (ehciInstance->ehciIsoList == NULL) + { + return kStatus_USB_Error; + } + USB_HostEhciLock(); + isoPointer = ehciInstance->ehciIsoList; + ehciInstance->ehciIsoList = ehciInstance->ehciIsoList->next; + USB_HostEhciUnlock(); + isoPointer->lastLinkFrame = 0xFFFF; + ehciPipePointer->ehciQh = isoPointer; + + return status; +} + +static usb_status_t USB_HostEhciCloseIso(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer) +{ + usb_host_ehci_iso_t *isoPointer; + uint32_t speed; + + isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh; + + if (isoPointer->ehciTransferHead != NULL) + { + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, + &speed); + if (speed == USB_SPEED_HIGH) + { +#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) + USB_HostEhciItdArrayDeinit(ehciInstance, ehciPipePointer); /* de-initialize itd list and free them */ +#endif + } + else + { +#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)) + USB_HostEhciSitdArrayDeinit(ehciInstance, ehciPipePointer); /* de-initialize sitd list and free them */ +#endif + } + } + + /* release usb_host_ehci_iso_t */ + USB_HostEhciLock(); + isoPointer->next = ehciInstance->ehciIsoList; + ehciInstance->ehciIsoList = isoPointer; + USB_HostEhciUnlock(); + return kStatus_USB_Success; +} + +#endif + +static usb_status_t USB_HostEhciResetIP(usb_host_ehci_instance_t *ehciInstance) +{ + /* reset controller */ + ehciInstance->ehciIpBase->USBCMD = USBHS_USBCMD_RST_MASK; + while (ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_RST_MASK) + { + } +/* set host mode */ +#if (ENDIANNESS == USB_LITTLE_ENDIAN) + ehciInstance->ehciIpBase->USBMODE |= 0x03; +#else + ehciInstance->ehciIpBase->USBMODE |= (0x03 | (0x01 << USBHS_USBMODE_ES_SHIFT)); +#endif + /* check frame list size */ + if (!(ehciInstance->ehciIpBase->HCCPARAMS & USBHS_HCCPARAMS_PFL_MASK)) + { +#if ((USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE < 8) || (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE > 1024)) + return kStatus_USB_Error; +#endif +#if (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE & (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE - 1)) + return kStatus_USB_Error; /* frame size must be 1024/512/256/128/64/32/16/8 */ +#endif + } + return kStatus_USB_Success; +} + +static usb_status_t USB_HostEhciStartIP(usb_host_ehci_instance_t *ehciInstance) +{ + uint32_t tmp = 0; + + if (ehciInstance->ehciIpBase->HCSPARAMS & USBHS_HCSPARAMS_PPC_MASK) /* Ports have power port switches */ + { + /* only has one port */ + tmp = ehciInstance->ehciIpBase->PORTSC1; + tmp &= (~EHCI_PORTSC1_W1_BITS); + ehciInstance->ehciIpBase->PORTSC1 = (tmp | USBHS_PORTSC1_PP_MASK); /* turn on port power */ + } + + /* set frame list size */ + if (ehciInstance->ehciIpBase->HCCPARAMS & USBHS_HCCPARAMS_PFL_MASK) + { +#if (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE <= 64) + ehciInstance->ehciIpBase->USBCMD |= (USBHS_USBCMD_FS2_MASK); +#if (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 64) + ehciInstance->ehciIpBase->USBCMD |= (0x00 << USBHS_USBCMD_FS_SHIFT); +#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 32) + ehciInstance->ehciIpBase->USBCMD |= (0x01 << USBHS_USBCMD_FS_SHIFT); +#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 16) + ehciInstance->ehciIpBase->USBCMD |= (0x02 << USBHS_USBCMD_FS_SHIFT); +#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 8) + ehciInstance->ehciIpBase->USBCMD |= (0x03 << USBHS_USBCMD_FS_SHIFT); +#endif +#else +#if (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 1024) + ehciInstance->ehciIpBase->USBCMD |= (0x00 << USBHS_USBCMD_FS_SHIFT); +#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 512) + ehciInstance->ehciIpBase->USBCMD |= (0x01 << USBHS_USBCMD_FS_SHIFT); +#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 256) + ehciInstance->ehciIpBase->USBCMD |= (0x02 << USBHS_USBCMD_FS_SHIFT); +#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 128) + ehciInstance->ehciIpBase->USBCMD |= (0x03 << USBHS_USBCMD_FS_SHIFT); +#endif +#endif + } + + /* start the controller */ + ehciInstance->ehciIpBase->USBCMD = USBHS_USBCMD_RS_MASK; + + /* set timer0 */ + ehciInstance->ehciIpBase->GPTIMER0LD = (100 * 1000 - 1); /* 100ms */ + + /* enable interrupt (USB interrupt enable + USB error interrupt enable + port change detect enable + system error + * enable + interrupt on async advance enable) + general purpos Timer 0 Interrupt enable */ + ehciInstance->ehciIpBase->USBINTR |= (0x1000037); + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostEhciCancelPipe(usb_host_ehci_instance_t *ehciInstance, + usb_host_ehci_pipe_t *ehciPipePointer, + usb_host_transfer_t *transfer) +{ + usb_host_ehci_qh_t *qhPointer; +#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \ + ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) + usb_host_ehci_iso_t *isoPointer; + uint32_t speed; +#endif + uint8_t cancelPipe = 0; + + switch (ehciPipePointer->pipeCommon.pipeType) + { + case USB_ENDPOINT_BULK: + case USB_ENDPOINT_CONTROL: + case USB_ENDPOINT_INTERRUPT: + qhPointer = (usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; + if (qhPointer->ehciTransferHead == NULL) /* there is no transfer to cancel */ + { + return kStatus_USB_Success; + } + if (transfer != NULL) + { + if ((qhPointer->ehciTransferHead == transfer) && + (qhPointer->ehciTransferHead == qhPointer->ehciTransferTail)) /* only has this one transfer */ + { + cancelPipe = 1; + } + else + { + cancelPipe = 0; + } + } + else + { + cancelPipe = 1; + } + if (cancelPipe == 1) /* cancel all pipe */ + { + USB_HostEhciQhQtdListDeinit(ehciInstance, ehciPipePointer); /* release all the qtd */ + } + else /* cancel one transfer */ + { + USB_HostEhciTransferQtdListDeinit(ehciInstance, ehciPipePointer, transfer); + } + break; + +#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \ + ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) + case USB_ENDPOINT_ISOCHRONOUS: + isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh; + if (isoPointer->ehciTransferHead == NULL) /* there is no transfer to cancel */ + { + return kStatus_USB_Success; + } + /* cancel all pipe, don't implement canceling transfer for iso */ + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, + &speed); + if (speed == USB_SPEED_HIGH) + { +#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) + USB_HostEhciItdArrayDeinit(ehciInstance, ehciPipePointer); /* de-initialize itd */ +#endif + } + else + { +#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)) + USB_HostEhciSitdArrayDeinit(ehciInstance, ehciPipePointer); /* de-initialize sitd */ +#endif + } + break; +#endif + + default: + break; + } + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostEhciControlBus(usb_host_ehci_instance_t *ehciInstance, uint8_t busControl) +{ + usb_status_t status = kStatus_USB_Success; + uint32_t portScRegister; + + switch (busControl) + { + case kUSB_HostBusReset: + /* reset port */ + portScRegister = ehciInstance->ehciIpBase->PORTSC1; + portScRegister &= (~EHCI_PORTSC1_W1_BITS); + ehciInstance->ehciIpBase->PORTSC1 = (portScRegister | USBHS_PORTSC1_PR_MASK); + while (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_PR_MASK) + { + } + break; + + case kUSB_HostBusRestart: + ehciInstance->deviceAttached = kEHCIDeviceDetached; + ehciInstance->ehciIpBase->USBINTR |= (USBHS_USBINTR_PCE_MASK); /* enable ehci port change interrupt */ + break; + + case kUSB_HostBusEnableAttach: /* enable device attach */ + if (ehciInstance->deviceAttached == kEHCIDeviceDetached) + { + ehciInstance->ehciIpBase->USBINTR |= (USBHS_USBINTR_PCE_MASK); /* enable ehci port change interrupt */ + } + break; + + case kUSB_HostBusDisableAttach: /* disable device attach */ + ehciInstance->ehciIpBase->USBINTR &= (~USBHS_USBINTR_PCE_MASK); /* disable ehci port change interrupt */ + break; +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + case kUSB_HostBusSuspend: + if (ehciInstance->ehciIpBase->PORTSC1 && USBHS_PORTSC1_CCS_MASK) + { + /* set timer1 */ + ehciInstance->ehciIpBase->GPTIMER1LD = (1 * 1000); /* 1ms */ + ehciInstance->ehciIpBase->GPTIMER1CTL |= + (USBHS_GPTIMER0CTL_RUN_MASK | USBHS_GPTIMER0CTL_MODE_MASK | USBHS_GPTIMER0CTL_RST_MASK); + + USB_HostEhciStopAsync(ehciInstance); + USB_HostEhciStopPeriodic(ehciInstance); + while (ehciInstance->ehciIpBase->USBSTS & (USBHS_USBSTS_PS_MASK | USBHS_USBSTS_AS_MASK)) + { + __ASM("nop"); + } + ehciInstance->ehciIpBase->PORTSC1 &= ~USBHS_PORTSC1_WKCN_MASK; + ehciInstance->ehciIpBase->PORTSC1 |= USBHS_PORTSC1_WKDS_MASK; + ehciInstance->ehciIpBase->PORTSC1 |= (USBHS_PORTSC1_SUSP_MASK); /* Suspend the device */ + + ehciInstance->matchTick = 0U; + ehciInstance->ehciIpBase->USBINTR |= (USBHS_USBINTR_TIE1_MASK); + ehciInstance->busSuspendStatus = kBus_EhciStartSuspend; + } + else + { + status = kStatus_USB_Error; + } + break; + case kUSB_HostBusResume: + ehciInstance->ehciIpBase->PORTSC1 &= ~(USBHS_PORTSC1_SUSP_MASK); /* Clear Suspend bit */ + ehciInstance->ehciIpBase->PORTSC1 &= ~USBHS_PORTSC1_PHCD_MASK; + if (ehciInstance->deviceAttached != kEHCIDeviceDetached) + { + ehciInstance->busSuspendStatus = kBus_EhciStartResume; +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + ehciInstance->registerNcBase->USB_OTGn_CTRL &= ~USBNC_USB_OTGn_CTRL_WIE_MASK; +#else + ehciInstance->ehciIpBase->USBGENCTRL &= ~USBHS_USBGENCTRL_WU_IE_MASK; +#endif + ehciInstance->ehciIpBase->USBCMD |= (USBHS_USBCMD_RS_MASK); + ehciInstance->ehciIpBase->PORTSC1 |= (USBHS_PORTSC1_FPR_MASK); /* Resume the device */ + } + else + { + status = kStatus_USB_Error; + } + break; +#endif + default: + status = kStatus_USB_Error; + break; + } + return status; +} + +void USB_HostEhciTransactionDone(usb_host_ehci_instance_t *ehciInstance) +{ + /* process async QH */ + usb_host_ehci_pipe_t *ehciPipePointer; + usb_host_ehci_pipe_t *ehciClearPipePointer = NULL; + volatile usb_host_ehci_qh_t *vltQhPointer; + volatile usb_host_ehci_qtd_t *vltQtdPointer; + usb_host_transfer_t *transfer; + usb_host_transfer_t *nextTransfer; + uint32_t qtdStatus = 0; +#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) + volatile usb_host_ehci_itd_t *vltItdPointer; + uint8_t index = 0; +#endif +#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)) + volatile usb_host_ehci_sitd_t *vltSitdPointer; +#endif +#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \ + ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) + usb_host_ehci_iso_t *isoPointer; + uint32_t dataLength; + uint32_t speed; +#endif + + ehciPipePointer = ehciInstance->ehciRunningPipeList; /* check all the running pipes */ + while (ehciPipePointer != NULL) + { + switch (ehciPipePointer->pipeCommon.pipeType) + { + case USB_ENDPOINT_BULK: + case USB_ENDPOINT_INTERRUPT: + case USB_ENDPOINT_CONTROL: + vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; /* pipe's qh */ + transfer = vltQhPointer->ehciTransferHead; /* qh's transfer */ + + while (transfer != NULL) + { + nextTransfer = transfer->next; + /* normal case */ + vltQtdPointer = (volatile usb_host_ehci_qtd_t *)transfer->union2.unitTail; + if ((vltQtdPointer->transferResults[0] & (EHCI_HOST_QTD_IOC_MASK)) && + (!(vltQtdPointer->transferResults[0] & + EHCI_HOST_QTD_STATUS_ACTIVE_MASK))) /* transfer is done */ + { + qtdStatus = (vltQtdPointer->transferResults[0] & EHCI_HOST_QTD_STATUS_ERROR_MASK); + transfer->transferSofar = + USB_HostEhciQtdListRelease(ehciInstance, (usb_host_ehci_qtd_t *)(transfer->union1.unitHead), + (usb_host_ehci_qtd_t *)(transfer->union2.unitTail)); + transfer->transferSofar = (transfer->transferLength < transfer->transferSofar) ? + 0 : + (transfer->transferLength - transfer->transferSofar); + + vltQhPointer->ehciTransferHead = transfer->next; + vltQhPointer->timeOutLabel = 0; + vltQhPointer->timeOutValue = USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE; + if (qtdStatus) /* has errors */ + { + if (!(vltQhPointer->transferOverlayResults[0] & EHCI_HOST_QTD_STATUS_ACTIVE_MASK)) + { + vltQhPointer->transferOverlayResults[0] &= + (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */ + } + if (qtdStatus & EHCI_HOST_QH_STATUS_NOSTALL_ERROR_MASK) + { + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, + kStatus_USB_TransferFailed); /* transfer fail */ + } + else + { + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferStall); + } + } + else + { + if ((ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_CONTROL) && + (transfer->setupPacket->bRequest == USB_REQUEST_STANDARD_CLEAR_FEATURE) && + (transfer->setupPacket->bmRequestType == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) && + ((USB_SHORT_FROM_LITTLE_ENDIAN(transfer->setupPacket->wValue) & 0x00FFu) == + USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT)) + { + ehciClearPipePointer = ehciInstance->ehciRunningPipeList; + while (ehciClearPipePointer != NULL) + { + /* only compute bulk and interrupt pipe */ + if (((ehciClearPipePointer->pipeCommon.endpointAddress | + (ehciClearPipePointer->pipeCommon.direction + << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) == + (uint8_t)(USB_SHORT_FROM_LITTLE_ENDIAN(transfer->setupPacket->wIndex))) && + (ehciClearPipePointer->pipeCommon.deviceHandle == + ehciPipePointer->pipeCommon.deviceHandle)) + { + break; + } + ehciClearPipePointer = + (usb_host_ehci_pipe_t *)ehciClearPipePointer->pipeCommon.next; + } + + if ((ehciClearPipePointer != NULL) && + ((ehciClearPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT) || + (ehciClearPipePointer->pipeCommon.pipeType == USB_ENDPOINT_BULK))) + { + ((volatile usb_host_ehci_qh_t *)(ehciClearPipePointer->ehciQh)) + ->transferOverlayResults[0] &= (~EHCI_HOST_QTD_DT_MASK); + } + } + + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, + kStatus_USB_Success); /* transfer success */ + } + } + else if ((!(vltQhPointer->transferOverlayResults[0] & EHCI_HOST_QTD_STATUS_ACTIVE_MASK)) && + (vltQhPointer->transferOverlayResults[0] & + EHCI_HOST_QH_STATUS_ERROR_MASK)) /* there is error and transfer is done */ + { + qtdStatus = (vltQhPointer->transferOverlayResults[0] & EHCI_HOST_QH_STATUS_ERROR_MASK); + vltQtdPointer = (volatile usb_host_ehci_qtd_t *)(vltQhPointer->currentQtdPointer); + + if (((uint32_t)vltQtdPointer & EHCI_HOST_T_INVALID_VALUE) || + (vltQtdPointer == NULL)) /* the error status is unreasonable */ + { + vltQhPointer->transferOverlayResults[0] &= + (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */ + } + else + { + /* remove qtd from qh */ + while ((vltQtdPointer != NULL) && (!(vltQtdPointer->transferResults[0] & + EHCI_HOST_QTD_IOC_MASK))) /* find the IOC qtd */ + { + vltQtdPointer = (volatile usb_host_ehci_qtd_t *)vltQtdPointer->nextQtdPointer; + } + + vltQhPointer->nextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + vltQhPointer->currentQtdPointer = EHCI_HOST_T_INVALID_VALUE; + vltQhPointer->transferOverlayResults[0] &= + (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */ + if (vltQtdPointer != NULL) + { + vltQhPointer->nextQtdPointer = vltQtdPointer->nextQtdPointer; + } + + transfer->transferSofar = USB_HostEhciQtdListRelease( + ehciInstance, (usb_host_ehci_qtd_t *)(transfer->union1.unitHead), + (usb_host_ehci_qtd_t *)(transfer->union2.unitTail)); + transfer->transferSofar = (transfer->transferLength < transfer->transferSofar) ? + 0 : + (transfer->transferLength - transfer->transferSofar); + vltQhPointer->ehciTransferHead = transfer->next; + vltQhPointer->timeOutLabel = 0; + vltQhPointer->timeOutValue = USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE; + if (qtdStatus & EHCI_HOST_QH_STATUS_NOSTALL_ERROR_MASK) + { + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, + kStatus_USB_TransferFailed); /* transfer fail */ + } + else + { + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, + kStatus_USB_TransferStall); /* transfer stall */ + } + } + } + else + { + break; + } + transfer = nextTransfer; + } + break; +#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \ + ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) + case USB_ENDPOINT_ISOCHRONOUS: + qtdStatus = 0; /* qtdStatus means break here, because there is only one break in while for misra */ + isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh; /* pipe's usb_host_ehci_iso_t */ + transfer = isoPointer->ehciTransferHead; /* usb_host_ehci_iso_t's transfer */ + while (transfer != NULL) + { + nextTransfer = transfer->next; + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, + kUSB_HostGetDeviceSpeed, &speed); + if (speed == USB_SPEED_HIGH) + { +#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) + vltItdPointer = + (volatile usb_host_ehci_itd_t *)(transfer->union2.unitTail); /* transfer's last itd */ + for (index = 0; index < 8; ++index) + { + if (vltItdPointer->transactions[index] & EHCI_HOST_ITD_STATUS_ACTIVE_MASK) + { + break; + } + } + if (index == 8) /* transfer is done */ + { + /* remove itd from frame list and release itd */ + dataLength = USB_HostEhciItdArrayRelease(ehciInstance, + (usb_host_ehci_itd_t *)transfer->union1.unitHead, + (usb_host_ehci_itd_t *)transfer->union2.unitTail); + transfer->transferSofar = dataLength; + isoPointer->ehciTransferHead = transfer->next; + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, + kStatus_USB_Success); /* transfer callback success */ + /* TODO: iso callback error */ + } + else + { + qtdStatus = 1; /* break */ + } +#endif + } + else + { +#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)) + vltSitdPointer = + (volatile usb_host_ehci_sitd_t *)(transfer->union2.unitTail); /* transfer's last sitd */ + if (!(vltSitdPointer->transferResults[0] & + EHCI_HOST_SITD_STATUS_ACTIVE_MASK)) /* transfer is done */ + { + /* remove sitd from frame list and release itd */ + dataLength = USB_HostEhciSitdArrayRelease( + ehciInstance, (usb_host_ehci_sitd_t *)transfer->union1.unitHead, + (usb_host_ehci_sitd_t *)transfer->union2.unitTail); + transfer->transferSofar = dataLength; + isoPointer->ehciTransferHead = transfer->next; + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, + kStatus_USB_Success); /* transfer callback success */ + /* TODO: iso callback error */ + } + else + { + qtdStatus = 1; /* break */ + } +#endif + } + if (qtdStatus == 1) + { + break; + } + transfer = nextTransfer; + } + break; +#endif + + default: + break; + } + ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next; + } +} + +static void USB_HostEhciPortChange(usb_host_ehci_instance_t *ehciInstance) +{ + /* note: only has one port */ + uint32_t portScRegister = ehciInstance->ehciIpBase->PORTSC1; + int32_t sofStart = 0; + int32_t sofCount = 0; + uint32_t index; + + if (portScRegister & USBHS_PORTSC1_CSC_MASK) /* connection status change */ + { + sofStart = (int32_t)(ehciInstance->ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE); + + /* process CSC bit */ + while (1) + { + portScRegister = ehciInstance->ehciIpBase->PORTSC1; + if (portScRegister & USBHS_PORTSC1_CSC_MASK) + { + /* clear csc bit */ + portScRegister = ehciInstance->ehciIpBase->PORTSC1; + portScRegister &= (~EHCI_PORTSC1_W1_BITS); + ehciInstance->ehciIpBase->PORTSC1 = (portScRegister | USBHS_PORTSC1_CSC_MASK); + } + sofCount = (int32_t)(ehciInstance->ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE); + if (((sofCount - sofStart + EHCI_MAX_UFRAME_VALUE + 1) & EHCI_MAX_UFRAME_VALUE) > + (1 * 8)) /* delay 1ms to clear CSC */ + { + break; + } + } + } + + /* process CCS bit */ + portScRegister = ehciInstance->ehciIpBase->PORTSC1; + if (portScRegister & USBHS_PORTSC1_CCS_MASK) /* process attach */ + { + if ((ehciInstance->deviceAttached == kEHCIDevicePhyAttached) || + (ehciInstance->deviceAttached == kEHCIDeviceAttached)) + { + return; + } +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + ehciInstance->busSuspendStatus = kBus_EhciIdle; + ehciInstance->ehciIpBase->USBINTR &= ~(USBHS_USBINTR_TIE1_MASK); +#endif + for (index = 0; index < USB_HOST_EHCI_PORT_CONNECT_DEBOUNCE_DELAY; ++index) + { + USB_HostEhciDelay(ehciInstance->ehciIpBase, 1); + if (!(ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_CCS_MASK)) + { + break; + } + } + if (index < USB_HOST_EHCI_PORT_CONNECT_DEBOUNCE_DELAY) /* CCS is cleared */ + { + ehciInstance->deviceAttached = kEHCIDeviceDetached; + return; + } + /* reset port */ + portScRegister = ehciInstance->ehciIpBase->PORTSC1; + portScRegister &= (~EHCI_PORTSC1_W1_BITS); + ehciInstance->ehciIpBase->PORTSC1 = (portScRegister | USBHS_PORTSC1_PR_MASK); + while (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_PR_MASK) + { + } + ehciInstance->firstDeviceSpeed = + ((ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_PSPD_MASK) >> USBHS_PORTSC1_PSPD_SHIFT); + /* enable ehci phy disconnection */ + if (ehciInstance->firstDeviceSpeed == USB_SPEED_HIGH) + { + USB_EhcihostPhyDisconnectDetectCmd(ehciInstance->controllerId, 1); + } + + /* wait for reset */ + USB_HostEhciDelay(ehciInstance->ehciIpBase, USB_HOST_EHCI_PORT_RESET_DELAY); + /* process attach */ + USB_OsaEventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_DEVICE_ATTACH); + /* gpt timer start */ + ehciInstance->ehciIpBase->GPTIMER0CTL |= + (USBHS_GPTIMER0CTL_RUN_MASK | USBHS_GPTIMER0CTL_MODE_MASK | USBHS_GPTIMER0CTL_RST_MASK); + ehciInstance->deviceAttached = kEHCIDevicePhyAttached; + } + else + { + if ((ehciInstance->deviceAttached == kEHCIDevicePhyAttached) || + (ehciInstance->deviceAttached == kEHCIDeviceAttached)) + { +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + ehciInstance->busSuspendStatus = kBus_EhciIdle; + ehciInstance->ehciIpBase->USBINTR &= ~(USBHS_USBINTR_TIE1_MASK); +#endif + /* disable ehci phy disconnection */ + USB_EhcihostPhyDisconnectDetectCmd(ehciInstance->controllerId, 0); + /* disable async and periodic */ + USB_HostEhciStopAsync(ehciInstance); + USB_HostEhciStopPeriodic(ehciInstance); + USB_OsaEventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_DEVICE_DETACH); + } + } +} + +static void USB_HostEhciTimer0(usb_host_ehci_instance_t *ehciInstance) +{ + volatile usb_host_ehci_qh_t *vltQhPointer; + volatile usb_host_ehci_qtd_t *vltQtdPointer; + usb_host_transfer_t *transfer; + uint32_t backValue; + volatile uint32_t *totalBytesAddress = NULL; + usb_host_ehci_pipe_t *ehciPipePointer = ehciInstance->ehciRunningPipeList; + uint8_t timeoutLabel; + + while (ehciPipePointer != NULL) + { + switch (ehciPipePointer->pipeCommon.pipeType) + { + case USB_ENDPOINT_BULK: + case USB_ENDPOINT_CONTROL: + vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; /* pipe's qh */ + transfer = vltQhPointer->ehciTransferHead; /* qh's transfer */ + if ((transfer != NULL)) /* there is transfering data */ + { + timeoutLabel = 0; + if (ehciInstance->deviceAttached != kEHCIDeviceAttached) + { + vltQtdPointer = (volatile usb_host_ehci_qtd_t *)transfer->union2.unitTail; + + vltQhPointer->nextQtdPointer = EHCI_HOST_T_INVALID_VALUE; /* invalid next qtd */ + vltQhPointer->transferOverlayResults[0] &= + (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */ + timeoutLabel = 1; + } + else + { + if (vltQhPointer->transferOverlayResults[0] & EHCI_HOST_QTD_STATUS_ACTIVE_MASK) + { + vltQtdPointer = (volatile usb_host_ehci_qtd_t *)vltQhPointer->currentQtdPointer; + totalBytesAddress = &(vltQhPointer->transferOverlayResults[0]); + } + else + { + vltQtdPointer = (volatile usb_host_ehci_qtd_t *)transfer->union2.unitTail; + totalBytesAddress = ((uint32_t *)vltQtdPointer + 2); + } + + backValue = + (((*totalBytesAddress) & EHCI_HOST_QTD_TOTAL_BYTES_MASK) >> + EHCI_HOST_QTD_TOTAL_BYTES_SHIFT); /* backValue is used for total bytes to transfer */ + if (vltQhPointer->timeOutLabel != backValue) /* use total bytes to reflect the time out */ + { + vltQhPointer->timeOutValue = USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE; + vltQhPointer->timeOutLabel = backValue; + } + else + { + /* time out when the total bytes don't change for the duration + * USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE + */ + (vltQhPointer->timeOutValue)--; + if (vltQhPointer->timeOutValue == 0) + { + /* stop the qh schedule */ + USB_HostEhciStopAsync(ehciInstance); + if (backValue != (((*totalBytesAddress) & EHCI_HOST_QTD_TOTAL_BYTES_MASK) >> + EHCI_HOST_QTD_TOTAL_BYTES_SHIFT)) + { + USB_HostEhciStartAsync(ehciInstance); + } + else + { + vltQhPointer->nextQtdPointer = EHCI_HOST_T_INVALID_VALUE; /* invalid next qtd */ + vltQhPointer->transferOverlayResults[0] &= + (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */ + USB_HostEhciStartAsync(ehciInstance); + timeoutLabel = 1; + } + } + } + } + + if (timeoutLabel == 1) + { + /* remove qtd from qh */ + while ((vltQtdPointer != NULL) && + (!(vltQtdPointer->transferResults[0] & EHCI_HOST_QTD_IOC_MASK)) && + (vltQtdPointer != (usb_host_ehci_qtd_t *)vltQhPointer->ehciTransferTail)) + { + vltQtdPointer = (volatile usb_host_ehci_qtd_t *)vltQtdPointer->nextQtdPointer; + } + if ((vltQtdPointer != NULL) && (!(vltQtdPointer->nextQtdPointer & EHCI_HOST_T_INVALID_VALUE))) + { + vltQhPointer->nextQtdPointer = + vltQtdPointer->nextQtdPointer; /* start qh if there are other qtd that don't belong to + the transfer */ + } + transfer->transferSofar = + USB_HostEhciQtdListRelease(ehciInstance, (usb_host_ehci_qtd_t *)(transfer->union1.unitHead), + (usb_host_ehci_qtd_t *)(transfer->union2.unitTail)); + transfer->transferSofar = (transfer->transferLength < transfer->transferSofar) ? + 0 : + (transfer->transferLength - transfer->transferSofar); + + vltQhPointer->ehciTransferHead = transfer->next; + vltQhPointer->timeOutValue = USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE; + /* callback function is different from the current condition */ + transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferFailed); + } + } + break; + default: + break; + } + ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next; + } +} + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) +static void USB_HostEhciTimer1(usb_host_ehci_instance_t *ehciInstance) +{ + if (ehciInstance->deviceAttached != kEHCIDeviceDetached) + { + if (kBus_EhciStartSuspend == ehciInstance->busSuspendStatus) + { + usb_host_instance_t *hostPointer = (usb_host_instance_t *)ehciInstance->hostHandle; + + if (0 == ehciInstance->matchTick) + { + ehciInstance->matchTick = hostPointer->hwTick; + } + else + { + if ((hostPointer->hwTick - ehciInstance->matchTick) >= 5) + { + ehciInstance->ehciIpBase->USBCMD &= ~USBHS_USBCMD_RS_MASK; + ehciInstance->ehciIpBase->USBSTS |= USBHS_USBSTS_SRI_MASK; +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) +#if 0 + ehciInstance->registerPhyBase->CTRL |= USBPHY_CTRL_ENVBUSCHG_WKUP_MASK + | USBPHY_CTRL_ENIDCHG_WKUP_MASK + | USBPHY_CTRL_ENDPDMCHG_WKUP_MASK + | USBPHY_CTRL_ENIRQRESUMEDETECT_MASK + ; +#endif +#endif + ehciInstance->ehciIpBase->PORTSC1 |= USBHS_PORTSC1_PHCD_MASK; + + ehciInstance->registerPhyBase->PWD = 0xFFFFFFFFU; + + while (ehciInstance->registerPhyBase->CTRL & (USBPHY_CTRL_UTMI_SUSPENDM_MASK)) + { + __ASM("nop"); + } + +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + ehciInstance->registerNcBase->USB_OTGn_CTRL |= USBNC_USB_OTGn_CTRL_WKUP_ID_EN_MASK | + USBNC_USB_OTGn_CTRL_WKUP_VBUS_EN_MASK | + USBNC_USB_OTGn_CTRL_WKUP_DPDM_EN_MASK; + ehciInstance->registerNcBase->USB_OTGn_CTRL |= USBNC_USB_OTGn_CTRL_WIE_MASK; +#else + ehciInstance->ehciIpBase->USBGENCTRL = USBHS_USBGENCTRL_WU_IE_MASK; +#endif + ehciInstance->registerPhyBase->CTRL |= USBPHY_CTRL_CLKGATE_MASK; + hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL, + kUSB_HostEventSuspended); /* call host callback function */ + ehciInstance->busSuspendStatus = kBus_EhciSuspended; + } + } + } + else if (kBus_EhciStartResume == ehciInstance->busSuspendStatus) + { + usb_host_instance_t *hostPointer = (usb_host_instance_t *)ehciInstance->hostHandle; + if (!(ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_FPR_MASK)) + { + ehciInstance->ehciIpBase->PORTSC1 &= ~USBHS_PORTSC1_WKDS_MASK; + if (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_CCS_MASK) + { + USB_HostEhciStartAsync(ehciInstance); + USB_HostEhciStartPeriodic(ehciInstance); + } + hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL, + kUSB_HostEventResumed); /* call host callback function */ + hostPointer->suspendedDevice = NULL; + ehciInstance->busSuspendStatus = kBus_EhciIdle; + ehciInstance->ehciIpBase->USBINTR &= ~(USBHS_USBINTR_TIE1_MASK); + } + } + else + { + } + } + else + { + ehciInstance->busSuspendStatus = kBus_EhciIdle; + ehciInstance->ehciIpBase->USBINTR &= ~(USBHS_USBINTR_TIE1_MASK); + } +} +#endif + +void *USB_EhciGetValidFrameList(usb_host_ehci_instance_t *ehciInstance, uint8_t *instanceIndex) +{ + if (ehciInstance->controllerId < kUSB_ControllerEhci0) + { + return NULL; + } + +#if (USB_HOST_CONFIG_EHCI == 1U) + if (!usbHostEhciFramListStatus[0]) + { + usbHostEhciFramListStatus[0] = 1; + *instanceIndex = 0; + return &s_UsbHostEhciFrameList1[0]; + } +#elif (USB_HOST_CONFIG_EHCI == 2U) + if (!usbHostEhciFramListStatus[0]) + { + usbHostEhciFramListStatus[0] = 1; + *instanceIndex = 0; + return &s_UsbHostEhciFrameList1[0]; + } + else if (!usbHostEhciFramListStatus[1]) + { + usbHostEhciFramListStatus[1] = 1; + *instanceIndex = 1; + return &s_UsbHostEhciFrameList2[0]; + } + else + { + } +#endif + + return NULL; +} + +usb_status_t USB_HostEhciCreate(uint8_t controllerId, + usb_host_handle upperLayerHandle, + usb_host_controller_handle *controllerHandle) +{ + uint32_t index = 0; + usb_osa_status_t osaStatus; + usb_host_ehci_instance_t *ehciInstance; + uint32_t usbhsBaseAddrs[] = USBHS_BASE_ADDRS; + usb_host_ehci_data_t *usbHostEhciData[] = USB_HOST_EHCI_DATA_ARRAY; + uint32_t *framePointer; + uint8_t instanceIndex; + + if ((uint32_t)(controllerId - kUSB_ControllerEhci0) >= (sizeof(usbhsBaseAddrs) / sizeof(usbhsBaseAddrs[0]))) + { + return kStatus_USB_ControllerNotFound; + } + + *controllerHandle = NULL; + ehciInstance = (usb_host_ehci_instance_t *)USB_OsaMemoryAllocate( + sizeof(usb_host_ehci_instance_t)); /* malloc host ehci instance */ + if (ehciInstance == NULL) + { + return kStatus_USB_AllocFail; + } + ehciInstance->controllerId = controllerId; + ehciInstance->hostHandle = upperLayerHandle; + ehciInstance->deviceAttached = kEHCIDeviceDetached; + ehciInstance->ehciIpBase = (USBHS_Type *) + usbhsBaseAddrs[controllerId - kUSB_ControllerEhci0]; /* operate ehci ip through the base address */ +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + ehciInstance->busSuspendStatus = kBus_EhciIdle; + +#if (defined(USB_HOST_CONFIG_LOW_POWER_MODE) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + ehciInstance->registerPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + ehciInstance->registerNcBase = (USBNC_Type *)USB_EhciNCGetBase(controllerId); +#endif + +#endif + +#endif + + if (USB_HostEhciResetIP(ehciInstance) != kStatus_USB_Success) /* reset ehci ip */ + { + USB_OsaMemoryFree(ehciInstance); + return kStatus_USB_Error; + } + + /* initialize ehci frame list */ + ehciInstance->ehciFrameList = USB_EhciGetValidFrameList(ehciInstance, &instanceIndex); + if (ehciInstance->ehciFrameList == NULL) + { + return kStatus_USB_Error; + } + + /* initialize ehci units */ + ehciInstance->ehciUnitBase = (uint32_t *)(usbHostEhciData[instanceIndex]); + /* initialize qh/qtd/itd/sitd/iso list */ + ehciInstance->ehciQhList = (usb_host_ehci_qh_t *)((uint32_t)(ehciInstance->ehciUnitBase)); + ehciInstance->ehciQtdHead = (usb_host_ehci_qtd_t *)((uint32_t)ehciInstance->ehciQhList + + (sizeof(usb_host_ehci_qh_t) * USB_HOST_CONFIG_EHCI_MAX_QH)); + ehciInstance->ehciItdList = (usb_host_ehci_itd_t *)((uint32_t)ehciInstance->ehciQtdHead + + (sizeof(usb_host_ehci_qtd_t) * USB_HOST_CONFIG_EHCI_MAX_QTD)); + ehciInstance->ehciSitdList = ehciInstance->ehciSitdIndexBase = + (usb_host_ehci_sitd_t *)((uint32_t)ehciInstance->ehciItdList + + (sizeof(usb_host_ehci_itd_t) * USB_HOST_CONFIG_EHCI_MAX_ITD)); + ehciInstance->ehciIsoList = (usb_host_ehci_iso_t *)((uint32_t)ehciInstance->ehciSitdList + + (sizeof(usb_host_ehci_sitd_t) * USB_HOST_CONFIG_EHCI_MAX_SITD)); + ehciInstance->ehciPipeIndexBase = + (usb_host_ehci_pipe_t *)((uint32_t)ehciInstance->ehciIsoList + + (sizeof(usb_host_ehci_iso_t) * USB_HOST_EHCI_ISO_NUMBER)); + for (index = 1; index < USB_HOST_CONFIG_EHCI_MAX_QH; ++index) + { + ehciInstance->ehciQhList[index - 1].horizontalLinkPointer = (uint32_t)(&ehciInstance->ehciQhList[index]); + } + ehciInstance->ehciQhList[USB_HOST_CONFIG_EHCI_MAX_QH - 1].horizontalLinkPointer = (uint32_t)NULL; + for (index = 1; index < USB_HOST_CONFIG_EHCI_MAX_QTD; ++index) + { + ehciInstance->ehciQtdHead[index - 1].nextQtdPointer = (uint32_t)(&ehciInstance->ehciQtdHead[index]); + } + ehciInstance->ehciQtdNumber = USB_HOST_CONFIG_EHCI_MAX_QTD; + ehciInstance->ehciQtdHead[USB_HOST_CONFIG_EHCI_MAX_QTD - 1].nextQtdPointer = (uint32_t)NULL; + ehciInstance->ehciQtdTail = &ehciInstance->ehciQtdHead[USB_HOST_CONFIG_EHCI_MAX_QTD - 1]; + +#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) + for (index = 1; index < USB_HOST_CONFIG_EHCI_MAX_ITD; ++index) + { + ehciInstance->ehciItdList[index - 1].nextLinkPointer = (uint32_t)(&ehciInstance->ehciItdList[index]); + } + ehciInstance->ehciItdNumber = USB_HOST_CONFIG_EHCI_MAX_ITD; + ehciInstance->ehciItdList[USB_HOST_CONFIG_EHCI_MAX_ITD - 1].nextLinkPointer = (uint32_t)NULL; +#endif /* USB_HOST_CONFIG_EHCI_MAX_ITD */ + +#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)) + for (index = 1; index < USB_HOST_CONFIG_EHCI_MAX_SITD; ++index) + { + ehciInstance->ehciSitdList[index - 1].nextLinkPointer = (uint32_t)(&ehciInstance->ehciSitdList[index]); + } + ehciInstance->ehciSitdNumber = USB_HOST_CONFIG_EHCI_MAX_SITD; + ehciInstance->ehciSitdList[USB_HOST_CONFIG_EHCI_MAX_SITD - 1].nextLinkPointer = (uint32_t)NULL; +#endif /* USB_HOST_CONFIG_EHCI_MAX_SITD */ + +#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) + for (index = 1; index < USB_HOST_EHCI_ISO_NUMBER; ++index) + { + ehciInstance->ehciIsoList[index - 1].next = &ehciInstance->ehciIsoList[index]; + } + ehciInstance->ehciIsoList[USB_HOST_EHCI_ISO_NUMBER - 1].next = NULL; +#endif + + /* initialize pipes */ + ehciInstance->ehciPipeList = ehciInstance->ehciPipeIndexBase; + for (index = 1; index < USB_HOST_CONFIG_MAX_PIPES; ++index) + { + ehciInstance->ehciPipeList[index - 1].pipeCommon.next = (usb_host_pipe_t *)&ehciInstance->ehciPipeList[index]; + } + /* initialize mutext */ + osaStatus = USB_OsaMutexCreate(&ehciInstance->ehciMutex); + if (osaStatus != kStatus_USB_OSA_Success) + { +#ifdef HOST_ECHO + usb_echo("ehci mutex init fail\r\n"); +#endif + USB_OsaMemoryFree(ehciInstance); + return kStatus_USB_Error; + } + /* initialize task event */ + osaStatus = USB_OsaEventCreate(&ehciInstance->taskEventHandle, 1); + if (osaStatus != kStatus_USB_OSA_Success) + { +#ifdef HOST_ECHO + usb_echo("ehci event init fail\r\n"); +#endif + USB_OsaMutexDestroy(ehciInstance->ehciMutex); + USB_OsaMemoryFree(ehciInstance); + return kStatus_USB_Error; + } + + /* initialize first qh */ + ehciInstance->shedFirstQh = ehciInstance->ehciQhList; + ehciInstance->ehciQhList = + (usb_host_ehci_qh_t *)(ehciInstance->ehciQhList->horizontalLinkPointer & EHCI_HOST_POINTER_ADDRESS_MASK); + ehciInstance->shedFirstQh->staticEndpointStates[0] |= (1 << EHCI_HOST_QH_H_SHIFT); /* first qh */ + ehciInstance->shedFirstQh->horizontalLinkPointer = EHCI_HOST_T_INVALID_VALUE; + ehciInstance->shedFirstQh->currentQtdPointer = EHCI_HOST_T_INVALID_VALUE; + ehciInstance->shedFirstQh->nextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + ehciInstance->shedFirstQh->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE; + ehciInstance->shedFirstQh->horizontalLinkPointer = + (uint32_t)((uint32_t)(ehciInstance->shedFirstQh) | EHCI_HOST_POINTER_TYPE_QH); + + /* initialize periodic list */ + framePointer = (uint32_t *)ehciInstance->ehciFrameList; + for (index = 0; index < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE; ++index) + { + framePointer[index] = EHCI_HOST_T_INVALID_VALUE; + } + + USB_HostEhciStartIP(ehciInstance); /* start ehci ip */ + + *controllerHandle = ehciInstance; + + return kStatus_USB_Success; +} + +usb_status_t USB_HostEhciDestory(usb_host_controller_handle controllerHandle) +{ + usb_host_ehci_instance_t *ehciInstance = (usb_host_ehci_instance_t *)controllerHandle; + + /* disable all interrupts */ + ehciInstance->ehciIpBase->USBINTR = 0; + /* stop the controller */ + ehciInstance->ehciIpBase->USBCMD = 0; +/* free memory */ +#if (USB_HOST_CONFIG_EHCI == 1U) + if (ehciInstance->ehciFrameList == &s_UsbHostEhciFrameList1[0]) + { + usbHostEhciFramListStatus[0] = 0; + } +#elif (USB_HOST_CONFIG_EHCI == 2U) + if (ehciInstance->ehciFrameList == &s_UsbHostEhciFrameList1[0]) + { + usbHostEhciFramListStatus[0] = 0; + } + else if (ehciInstance->ehciFrameList == &s_UsbHostEhciFrameList2[0]) + { + usbHostEhciFramListStatus[1] = 0; + } + else + { + } +#endif + USB_OsaMutexDestroy(ehciInstance->ehciMutex); + USB_OsaEventDestroy(ehciInstance->taskEventHandle); + USB_OsaMemoryFree(ehciInstance); + + return kStatus_USB_Success; +} + +usb_status_t USB_HostEhciOpenPipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle *pipeHandle, + usb_host_pipe_init_t *pipeInit) +{ + usb_host_ehci_pipe_t *ehciPipePointer = NULL; + usb_status_t status; + uint32_t speed; + usb_host_ehci_instance_t *ehciInstance = (usb_host_ehci_instance_t *)controllerHandle; + + /* get one pipe */ + USB_HostEhciLock(); + if (ehciInstance->ehciPipeList != NULL) + { + ehciPipePointer = ehciInstance->ehciPipeList; + ehciInstance->ehciPipeList = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next; + } + USB_HostEhciUnlock(); + if (ehciPipePointer == NULL) + { +#ifdef HOST_ECHO + usb_echo("ehci open pipe failed\r\n"); +#endif + return kStatus_USB_Busy; + } + + /* initialize pipe informations */ + USB_HostEhciZeroMem((uint32_t *)ehciPipePointer, sizeof(usb_host_ehci_pipe_t) / 4); + ehciPipePointer->pipeCommon.deviceHandle = pipeInit->devInstance; + ehciPipePointer->pipeCommon.endpointAddress = pipeInit->endpointAddress; + ehciPipePointer->pipeCommon.direction = pipeInit->direction; + ehciPipePointer->pipeCommon.interval = pipeInit->interval; + ehciPipePointer->pipeCommon.maxPacketSize = pipeInit->maxPacketSize; + ehciPipePointer->pipeCommon.pipeType = pipeInit->pipeType; + ehciPipePointer->pipeCommon.numberPerUframe = pipeInit->numberPerUframe; + if (ehciPipePointer->pipeCommon.numberPerUframe == 0) + { + ehciPipePointer->pipeCommon.numberPerUframe = 1; + } + ehciPipePointer->pipeCommon.nakCount = pipeInit->nakCount; + ehciPipePointer->pipeCommon.nextdata01 = 0; + ehciPipePointer->ehciQh = NULL; + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, &speed); + if (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_ISOCHRONOUS) + { + ehciPipePointer->pipeCommon.interval = + (1 << (ehciPipePointer->pipeCommon.interval - 1)); /* iso interval is the power of 2 */ + } + else if (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT) + { + if (speed == USB_SPEED_HIGH) + { + ehciPipePointer->pipeCommon.interval = + (1 << (ehciPipePointer->pipeCommon.interval - 1)); /* HS interrupt interval is the power of 2 */ + } + else + { + ehciPipePointer->pipeCommon.interval = USB_HostEhciGet2PowerValue( + ehciPipePointer->pipeCommon + .interval); /* FS/LS interrupt interval should be the power of 2, it is used for ehci bandwidth */ + } + } + else + { + } + + /* save the micro-frame interval, it is convenient for the interval process */ + if (speed == USB_SPEED_HIGH) + { + ehciPipePointer->uframeInterval = ehciPipePointer->pipeCommon.interval; + } + else + { + ehciPipePointer->uframeInterval = 8 * ehciPipePointer->pipeCommon.interval; + } + + /* open pipe */ + switch (ehciPipePointer->pipeCommon.pipeType) + { + case USB_ENDPOINT_CONTROL: + case USB_ENDPOINT_BULK: + status = USB_HostEhciOpenControlBulk(ehciInstance, ehciPipePointer); + break; + +#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \ + ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) + case USB_ENDPOINT_ISOCHRONOUS: + status = USB_HostEhciOpenIso(ehciInstance, ehciPipePointer); + break; +#endif + + case USB_ENDPOINT_INTERRUPT: + status = USB_HostEhciOpenInterrupt(ehciInstance, ehciPipePointer); + break; + + default: + status = kStatus_USB_Error; + break; + } + + if (status != kStatus_USB_Success) + { + /* release pipe */ + USB_HostEhciLock(); + ehciPipePointer->pipeCommon.next = (usb_host_pipe_t *)ehciInstance->ehciPipeList; + ehciInstance->ehciPipeList = ehciPipePointer; + USB_HostEhciUnlock(); + return status; + } + + /* add pipe to run pipe list */ + USB_HostEhciLock(); + ehciPipePointer->pipeCommon.next = (usb_host_pipe_t *)ehciInstance->ehciRunningPipeList; + ehciInstance->ehciRunningPipeList = ehciPipePointer; + USB_HostEhciUnlock(); + + *pipeHandle = ehciPipePointer; + return status; +} + +usb_status_t USB_HostEhciClosePipe(usb_host_controller_handle controllerHandle, usb_host_pipe_handle pipeHandle) +{ + usb_host_ehci_instance_t *ehciInstance = (usb_host_ehci_instance_t *)controllerHandle; + usb_host_ehci_pipe_t *ehciPipePointer = (usb_host_ehci_pipe_t *)pipeHandle; + usb_host_pipe_t *prevPointer = NULL; + + switch (ehciPipePointer->pipeCommon.pipeType) + { + case USB_ENDPOINT_BULK: + case USB_ENDPOINT_CONTROL: + USB_HostEhciCloseControlBulk(ehciInstance, ehciPipePointer); + break; + + case USB_ENDPOINT_INTERRUPT: + USB_HostEhciCloseInterrupt(ehciInstance, ehciPipePointer); + break; + +#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \ + ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) + case USB_ENDPOINT_ISOCHRONOUS: + USB_HostEhciCloseIso(ehciInstance, ehciPipePointer); + break; +#endif + + default: + break; + } + + /* delete pipe from run pipe list */ + USB_HostEhciLock(); + prevPointer = (usb_host_pipe_t *)ehciInstance->ehciRunningPipeList; + if (prevPointer == (usb_host_pipe_t *)ehciPipePointer) + { + ehciInstance->ehciRunningPipeList = (usb_host_ehci_pipe_t *)(prevPointer->next); + } + else + { + while (prevPointer != NULL) + { + if (prevPointer->next == (usb_host_pipe_t *)ehciPipePointer) + { + prevPointer->next = ehciPipePointer->pipeCommon.next; + break; + } + else + { + prevPointer = prevPointer->next; + } + } + } + USB_HostEhciUnlock(); + + /* release pipe */ + USB_HostEhciLock(); + ehciPipePointer->pipeCommon.next = (usb_host_pipe_t *)ehciInstance->ehciPipeList; + ehciInstance->ehciPipeList = ehciPipePointer; + USB_HostEhciUnlock(); + + return kStatus_USB_Success; +} + +usb_status_t USB_HostEhciWritePipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer) +{ + usb_host_ehci_instance_t *ehciInstance = (usb_host_ehci_instance_t *)controllerHandle; + usb_host_ehci_pipe_t *ehciPipePointer = (usb_host_ehci_pipe_t *)pipeHandle; + usb_status_t status = kStatus_USB_Success; +#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \ + ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) + uint32_t speed; +#endif + + switch (ehciPipePointer->pipeCommon.pipeType) + { + case USB_ENDPOINT_BULK: + case USB_ENDPOINT_CONTROL: + case USB_ENDPOINT_INTERRUPT: + status = USB_HostEhciQhQtdListInit(ehciInstance, ehciPipePointer, + transfer); /* initialize qtd for control/bulk transfer */ + break; + +#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \ + ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) + case USB_ENDPOINT_ISOCHRONOUS: + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, + &speed); + if (speed == USB_SPEED_HIGH) + { +#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) + status = USB_HostEhciItdArrayInit(ehciInstance, ehciPipePointer, + transfer); /* initialize itd for iso transfer */ +#endif + } + else + { +#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)) + status = USB_HostEhciSitdArrayInit(ehciInstance, ehciPipePointer, + transfer); /* initialize sitd for iso transfer */ +#endif + } + break; +#endif + + default: + break; + } + return status; +} + +usb_status_t USB_HostEhciReadpipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer) +{ + return USB_HostEhciWritePipe(controllerHandle, pipeHandle, transfer); /* same as write */ +} + +usb_status_t USB_HostEhciIoctl(usb_host_controller_handle controllerHandle, uint32_t ioctlEvent, void *ioctlParam) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_ehci_instance_t *ehciInstance = (usb_host_ehci_instance_t *)controllerHandle; + usb_host_cancel_param_t *param; + usb_host_ehci_pipe_t *ehciPipePointer; + volatile usb_host_ehci_qh_t *vltQhPointer; + uint32_t deviceAddress; + + if (controllerHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + switch (ioctlEvent) + { + case kUSB_HostCancelTransfer: /* cancel pipe or one transfer */ + param = (usb_host_cancel_param_t *)ioctlParam; + status = USB_HostEhciCancelPipe(ehciInstance, (usb_host_ehci_pipe_t *)param->pipeHandle, param->transfer); + break; + + case kUSB_HostBusControl: /* bus control */ + status = USB_HostEhciControlBus(ehciInstance, *((uint8_t *)ioctlParam)); + break; + + case kUSB_HostGetFrameNumber: /* get frame number */ + *((uint32_t *)ioctlParam) = ((ehciInstance->ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE) >> 3); + break; + + case kUSB_HostUpdateControlEndpointAddress: + ehciPipePointer = (usb_host_ehci_pipe_t *)ioctlParam; + vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; + /* update address */ + USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceAddress, + &deviceAddress); + vltQhPointer->staticEndpointStates[0] |= deviceAddress; + USB_HostEhciDelay(ehciInstance->ehciIpBase, 2U); + break; + + case kUSB_HostUpdateControlPacketSize: + ehciPipePointer = (usb_host_ehci_pipe_t *)ioctlParam; + vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; + USB_HostEhciLock(); + if (ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK) + { + USB_HostEhciStopAsync(ehciInstance); + /* update max packet size */ + vltQhPointer->staticEndpointStates[0] = + (((vltQhPointer->staticEndpointStates[0]) & (~EHCI_HOST_QH_MAX_PACKET_LENGTH_MASK)) | + ((uint32_t)ehciPipePointer->pipeCommon.maxPacketSize << EHCI_HOST_QH_MAX_PACKET_LENGTH_SHIFT)); + USB_HostEhciStartAsync(ehciInstance); + } + else + { + /* update max packet size */ + vltQhPointer->staticEndpointStates[0] = + (((vltQhPointer->staticEndpointStates[0]) & (~EHCI_HOST_QH_MAX_PACKET_LENGTH_MASK)) | + ((uint32_t)ehciPipePointer->pipeCommon.maxPacketSize << EHCI_HOST_QH_MAX_PACKET_LENGTH_SHIFT)); + } + USB_HostEhciUnlock(); + break; + + default: + break; + } + return status; +} + +void USB_HostEhciTaskFunction(void *hostHandle) +{ + usb_host_ehci_instance_t *ehciInstance; + uint32_t bitSet; + usb_device_handle deviceHandle; + + if (hostHandle == NULL) + { + return; + } + ehciInstance = (usb_host_ehci_instance_t *)((usb_host_instance_t *)hostHandle)->controllerHandle; + + if (USB_OsaEventWait(ehciInstance->taskEventHandle, 0xFF, 0, 0, &bitSet) == + kStatus_USB_OSA_Success) /* wait all event */ + { + if (bitSet & EHCI_TASK_EVENT_PORT_CHANGE) /* port change */ + { + USB_HostEhciPortChange(ehciInstance); + } + + if (bitSet & EHCI_TASK_EVENT_TIMER0) /* timer0 */ + { + USB_HostEhciTimer0(ehciInstance); + } + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + if (bitSet & EHCI_TASK_EVENT_TIMER1) /* timer1 */ + { + USB_HostEhciTimer1(ehciInstance); + } +#endif + + if (ehciInstance->deviceAttached == kEHCIDeviceAttached) + { + if (bitSet & EHCI_TASK_EVENT_TRANSACTION_DONE) /* transaction done */ + { + USB_HostEhciTransactionDone(ehciInstance); + } + + if (bitSet & EHCI_TASK_EVENT_DEVICE_DETACH) /* device detach */ + { + ehciInstance->ehciIpBase->USBINTR &= + (~USBHS_USBINTR_PCE_MASK); /* disable attach, enable when the detach process is done */ + ehciInstance->deviceAttached = kEHCIDeviceDetached; + USB_HostDetachDevice(ehciInstance->hostHandle, 0, 0); + } + } + else if (ehciInstance->deviceAttached != kEHCIDeviceAttached) + { + if (bitSet & EHCI_TASK_EVENT_DEVICE_ATTACH) /* device is attached */ + { + USB_HostEhciStartAsync(ehciInstance); + USB_HostEhciStartPeriodic(ehciInstance); + + if (USB_HostAttachDevice(ehciInstance->hostHandle, ehciInstance->firstDeviceSpeed, 0, 0, 1, + &deviceHandle) == kStatus_USB_Success) + { + ehciInstance->deviceAttached = kEHCIDeviceAttached; + } + } + } + else + { + } + } +} + +void USB_HostEhciIsrFunction(void *hostHandle) +{ + usb_host_ehci_instance_t *ehciInstance; + static uint32_t interruptStatus = 0; + + if (hostHandle == NULL) + { + return; + } + + ehciInstance = (usb_host_ehci_instance_t *)((usb_host_instance_t *)hostHandle)->controllerHandle; + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + if (ehciInstance->registerNcBase->USB_OTGn_CTRL & USBNC_USB_OTGn_CTRL_WIE_MASK) + { + usb_host_instance_t *hostPointer = (usb_host_instance_t *)ehciInstance->hostHandle; + ehciInstance->registerNcBase->USB_OTGn_CTRL &= ~USBNC_USB_OTGn_CTRL_WIE_MASK; + hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL, + kUSB_HostEventDetectResume); /* call host callback function */ + + while (!(ehciInstance->registerNcBase->USB_OTGn_PHY_CTRL_0 & USBNC_USB_OTGn_PHY_CTRL_0_UTMI_CLK_VLD_MASK)) + { + } + + if (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_CCS_MASK) + { + USB_HostEhciStartAsync(ehciInstance); + USB_HostEhciStartPeriodic(ehciInstance); + } + ehciInstance->ehciIpBase->USBCMD |= (USBHS_USBCMD_RS_MASK); + if ((kBus_EhciSuspended == ehciInstance->busSuspendStatus)) + { + /* ehciInstance->ehciIpBase->PORTSC1 |= USBHS_PORTSC1_FPR_MASK; */ + ehciInstance->busSuspendStatus = kBus_EhciStartResume; + } + else + { + } + } + else + { + } +#else + if (ehciInstance->ehciIpBase->USBGENCTRL & USBHS_USBGENCTRL_WU_IE_MASK) + { + usb_host_instance_t *hostPointer = (usb_host_instance_t *)ehciInstance->hostHandle; + + hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL, + kUSB_HostEventDetectResume); /* call host callback function */ + + while (!(USBPHY->PLL_SIC & USBPHY_PLL_SIC_PLL_LOCK_MASK)) + { + } + ehciInstance->ehciIpBase->USBGENCTRL |= USBHS_USBGENCTRL_WU_INT_CLR_MASK; + ehciInstance->ehciIpBase->USBGENCTRL &= ~USBHS_USBGENCTRL_WU_IE_MASK; + if (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_CCS_MASK) + { + USB_HostEhciStartAsync(ehciInstance); + USB_HostEhciStartPeriodic(ehciInstance); + } + ehciInstance->ehciIpBase->USBCMD |= (USBHS_USBCMD_RS_MASK); + if ((kBus_EhciSuspended == ehciInstance->busSuspendStatus)) + { + ehciInstance->busSuspendStatus = kBus_EhciStartResume; + /*ehciInstance->ehciIpBase->PORTSC1 |= USBHS_PORTSC1_FPR_MASK; */ + } + else + { + } + } + else + { + } +#endif /* FSL_FEATURE_SOC_USBNC_COUNT */ + +#endif /* USB_HOST_CONFIG_LOW_POWER_MODE */ + + interruptStatus = ehciInstance->ehciIpBase->USBSTS; + interruptStatus &= ehciInstance->ehciIpBase->USBINTR; + while (interruptStatus) /* there are usb interrupts */ + { + ehciInstance->ehciIpBase->USBSTS = interruptStatus; /* clear interrupt */ + + if (interruptStatus & USBHS_USBSTS_SRI_MASK) /* SOF interrupt */ + { + } + + if (interruptStatus & USBHS_USBSTS_SEI_MASK) /* system error interrupt */ + { + } + + if ((interruptStatus & USBHS_USBSTS_UI_MASK) || + (interruptStatus & USBHS_USBSTS_UEI_MASK)) /* USB interrupt or USB error interrupt */ + { + USB_OsaEventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_TRANSACTION_DONE); + } + + if (interruptStatus & USBHS_USBSTS_PCI_MASK) /* port change detect interrupt */ + { +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + usb_host_instance_t *hostPointer = (usb_host_instance_t *)ehciInstance->hostHandle; + if (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_FPR_MASK) + { + if (kBus_EhciStartSuspend == ehciInstance->busSuspendStatus) + { + if (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_CCS_MASK) + { + USB_HostEhciStartAsync(ehciInstance); + USB_HostEhciStartPeriodic(ehciInstance); + } + hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL, + kUSB_HostEventNotSuspended); /* call host callback function */ + hostPointer->suspendedDevice = NULL; + ehciInstance->busSuspendStatus = kBus_EhciIdle; + ehciInstance->ehciIpBase->USBINTR &= ~(USBHS_USBINTR_TIE1_MASK); + } + else + { + } + } +#endif + USB_OsaEventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_PORT_CHANGE); + } + + if (interruptStatus & USBHS_USBSTS_TI0_MASK) /* timer 0 interrupt */ + { + USB_OsaEventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_TIMER0); + } + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + if (interruptStatus & USBHS_USBSTS_TI1_MASK) /* timer 1 interrupt */ + { + USB_OsaEventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_TIMER1); + } +#endif + + interruptStatus = ehciInstance->ehciIpBase->USBSTS; + interruptStatus &= ehciInstance->ehciIpBase->USBINTR; + } +} + +#endif /* USB_HOST_CONFIG_EHCI */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_ehci.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_ehci.h new file mode 100644 index 000000000..b16c668d1 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_ehci.h @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _USB_HOST_CONTROLLER_EHCI_H_ +#define _USB_HOST_CONTROLLER_EHCI_H_ + +/******************************************************************************* + * KHCI private public structures, enumerations, macros, functions + ******************************************************************************/ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/* EHCI host macros */ +#define EHCI_HOST_T_INVALID_VALUE (1U) +#define EHCI_HOST_POINTER_TYPE_ITD (0x00U) +#define EHCI_HOST_POINTER_TYPE_QH (0x00000002U) +#define EHCI_HOST_POINTER_TYPE_SITD (0x00000004U) +#define EHCI_HOST_POINTER_TYPE_FSTN (0x00000006U) +#define EHCI_HOST_POINTER_TYPE_MASK (0x00000006U) +#define EHCI_HOST_POINTER_ADDRESS_MASK (0xFFFFFFE0U) +#define EHCI_HOST_PID_OUT (0U) +#define EHCI_HOST_PID_IN (1U) +#define EHCI_HOST_PID_SETUP (2U) + +#define EHCI_HOST_QH_RL_SHIFT (28U) +#define EHCI_HOST_QH_RL_MASK (0xF0000000U) +#define EHCI_HOST_QH_C_SHIFT (27U) +#define EHCI_HOST_QH_MAX_PACKET_LENGTH_SHIFT (16U) +#define EHCI_HOST_QH_MAX_PACKET_LENGTH_MASK (0x07FF0000U) +#define EHCI_HOST_QH_H_SHIFT (15U) +#define EHCI_HOST_QH_DTC_SHIFT (14U) +#define EHCI_HOST_QH_EPS_SHIFT (12U) +#define EHCI_HOST_QH_ENDPT_SHIFT (8U) +#define EHCI_HOST_QH_I_SHIFT (7U) +#define EHCI_HOST_QH_DEVICE_ADDRESS_SHIFT (0U) +#define EHCI_HOST_QH_MULT_SHIFT (30U) +#define EHCI_HOST_QH_PORT_NUMBER_SHIFT (23U) +#define EHCI_HOST_QH_HUB_ADDR_SHIFT (16U) +#define EHCI_HOST_QH_UFRAME_CMASK_SHIFT (8U) +#define EHCI_HOST_QH_UFRAME_SMASK_SHIFT (0U) +#define EHCI_HOST_QH_STATUS_ERROR_MASK (0x0000007EU) +#define EHCI_HOST_QH_STATUS_NOSTALL_ERROR_MASK (0x0000003EU) + +#define EHCI_HOST_QTD_DT_SHIFT (31U) +#define EHCI_HOST_QTD_DT_MASK (0x80000000U) +#define EHCI_HOST_QTD_TOTAL_BYTES_SHIFT (16U) +#define EHCI_HOST_QTD_TOTAL_BYTES_MASK (0x7FFF0000U) +#define EHCI_HOST_QTD_IOC_MASK (0x00008000U) +#define EHCI_HOST_QTD_C_PAGE_SHIFT (12U) +#define EHCI_HOST_QTD_CERR_SHIFT (10U) +#define EHCI_HOST_QTD_CERR_MAX_VALUE (0x00000003U) +#define EHCI_HOST_QTD_PID_CODE_SHIFT (8U) +#define EHCI_HOST_QTD_STATUS_SHIFT (0U) +#define EHCI_HOST_QTD_CURRENT_OFFSET_MASK (0x00000FFFU) +#define EHCI_HOST_QTD_BUFFER_POINTER_SHIFT (12U) +#define EHCI_HOST_QTD_STATUS_ACTIVE_MASK (0x00000080U) +#define EHCI_HOST_QTD_STATUS_MASK (0x000000ffU) +#define EHCI_HOST_QTD_STATUS_ERROR_MASK (0x0000007EU) +#define EHCI_HOST_QTD_STATUS_STALL_ERROR_MASK (0x00000040U) + +#define EHCI_HOST_ITD_STATUS_ACTIVE_MASK (0x80000000U) +#define EHCI_HOST_ITD_TRANSACTION_LEN_SHIFT (16U) +#define EHCI_HOST_ITD_TRANSACTION_LEN_MASK (0x0FFF0000U) +#define EHCI_HOST_ITD_IOC_SHIFT (15U) +#define EHCI_HOST_ITD_PG_SHIFT (12U) +#define EHCI_HOST_ITD_TRANSACTION_OFFSET_SHIFT (0U) +#define EHCI_HOST_ITD_TRANSACTION_OFFSET_MASK (0x00000FFFU) +#define EHCI_HOST_ITD_BUFFER_POINTER_SHIFT (12U) +#define EHCI_HOST_ITD_ENDPT_SHIFT (8U) +#define EHCI_HOST_ITD_DEVICE_ADDRESS_SHIFT (0U) +#define EHCI_HOST_ITD_MAX_PACKET_SIZE_SHIFT (0U) +#define EHCI_HOST_ITD_MULT_SHIFT (0U) +#define EHCI_HOST_ITD_DIRECTION_SHIFT (11U) + +#define EHCI_HOST_SITD_STATUS_ACTIVE_MASK (0x00000080U) +#define EHCI_HOST_SITD_DIRECTION_SHIFT (31U) +#define EHCI_HOST_SITD_PORT_NUMBER_SHIFT (24U) +#define EHCI_HOST_SITD_HUB_ADDR_SHIFT (16U) +#define EHCI_HOST_SITD_ENDPT_SHIFT (8U) +#define EHCI_HOST_SITD_DEVICE_ADDRESS_SHIFT (0U) +#define EHCI_HOST_SITD_CMASK_SHIFT (8U) +#define EHCI_HOST_SITD_SMASK_SHIFT (0U) +#define EHCI_HOST_SITD_TOTAL_BYTES_SHIFT (16U) +#define EHCI_HOST_SITD_TOTAL_BYTES_MASK (0x03FF0000U) +#define EHCI_HOST_SITD_TP_SHIFT (3U) +#define EHCI_HOST_SITD_TCOUNT_SHIFT (0U) +#define EHCI_HOST_SITD_IOC_SHIFT (31U) + +/* register related MACROs */ +#define EHCI_PORTSC1_W1_BITS (0x0000002AU) +#define EHCI_MAX_UFRAME_VALUE (0x00003FFFU) + +/* task event */ +#define EHCI_TASK_EVENT_DEVICE_ATTACH (0x01U) +#define EHCI_TASK_EVENT_TRANSACTION_DONE (0x02U) +#define EHCI_TASK_EVENT_DEVICE_DETACH (0x04U) +#define EHCI_TASK_EVENT_PORT_CHANGE (0x08U) +#define EHCI_TASK_EVENT_TIMER0 (0x10U) +#define EHCI_TASK_EVENT_TIMER1 (0x20U) + +#define USB_HostEhciLock() USB_OsaMutexLock(ehciInstance->ehciMutex) +#define USB_HostEhciUnlock() USB_OsaMutexUnlock(ehciInstance->ehciMutex) + +/******************************************************************************* + * KHCI driver public structures, enumerations, macros, functions + ******************************************************************************/ + +/*! + * @addtogroup usb_host_controller_ehci + * @{ + */ + +/*! @brief The maximum supported ISO pipe number */ +#define USB_HOST_EHCI_ISO_NUMBER USB_HOST_CONFIG_EHCI_MAX_ITD +/*! @brief Check the port connect state delay if the state is unstable */ +#define USB_HOST_EHCI_PORT_CONNECT_DEBOUNCE_DELAY (101U) +/*! @brief Delay for port reset */ +#define USB_HOST_EHCI_PORT_RESET_DELAY (11U) +/*! @brief The SITD inserts a frame interval for putting more SITD continuously. + * There is an interval when an application sends two FS/LS ISO transfers. + * When the interval is less than the macro, the two transfers are continuous in the frame list. Otherwise, the two + * transfers + * are not continuous. + * For example: + * - Use case 1: when inserting the SITD first, the inserted frame = the current frame value + this MACRO value. + * - Use case 2: when inserting SITD is not first, choose between the last inserted frame value and the + * current frame value according to the following criteria: + * If the interval is less than the MACRO value, the new SITD is continuous with the last SITD. + * If not, the new SITD inserting frame = the current frame value + this MACRO value. + */ +#define USB_HOST_EHCI_ISO_BOUNCE_FRAME_NUMBER (2U) +/*! @brief The ITD inserts a micro-frame interval for putting more ITD continuously. + * There is an interval when an application sends two HS ISO transfers. + * When the interval is less than the macro, the two transfers are continuous in the frame list. Otherwise, the two + * transfers + * are not continuous. + * For example: + * - Use case 1: when inserting ITD first, the inserted micro-frame = the current micro-frame value + this MACRO value. + * - Use case 2: when inserting ITD is not first, choose between the last inserted micro-frame value and the + * current micro-frame value according to the following criteria: + * If the interval is less than this MACRO value, the new ITD is continuous with the last ITD. + * If not, the new ITD inserting micro-frame = the current micro-frame value + this MACRO value. + */ +#define USB_HOST_EHCI_ISO_BOUNCE_UFRAME_NUMBER (16U) +/*! @brief Control or bulk transaction timeout value (unit: 100 ms) */ +#define USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE (50U) + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) +typedef enum _bus_ehci_suspend_request_state +{ + kBus_EhciIdle = 0U, + kBus_EhciStartSuspend, + kBus_EhciSuspended, + kBus_EhciStartResume, +} bus_ehci_suspend_request_state_t; +#endif + +/*! @brief EHCI state for device attachment/detachment. */ +typedef enum _host_ehci_device_state_ +{ + kEHCIDevicePhyAttached = 1, /*!< Device is physically attached */ + kEHCIDeviceAttached, /*!< Device is attached and initialized */ + kEHCIDeviceDetached, /*!< Device is detached and de-initialized */ +} host_ehci_device_state_t; + +/*! @brief EHCI pipe structure */ +typedef struct _usb_host_ehci_pipe +{ + usb_host_pipe_t pipeCommon; /*!< Common pipe information */ + void *ehciQh; /*!< Control/bulk/interrupt: QH; ISO: usb_host_ehci_iso_t*/ + + /* bandwidth */ + uint16_t uframeInterval; /*!< Micro-frame interval value */ + uint16_t startFrame; /*!< + Bandwidth start frame: its value is from 0 to frame_list. + */ + uint16_t dataTime; /*!< + Bandwidth time value: + - When the host works as HS: it's the data bandwidth value. + - When the host works as FS/LS: + - For FS/LS device, it's the data bandwidth value when transferring the data by FS/LS. + - For HS device, it's the data bandwidth value when transferring the data by HS. + */ + uint16_t startSplitTime; /*!< + Start splitting the bandwidth time value: + - When the host works as HS, it is the start split bandwidth value. + */ + uint16_t completeSplitTime; /*!< + Complete splitting the bandwidth time value: + - When host works as HS, it is the complete split bandwidth value. + */ + uint8_t startUframe; /*!< + Bandwidth start micro-frame: its value is from 0 to 7. + */ + uint8_t uframeSmask; /*!< + Start micro-frame. + - When host works as an HS: + - For FS/LS device, it's the interrupt or ISO transfer start-split mask. + - For HS device, it's the interrupt transfer start micro-frame mask. + - When host works as FS/LS, it's the interrupt and ISO start micro-frame mask + */ + uint8_t uframeCmask; /*!< + Complete micro-frame + - When host works as HS: + - For FS/LS device, it's the interrupt or ISO transfer complete-split mask. + */ +} usb_host_ehci_pipe_t; + +/*! @brief EHCI QH structure. See the USB EHCI specification */ +typedef struct _usb_host_ehci_qh +{ + uint32_t horizontalLinkPointer; /*!< QH specification filed, queue head a horizontal link pointer */ + uint32_t + staticEndpointStates[2]; /*!< QH specification filed, static endpoint state and configuration information */ + uint32_t currentQtdPointer; /*!< QH specification filed, current qTD pointer */ + uint32_t nextQtdPointer; /*!< QH specification filed, next qTD pointer */ + uint32_t alternateNextQtdPointer; /*!< QH specification filed, alternate next qTD pointer */ + uint32_t + transferOverlayResults[6]; /*!< QH specification filed, transfer overlay configuration and transfer results */ + + /* reserved space */ + usb_host_ehci_pipe_t *ehciPipePointer; /*!< EHCI pipe pointer */ + usb_host_transfer_t *ehciTransferHead; /*!< Transfer list head on this QH */ + usb_host_transfer_t *ehciTransferTail; /*!< Transfer list tail on this QH */ + uint16_t timeOutValue; /*!< Its maximum value is USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE. When the value is + zero, the transfer times out. */ + uint16_t timeOutLabel; /*!< It's used to judge the transfer timeout. The EHCI driver maintain the value */ +} usb_host_ehci_qh_t; + +/*! @brief EHCI QTD structure. See the USB EHCI specification. */ +typedef struct _usb_host_ehci_qtd +{ + uint32_t nextQtdPointer; /*!< QTD specification filed, the next QTD pointer */ + uint32_t alternateNextQtdPointer; /*!< QTD specification filed, alternate next QTD pointer */ + uint32_t transferResults[2]; /*!< QTD specification filed, transfer results fields */ + uint32_t bufferPointers[4]; /*!< QTD specification filed, transfer buffer fields */ +} usb_host_ehci_qtd_t; + +/*! @brief EHCI ITD structure. See the USB EHCI specification. */ +typedef struct _usb_host_ehci_itd +{ + uint32_t nextLinkPointer; /*!< ITD specification filed, the next linker pointer */ + uint32_t transactions[8]; /*!< ITD specification filed, transactions information */ + uint32_t bufferPointers[7]; /*!< ITD specification filed, transfer buffer fields */ + + /* add space */ + struct _usb_host_ehci_itd *nextItdPointer; /*!< Next ITD pointer */ + uint32_t frameEntryIndex; /*!< The ITD inserted frame value */ + uint32_t reserved[6]; /*!< Reserved fields for 32 bytes align */ +} usb_host_ehci_itd_t; + +/*! @brief EHCI SITD structure. See the USB EHCI specification. */ +typedef struct _usb_host_ehci_sitd +{ + uint32_t nextLinkPointer; /*!< SITD specification filed, the next linker pointer */ + uint32_t endpointStates[2]; /*!< SITD specification filed, endpoint configuration information */ + uint32_t transferResults[3]; /*!< SITD specification filed, transfer result fields */ + uint32_t backPointer; /*!< SITD specification filed, back pointer */ + + /* reserved space */ + uint16_t frameEntryIndex; /*!< The SITD inserted frame value */ + uint8_t nextSitdIndex; /*!< The next SITD index; Get the next SITD pointer through adding base address with the + index. 0xFF means invalid. */ + uint8_t reserved; /*!< Reserved fields for 32 bytes align */ +} usb_host_ehci_sitd_t; + +/*! @brief EHCI ISO structure; An ISO pipe has an instance of this structure to keep the ISO pipe-specific information. + */ +typedef struct _usb_host_ehci_iso +{ + struct _usb_host_ehci_iso *next; /*!< Next instance pointer */ + usb_host_pipe_t *ehciPipePointer; /*!< This ISO's EHCI pipe pointer */ + usb_host_transfer_t *ehciTransferHead; /*!< Transfer list head on this ISO pipe */ + usb_host_transfer_t *ehciTransferTail; /*!< Transfer list head on this ISO pipe */ + + uint16_t lastLinkFrame; /*!< It means that the inserted frame for ISO ITD/SITD. 0xFFFF is invalid. For ITD, it is a + micro-frame value. For SITD, it is a frame value */ +} usb_host_ehci_iso_t; + +/*! @brief EHCI instance structure */ +typedef struct _usb_host_ehci_instance +{ + usb_host_handle hostHandle; /*!< Related host handle*/ + uint32_t *ehciUnitBase; /*!< Keep the QH/QTD/ITD/SITD buffer pointer for release*/ + uint8_t *ehciFrameList; /*!< The frame list of the current ehci instance*/ + usb_host_ehci_qh_t *ehciQhList; /*!< Idle QH list pointer */ + usb_host_ehci_qtd_t *ehciQtdHead; /*!< Idle QTD list pointer head */ + usb_host_ehci_qtd_t *ehciQtdTail; /*!< Idle QTD list pointer tail (recently used qTD will be used)*/ + usb_host_ehci_itd_t *ehciItdList; /*!< Idle ITD list pointer*/ + usb_host_ehci_sitd_t *ehciSitdIndexBase; /*!< SITD buffer's start pointer*/ + usb_host_ehci_sitd_t *ehciSitdList; /*!< Idle SITD list pointer*/ + usb_host_ehci_iso_t *ehciIsoList; /*!< Idle ISO list pointer*/ + USBHS_Type *ehciIpBase; /*!< EHCI IP base address*/ + usb_host_ehci_qh_t *shedFirstQh; /*!< First async QH*/ + usb_host_ehci_pipe_t *ehciPipeIndexBase; /*!< Pipe buffer's start pointer*/ + usb_host_ehci_pipe_t *ehciPipeList; /*!< Idle pipe list pointer*/ + usb_host_ehci_pipe_t *ehciRunningPipeList; /*!< Running pipe list pointer*/ + usb_osa_mutex_handle ehciMutex; /*!< EHCI mutex*/ + usb_osa_event_handle taskEventHandle; /*!< EHCI task event*/ +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + uint64_t matchTick; + USBPHY_Type *registerPhyBase; /*!< The base address of the PHY register */ +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + USBNC_Type *registerNcBase; /*!< The base address of the USBNC register */ +#endif + +#endif + uint8_t controllerId; /*!< EHCI controller ID*/ + uint8_t deviceAttached; /*!< Device attach/detach state, see #host_ehci_device_state_t */ + uint8_t firstDeviceSpeed; /*!< The first device's speed, the controller's work speed*/ + uint8_t ehciItdNumber; /*!< Idle ITD number*/ + uint8_t ehciSitdNumber; /*!< Idle SITD number*/ + uint8_t ehciQtdNumber; /*!< Idle QTD number*/ +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + bus_ehci_suspend_request_state_t busSuspendStatus; /*!< Bus Suspend Status*/ +#endif +} usb_host_ehci_instance_t; + +/*! @brief EHCI data structure */ +typedef struct _usb_host_ehci_data +{ +#if ((defined(USB_HOST_CONFIG_EHCI_MAX_QH)) && (USB_HOST_CONFIG_EHCI_MAX_QH > 0U)) + usb_host_ehci_qh_t ehciQh[USB_HOST_CONFIG_EHCI_MAX_QH]; /*!< Idle QH list array*/ +#endif +#if ((defined(USB_HOST_CONFIG_EHCI_MAX_QTD)) && (USB_HOST_CONFIG_EHCI_MAX_QTD > 0U)) + usb_host_ehci_qtd_t ehciQtd[USB_HOST_CONFIG_EHCI_MAX_QTD]; /*!< Idle QTD list array*/ +#endif +#if ((defined(USB_HOST_CONFIG_EHCI_MAX_ITD)) && (USB_HOST_CONFIG_EHCI_MAX_ITD > 0U)) + usb_host_ehci_itd_t ehciItd[USB_HOST_CONFIG_EHCI_MAX_ITD]; /*!< Idle ITD list array*/ +#endif +#if ((defined(USB_HOST_CONFIG_EHCI_MAX_SITD)) && (USB_HOST_CONFIG_EHCI_MAX_SITD > 0U)) + usb_host_ehci_sitd_t ehciSitd[USB_HOST_CONFIG_EHCI_MAX_SITD]; /*!< Idle SITD list array*/ +#endif +#if ((defined(USB_HOST_EHCI_ISO_NUMBER)) && (USB_HOST_EHCI_ISO_NUMBER > 0U)) + usb_host_ehci_iso_t ehciIso[USB_HOST_EHCI_ISO_NUMBER]; /*!< Idle ISO list array*/ +#endif +#if ((defined(USB_HOST_CONFIG_MAX_PIPES)) && (USB_HOST_CONFIG_MAX_PIPES > 0U)) + usb_host_ehci_pipe_t ehciPipe[USB_HOST_CONFIG_MAX_PIPES]; /*!< Idle pipe list array*/ +#endif +} usb_host_ehci_data_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif +/*! + * @name USB host EHCI APIs + * @{ + */ + +/*! + * @brief Creates the USB host EHCI instance. + * + * This function initializes the USB host EHCI controller driver. + * + * @param[in] controllerId The controller ID of the USB IP. Please refer to the enumeration usb_controller_index_t. + * @param[in] upperLayerHandle The host level handle. + * @param[out] controllerHandle return the controller instance handle. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_AllocFail Allocating memory failed. + * @retval kStatus_USB_Error Host mutex create fail, KHCI/EHCI mutex or KHCI/EHCI event create fail. + * Or, KHCI/EHCI IP initialize fail. + */ +extern usb_status_t USB_HostEhciCreate(uint8_t controllerId, + usb_host_handle upperLayerHandle, + usb_host_controller_handle *controllerHandle); + +/*! + * @brief Destroys the USB host EHCI instance. + * + * This function de-initializes The USB host EHCI controller driver. + * + * @param[in] controllerHandle The controller handle. + * + * @retval kStatus_USB_Success The host is initialized successfully. + */ +extern usb_status_t USB_HostEhciDestory(usb_host_controller_handle controllerHandle); + +/*! + * @brief Opens the USB host pipe. + * + * This function opens a pipe according to the pipe_init_ptr parameter. + * + * @param[in] controllerHandle The controller handle. + * @param[out] pipeHandle The pipe handle pointer, it is used to return the pipe handle. + * @param[in] pipeInit It is used to initialize the pipe. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_Error There is no idle pipe. + * Or, there is no idle QH for EHCI. + * Or, bandwidth allocate fail for EHCI. + */ +extern usb_status_t USB_HostEhciOpenPipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle *pipeHandle, + usb_host_pipe_init_t *pipeInit); + +/*! + * @brief Closes the USB host pipe. + * + * This function closes a pipe and releases related resources. + * + * @param[in] controllerHandle The controller handle. + * @param[in] pipeHandle The closing pipe handle. + * + * @retval kStatus_USB_Success The host is initialized successfully. + */ +extern usb_status_t USB_HostEhciClosePipe(usb_host_controller_handle controllerHandle, usb_host_pipe_handle pipeHandle); + +/*! + * @brief Sends data to the pipe. + * + * This function requests to send the transfer to the specified pipe. + * + * @param[in] controllerHandle The controller handle. + * @param[in] pipeHandle The sending pipe handle. + * @param[in] transfer The transfer information. + * + * @retval kStatus_USB_Success Sent successfully. + * @retval kStatus_USB_LackSwapBuffer There is no swap buffer for KHCI. + * @retval kStatus_USB_Error There is no idle QTD/ITD/SITD for EHCI. + */ +extern usb_status_t USB_HostEhciWritePipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); + +/*! + * @brief Receives data from the pipe. + * + * This function requests to receive the transfer from the specified pipe. + * + * @param[in] controllerHandle The controller handle. + * @param[in] pipeHandle The receiving pipe handle. + * @param[in] transfer The transfer information. + + * @retval kStatus_USB_Success Send successfully. + * @retval kStatus_USB_LackSwapBuffer There is no swap buffer for KHCI. + * @retval kStatus_USB_Error There is no idle QTD/ITD/SITD for EHCI. + */ +extern usb_status_t USB_HostEhciReadpipe(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); + +/*! + * @brief Controls the EHCI. + * + * This function controls the EHCI. + * + * @param[in] controllerHandle The controller handle. + * @param[in] ioctlEvent See enumeration host_bus_control_t. + * @param[in] ioctlParam The control parameter. + * + * @retval kStatus_USB_Success Cancel successfully. + * @retval kStatus_USB_InvalidHandle The controllerHandle is a NULL pointer. + */ +extern usb_status_t USB_HostEhciIoctl(usb_host_controller_handle controllerHandle, + uint32_t ioctlEvent, + void *ioctlParam); + +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* _USB_HOST_CONTROLLER_EHCI_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_framework.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_framework.c new file mode 100644 index 000000000..7a351d3e3 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_framework.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_host_config.h" +#include "usb_host.h" +#include "usb_host_hci.h" +#include "usb_host_devices.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @brief standard control transfer common code. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param buffer data buffer pointer. + * @param bufferLen data length. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostCh9RequestCommon(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + uint8_t *buffer, + uint32_t bufferLen); + +/*! + * @brief standard get status implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardGetStatus(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard set/clear feature implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardSetClearFeature(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard set address implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardSetAddress(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard set/get descriptor implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardSetGetDescriptor(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard get interface implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardGetInterface(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard set interface implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardSetInterface(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/*! + * @brief standard sync frame implementation. + * + * @param deviceInstance device instance handle. + * @param transfer transfer. + * @param param parameter. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostStandardSyncFrame(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param); + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +usb_status_t USB_HostCh9RequestCommon(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + uint8_t *buffer, + uint32_t bufferLen) +{ + /* initialize transfer */ + transfer->setupPacket->wLength = USB_SHORT_TO_LITTLE_ENDIAN(bufferLen); + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLen; + + if (USB_HostSendSetup(deviceInstance->hostHandle, deviceInstance->controlPipe, transfer) != + kStatus_USB_Success) /* send setup transfer */ + { +#ifdef HOST_ECHO + usb_echo("failed for USB_HostSendSetup\r\n"); +#endif + USB_HostFreeTransfer(deviceInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + return kStatus_USB_Success; +} + +usb_status_t USB_HostStandardGetStatus(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_get_status_param_t *statusParam; + uint8_t length; + + /* initialize transfer */ + statusParam = (usb_host_get_status_param_t *)param; + transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_STANDARD; + if (statusParam->requestType == kRequestDevice) + { + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_DEVICE; + } + else if (statusParam->requestType == kRequestInterface) + { + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + } + else + { + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + } + transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(statusParam->statusSelector); + + length = 2; + if (statusParam->statusSelector == USB_REQUEST_STANDARD_GET_STATUS_OTG_STATUS_SELECTOR) + { + length = 1; + } + return USB_HostCh9RequestCommon(deviceInstance, transfer, statusParam->statusBuffer, length); +} + +usb_status_t USB_HostStandardSetClearFeature(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_process_feature_param_t *featureParam; + + /* initialize transfer */ + featureParam = (usb_host_process_feature_param_t *)param; + if (featureParam->requestType == kRequestDevice) + { + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_DEVICE; + } + else if (featureParam->requestType == kRequestInterface) + { + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + } + else + { + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + } + transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(featureParam->featureSelector); + transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(featureParam->interfaceOrEndpoint); + + return USB_HostCh9RequestCommon(deviceInstance, transfer, NULL, 0); +} + +usb_status_t USB_HostStandardSetAddress(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + uint8_t address; + + /* initialize transfer */ + address = *(uint8_t *)param; + transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(address); + + return USB_HostCh9RequestCommon(deviceInstance, transfer, NULL, 0); +} + +usb_status_t USB_HostStandardSetGetDescriptor(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_process_descriptor_param_t *descriptorParam; + + /* initialize transfer */ + descriptorParam = (usb_host_process_descriptor_param_t *)param; + transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN( + (uint16_t)((uint16_t)descriptorParam->descriptorType << 8) | descriptorParam->descriptorIndex); + transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(descriptorParam->languageId); + return USB_HostCh9RequestCommon(deviceInstance, transfer, descriptorParam->descriptorBuffer, + descriptorParam->descriptorLength); +} + +usb_status_t USB_HostStandardGetInterface(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_get_interface_param_t *interfaceParam; + + /* initialize transfer */ + interfaceParam = (usb_host_get_interface_param_t *)param; + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(interfaceParam->interface); + + return USB_HostCh9RequestCommon(deviceInstance, transfer, interfaceParam->alternateInterfaceBuffer, 1); +} + +usb_status_t USB_HostStandardSetInterface(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_set_interface_param_t *setParam; + + /* initialize transfer */ + setParam = (usb_host_set_interface_param_t *)param; + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(setParam->interface); + transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(setParam->alternateSetting); + + return USB_HostCh9RequestCommon(deviceInstance, transfer, NULL, 0); +} + +usb_status_t USB_HostStandardSyncFrame(usb_host_device_instance_t *deviceInstance, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_synch_frame_param_t *frameParam; + + /* initialize transfer */ + frameParam = (usb_host_synch_frame_param_t *)param; + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; + transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(frameParam->endpoint); + + return USB_HostCh9RequestCommon(deviceInstance, transfer, frameParam->frameNumberBuffer, 2); +} + +usb_status_t USB_HostRequestControl(usb_device_handle deviceHandle, + uint8_t usbRequest, + usb_host_transfer_t *transfer, + void *param) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_status_t status = kStatus_USB_Error; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* reset transfer fields */ + transfer->setupPacket->bmRequestType = 0x00; + transfer->setupPacket->bRequest = usbRequest; + transfer->setupPacket->wIndex = 0; + transfer->setupPacket->wLength = 0; + transfer->setupPacket->wValue = 0; + + switch (usbRequest) + { + case USB_REQUEST_STANDARD_GET_STATUS: /* standard get status request */ + status = USB_HostStandardGetStatus(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_CLEAR_FEATURE: /* standard clear status request */ + case USB_REQUEST_STANDARD_SET_FEATURE: /* standard set feature request */ + status = USB_HostStandardSetClearFeature(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_SET_ADDRESS: /* standard set address request */ + status = USB_HostStandardSetAddress(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_GET_DESCRIPTOR: /* standard get descriptor request */ + case USB_REQUEST_STANDARD_SET_DESCRIPTOR: /* standard set descriptor request */ + if (usbRequest == USB_REQUEST_STANDARD_GET_DESCRIPTOR) + { + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + } + status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_GET_CONFIGURATION: /* standard get configuration descriptor request */ + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + status = + USB_HostCh9RequestCommon((usb_host_device_instance_t *)deviceHandle, transfer, (uint8_t *)param, 1); + break; + + case USB_REQUEST_STANDARD_SET_CONFIGURATION: /* standard set configuration request */ + transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(*((uint8_t *)param)); + status = USB_HostCh9RequestCommon((usb_host_device_instance_t *)deviceHandle, transfer, NULL, 0); + break; + + case USB_REQUEST_STANDARD_GET_INTERFACE: /* standard get interface request */ + status = USB_HostStandardGetInterface(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_SET_INTERFACE: /* standard set interface request */ + status = USB_HostStandardSetInterface(deviceInstance, transfer, param); + break; + + case USB_REQUEST_STANDARD_SYNCH_FRAME: /* standard synch frame request */ + status = USB_HostStandardSyncFrame(deviceInstance, transfer, param); + break; + + default: + break; + } + + return status; +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_framework.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_framework.h new file mode 100644 index 000000000..fd84fc714 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_framework.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _USB_HOST_CH9_H_ +#define _USB_HOST_CH9_H_ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @addtogroup usb_host_drv + * @{ + */ + +/*! @brief Request type */ +typedef enum _usb_host_request_type +{ + kRequestDevice = 1U, /*!< Control request object is device */ + kRequestInterface, /*!< Control request object is interface */ + kRequestEndpoint, /*!< Control request object is endpoint */ +} usb_host_request_type_t; + +/*! @brief For USB_REQUEST_STANDARD_CLEAR_FEATURE and USB_REQUEST_STANDARD_SET_FEATURE */ +typedef struct _usb_host_process_feature_param +{ + uint8_t requestType; /*!< See the #usb_host_request_type_t */ + uint8_t featureSelector; /*!< Set/cleared feature */ + uint8_t interfaceOrEndpoint; /*!< Interface or end pointer */ +} usb_host_process_feature_param_t; + +/*! @brief For USB_REQUEST_STANDARD_GET_DESCRIPTOR and USB_REQUEST_STANDARD_SET_DESCRIPTOR */ +typedef struct _usb_host_process_descriptor_param +{ + uint8_t descriptorType; /*!< See the usb_spec.h, such as the USB_DESCRIPTOR_TYPE_DEVICE */ + uint8_t descriptorIndex; /*!< The descriptor index is used to select a specific descriptor (only for configuration + and string descriptors) when several descriptors of the same type are implemented in a + device */ + uint8_t languageId; /*!< It specifies the language ID for string descriptors or is reset to zero for other + descriptors */ + uint8_t *descriptorBuffer; /*!< Buffer pointer */ + uint16_t descriptorLength; /*!< Buffer data length */ +} usb_host_process_descriptor_param_t; + +/*! @brief For USB_REQUEST_STANDARD_GET_INTERFACE */ +typedef struct _usb_host_get_interface_param +{ + uint8_t interface; /*!< Interface number */ + uint8_t *alternateInterfaceBuffer; /*!< Save the transfer result */ +} usb_host_get_interface_param_t; + +/*! @brief For USB_REQUEST_STANDARD_GET_STATUS */ +typedef struct _usb_host_get_status_param +{ + uint16_t statusSelector; /*!< Interface number, the end pointer number or OTG status selector */ + uint8_t requestType; /*!< See the #usb_host_request_type_t */ + uint8_t *statusBuffer; /*!< Save the transfer result */ +} usb_host_get_status_param_t; + +/*! @brief For USB_REQUEST_STANDARD_SET_INTERFACE */ +typedef struct _usb_host_set_interface_param +{ + uint8_t alternateSetting; /*!< Alternate setting value */ + uint8_t interface; /*!< Interface number */ +} usb_host_set_interface_param_t; + +/*! @brief For USB_REQUEST_STANDARD_SYNCH_FRAME */ +typedef struct _usb_host_synch_frame_param +{ + uint8_t endpoint; /*!< Endpoint number */ + uint8_t *frameNumberBuffer; /*!< Frame number data buffer */ +} usb_host_synch_frame_param_t; + +/*! @}*/ + +/******************************************************************************* + * API + ******************************************************************************/ + +#endif /* _USB_HOST_CH9_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_hci.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_hci.c new file mode 100644 index 000000000..cce9f3729 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_hci.c @@ -0,0 +1,1047 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_host_config.h" +#include "fsl_common.h" +#include "usb_host.h" +#include "usb_host_hci.h" +#include "usb_host_devices.h" +#include "fsl_device_registers.h" +#if ((defined USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) +#include "fsl_cache.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "middleware.usb.host_stack" +#endif + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +extern uint32_t USB_HostHubGetTotalThinkTime(usb_host_handle hostHandle, uint8_t parentHubNo); + +extern usb_status_t USB_HostHubSuspendDevice(usb_host_handle hostHandle); + +extern usb_status_t USB_HostHubResumeDevice(usb_host_handle hostHandle); +#endif + +/*! + * @brief get the idle host instance. + * + * @return host instance pointer. + */ +static usb_host_instance_t *USB_HostGetInstance(void); + +/*! + * @brief release host instance. + * + * @param hostInstance host instance pointer. + */ +static void USB_HostReleaseInstance(usb_host_instance_t *hostInstance); + +/*! + * @brief get the khci/ehci interface. + * + * @param controllerId controller id. + * @param controllerTable return controller interface structure. + */ +static void USB_HostGetControllerInterface(uint8_t controllerId, + const usb_host_controller_interface_t **controllerTable); + +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) +extern void USB_HostEhciTestModeInit(usb_device_handle devHandle); +#endif /* USB_HOST_CONFIG_COMPLIANCE_TEST */ +#if ((defined USB_HOST_CONFIG_IP3516HS) && (USB_HOST_CONFIG_IP3516HS)) +extern void USB_HostIp3516HsTestModeInit(usb_device_handle devHandle); +#endif /* USB_HOST_CONFIG_COMPLIANCE_TEST */ +#endif /* USB_HOST_CONFIG_EHCI */ + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief USB host instance resource */ +usb_host_instance_t g_UsbHostInstance[USB_HOST_CONFIG_MAX_HOST]; + +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) +#include "usb_host_ehci.h" +static const usb_host_controller_interface_t s_EhciInterface = \ +{ + USB_HostEhciCreate, USB_HostEhciDestory, USB_HostEhciOpenPipe, USB_HostEhciClosePipe, + USB_HostEhciWritePipe, USB_HostEhciReadpipe, USB_HostEhciIoctl, +}; +#endif /* USB_HOST_CONFIG_EHCI */ + +#if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) +#include "usb_host_khci.h" +static const usb_host_controller_interface_t s_KhciInterface = \ +{ + USB_HostKhciCreate, USB_HostKhciDestory, USB_HostKhciOpenPipe, USB_HostKhciClosePipe, + USB_HostKhciWritePipe, USB_HostKhciReadpipe, USB_HostKciIoctl, +}; +#endif /* USB_HOST_CONFIG_KHCI */ + +#if ((defined USB_HOST_CONFIG_OHCI) && (USB_HOST_CONFIG_OHCI > 0U)) +#include "usb_host_ohci.h" +static const usb_host_controller_interface_t s_OhciInterface = \ +{ + USB_HostOhciCreate, USB_HostOhciDestory, USB_HostOhciOpenPipe, USB_HostOhciClosePipe, + USB_HostOhciWritePipe, USB_HostOhciReadPipe, USB_HostOhciIoctl, +}; +#endif /* USB_HOST_CONFIG_OHCI */ + +#if ((defined USB_HOST_CONFIG_IP3516HS) && (USB_HOST_CONFIG_IP3516HS > 0U)) +#include "usb_host_ip3516hs.h" +static const usb_host_controller_interface_t s_Ip3516HsInterface = \ +{ + USB_HostIp3516HsCreate, USB_HostIp3516HsDestory, USB_HostIp3516HsOpenPipe, USB_HostIp3516HsClosePipe, + USB_HostIp3516HsWritePipe, USB_HostIp3516HsReadPipe, USB_HostIp3516HsIoctl, +}; +#endif /* USB_HOST_CONFIG_IP3516HS */ + +USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) static uint8_t s_Setupbuffer[USB_HOST_CONFIG_MAX_HOST][USB_HOST_CONFIG_MAX_TRANSFERS][USB_DATA_ALIGN_SIZE_MULTIPLE(8)]; +/******************************************************************************* +* Code +******************************************************************************/ + +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) +/*FUNCTION*---------------------------------------------------------------- +* +* Function Name : usb_test_mode_init +* Returned Value : None +* Comments : +* This function is called by common class to initialize the class driver. It +* is called in response to a select interface call by application +* +*END*--------------------------------------------------------------------*/ +usb_status_t USB_HostTestModeInit(usb_device_handle deviceHandle) +{ +#if (((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) || \ + ((defined USB_HOST_CONFIG_IP3516HS) && (USB_HOST_CONFIG_IP3516HS))) + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; +#endif + uint32_t productId; + uint32_t vendorId; + + usb_echo("usb host test init\r\n"); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDevicePID, &productId); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceVID, &vendorId); + usb_echo(" vendor id :0x%x product id:0x%x \r\n", vendorId, productId); + + if ((productId != 0x0200U) && (productId != 0x0101) && (productId != 0x0102) && (productId != 0x0103) && + (productId != 0x0104) && (productId != 0x0105) && (productId != 0x0106) && (productId != 0x0107) && + (productId != 0x0108)) + { + usb_echo("Unsupported Device\r\n"); + } + + if (productId == 0x0200U) + { + usb_echo("PET test device attached\r\n"); + } + else + { +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) + if (hostInstance->controllerTable == &s_EhciInterface) + { + USB_HostEhciTestModeInit(deviceHandle); + } +#elif((defined USB_HOST_CONFIG_IP3516HS) && (USB_HOST_CONFIG_IP3516HS)) + if (hostInstance->controllerTable == &s_Ip3516HsInterface) + { + USB_HostIp3516HsTestModeInit(deviceHandle); + } +#endif + } + + return kStatus_USB_Success; +} +#endif + +static usb_host_instance_t *USB_HostGetInstance(void) +{ + uint8_t i = 0; + uint32_t index = 0; + USB_OSA_SR_ALLOC(); + USB_OSA_ENTER_CRITICAL(); + for (; i < USB_HOST_CONFIG_MAX_HOST; i++) + { + if (g_UsbHostInstance[i].occupied != 1) + { + uint8_t *buffer = (uint8_t *)&g_UsbHostInstance[i]; + for (uint32_t j = 0U; j < sizeof(usb_host_instance_t); j++) + { + buffer[j] = 0x00U; + } + g_UsbHostInstance[i].occupied = 1; + USB_OSA_EXIT_CRITICAL(); + for (index = 0; index < USB_HOST_CONFIG_MAX_TRANSFERS; ++index) + { + g_UsbHostInstance[i].transferList[index].setupPacket = + (usb_setup_struct_t *)&(s_Setupbuffer[i][index][0]); + } + return &g_UsbHostInstance[i]; + } + } + USB_OSA_EXIT_CRITICAL(); + return NULL; +} + +static void USB_HostReleaseInstance(usb_host_instance_t *hostInstance) +{ + USB_OSA_SR_ALLOC(); + USB_OSA_ENTER_CRITICAL(); + hostInstance->occupied = 0; + USB_OSA_EXIT_CRITICAL(); +} + +static void USB_HostGetControllerInterface(uint8_t controllerId, + const usb_host_controller_interface_t **controllerTable) +{ +#if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) + if (controllerId == kUSB_ControllerKhci0) + { + *controllerTable = &s_KhciInterface; + } +#endif /* USB_HOST_CONFIG_KHCI */ + +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) + if ((controllerId == kUSB_ControllerEhci0) || (controllerId == kUSB_ControllerEhci1)) + { + *controllerTable = &s_EhciInterface; + } +#endif /* USB_HOST_CONFIG_EHCI */ + +#if ((defined USB_HOST_CONFIG_OHCI) && (USB_HOST_CONFIG_OHCI > 0U)) + if (controllerId == kUSB_ControllerOhci0) + { + *controllerTable = &s_OhciInterface; + } +#endif /* USB_HOST_CONFIG_OHCI */ + +#if ((defined USB_HOST_CONFIG_IP3516HS) && (USB_HOST_CONFIG_IP3516HS > 0U)) + if (controllerId == kUSB_ControllerIp3516Hs0) + { + *controllerTable = &s_Ip3516HsInterface; + } +#endif /* USB_HOST_CONFIG_IP3516HS */ +} + +usb_status_t USB_HostInit(uint8_t controllerId, usb_host_handle *hostHandle, host_callback_t callbackFn) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = NULL; + usb_host_transfer_t *transferPrev = NULL; + uint8_t i = 0; + + hostInstance = USB_HostGetInstance(); /* get one host instance */ + if (hostInstance == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* get khci/ehci API table */ + USB_HostGetControllerInterface(controllerId, &hostInstance->controllerTable); + if (hostInstance->controllerTable == NULL) + { + USB_HostReleaseInstance(hostInstance); + return kStatus_USB_ControllerNotFound; + } + + /* judge the controller interface one time at here */ + if ((hostInstance->controllerTable->controllerCreate == NULL) || + (hostInstance->controllerTable->controllerDestory == NULL) || + (hostInstance->controllerTable->controllerOpenPipe == NULL) || + (hostInstance->controllerTable->controllerClosePipe == NULL) || + (hostInstance->controllerTable->controllerWritePipe == NULL) || + (hostInstance->controllerTable->controllerReadPipe == NULL) || + (hostInstance->controllerTable->controllerIoctl == NULL)) + { + return kStatus_USB_Error; + } + + /* HOST instance init*/ + hostInstance->controllerId = controllerId; + hostInstance->deviceCallback = callbackFn; + hostInstance->deviceList = NULL; + if (kStatus_USB_OSA_Success != USB_OsaMutexCreate(&hostInstance->hostMutex)) + { + USB_HostReleaseInstance(hostInstance); +#ifdef HOST_ECHO + usb_echo("host init: create host mutex fail\r\n"); +#endif + return kStatus_USB_Error; + } + + /* initialize transfer list */ + + hostInstance->transferHead = &hostInstance->transferList[0]; + transferPrev = hostInstance->transferHead; + for (i = 1; i < USB_HOST_CONFIG_MAX_TRANSFERS; ++i) + { + transferPrev->next = &hostInstance->transferList[i]; + transferPrev = transferPrev->next; + } + + /* controller create, the callbackFn is initialized in USB_HostGetControllerInterface */ + status = + hostInstance->controllerTable->controllerCreate(controllerId, hostInstance, &(hostInstance->controllerHandle)); + if ((status != kStatus_USB_Success) || (hostInstance->controllerHandle == NULL)) + { + USB_OsaMutexDestroy(hostInstance->hostMutex); + USB_HostReleaseInstance(hostInstance); +#ifdef HOST_ECHO + usb_echo("host init: controller init fail\r\n"); +#endif + return kStatus_USB_Error; + } + + *hostHandle = hostInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostDeinit(usb_host_handle hostHandle) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_device_instance_t *deviceInstance = NULL; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* device list detach */ + deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + while (deviceInstance != NULL) + { + deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + USB_HostDetachDeviceInternal(hostHandle, deviceInstance); + } + + /* controller instance destroy, the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerDestory(hostInstance->controllerHandle); + hostInstance->controllerHandle = NULL; + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host controller destroy fail\r\n"); +#endif + } + + /* resource release */ + if (hostInstance->hostMutex) + { + USB_OsaMutexDestroy(hostInstance->hostMutex); + hostInstance->hostMutex = NULL; + } + USB_HostReleaseInstance(hostInstance); + + return status; +} + +usb_status_t USB_HostOpenPipe(usb_host_handle hostHandle, + usb_host_pipe_handle *pipeHandle, + usb_host_pipe_init_t *pipeInit) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (pipeInit == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* call controller open pipe interface, the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerOpenPipe(hostInstance->controllerHandle, pipeHandle, pipeInit); + + return status; +} + +usb_status_t USB_HostClosePipe(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (pipeHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* call controller close pipe interface, the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerClosePipe(hostInstance->controllerHandle, pipeHandle); + + return status; +} + +usb_status_t USB_HostSend(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle, usb_host_transfer_t *transfer) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (pipeHandle == NULL) || (transfer == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* initialize transfer */ + transfer->transferSofar = 0; + transfer->direction = USB_OUT; + + USB_HostLock(); /* This api can be called by host task and app task */ +/* keep this code: in normal situation application will guarantee the device is attached when call send/receive function + */ +#if 0 + if ((USB_HostValidateDevice(pipe_ptr->deviceHandle) != kStatus_USB_Success) || (!(USB_HostGetDeviceAttachState(pipe_ptr->deviceHandle)))) + { + USB_HostUnlock(); + return status; + } +#endif +/* call controller write pipe interface */ +#if ((defined USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) + if (transfer->transferLength > 0) + { + DCACHE_CleanByRange((uint32_t)transfer->transferBuffer, transfer->transferLength); + } +#endif + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerWritePipe(hostInstance->controllerHandle, pipeHandle, transfer); + + USB_HostUnlock(); + return status; +} + +usb_status_t USB_HostSendSetup(usb_host_handle hostHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (pipeHandle == NULL) || (transfer == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* initialize transfer */ + transfer->transferSofar = 0; + transfer->next = NULL; + transfer->setupStatus = 0; + if ((transfer->setupPacket->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_IN) + { + transfer->direction = USB_IN; + } + else + { + transfer->direction = USB_OUT; + } + + USB_HostLock(); /* This API can be called by host task and application task */ +/* keep this code: in normal situation application will guarantee the device is attached when call send/receive function + */ +#if 0 + if ((USB_HostValidateDevice(pipe_ptr->deviceHandle) != kStatus_USB_Success) || (!(USB_HostGetDeviceAttachState(pipe_ptr->deviceHandle)))) + { + USB_HostUnlock(); + return status; + } +#endif +/* call controller write pipe interface */ +#if ((defined USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) + DCACHE_CleanByRange((uint32_t)&transfer->setupPacket->bmRequestType, sizeof(usb_setup_struct_t)); + if (transfer->transferLength > 0) + { + DCACHE_CleanInvalidateByRange((uint32_t)transfer->transferBuffer, transfer->transferLength); + } +#endif + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerWritePipe(hostInstance->controllerHandle, pipeHandle, transfer); + + USB_HostUnlock(); + return status; +} + +usb_status_t USB_HostRecv(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle, usb_host_transfer_t *transfer) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (pipeHandle == NULL) || (transfer == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* initialize transfer */ + transfer->transferSofar = 0; + transfer->direction = USB_IN; + + USB_HostLock(); /* This API can be called by host task and application task */ +/* keep this code: in normal situation application will guarantee the device is attached when call send/receive function + */ +#if 0 + if ((USB_HostValidateDevice(pipe_ptr->deviceHandle) != kStatus_USB_Success) || (!(USB_HostGetDeviceAttachState(pipe_ptr->deviceHandle)))) + { + USB_HostUnlock(); + return status; + } +#endif + +#if ((defined USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) + if (transfer->transferLength > 0) + { + DCACHE_CleanInvalidateByRange((uint32_t)transfer->transferBuffer, transfer->transferLength); + } +#endif + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerReadPipe(hostInstance->controllerHandle, pipeHandle, transfer); + + USB_HostUnlock(); + return status; +} + +usb_status_t USB_HostCancelTransfer(usb_host_handle hostHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_cancel_param_t cancelParam; + + if ((hostHandle == NULL) || (pipeHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* initialize cancel parameter */ + cancelParam.pipeHandle = pipeHandle; + cancelParam.transfer = transfer; + + /* USB_HostLock(); This api can be called by host task and app task */ + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostCancelTransfer, + &cancelParam); + /* USB_HostUnlock(); */ + + return status; +} + +usb_status_t USB_HostMallocTransfer(usb_host_handle hostHandle, usb_host_transfer_t **transfer) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if ((hostHandle == NULL) || (transfer == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* get one from the transfer_head */ + USB_HostLock(); + if (hostInstance->transferHead != NULL) + { + *transfer = hostInstance->transferHead; + hostInstance->transferHead = hostInstance->transferHead->next; + USB_HostUnlock(); + return kStatus_USB_Success; + } + else + { + *transfer = NULL; + USB_HostUnlock(); + return kStatus_USB_Error; + } +} + +usb_status_t USB_HostFreeTransfer(usb_host_handle hostHandle, usb_host_transfer_t *transfer) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + if (transfer == NULL) + { + return kStatus_USB_Success; + } + + /* release one to the transfer_head */ + USB_HostLock(); + transfer->next = hostInstance->transferHead; + hostInstance->transferHead = transfer; + USB_HostUnlock(); + return kStatus_USB_Success; +} + +usb_status_t USB_HostHelperGetPeripheralInformation(usb_device_handle deviceHandle, + uint32_t infoCode, + uint32_t *infoValue) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + if ((deviceHandle == NULL) || (infoValue == NULL)) + { + return kStatus_USB_InvalidParameter; + } + + switch (infoCode) + { + case kUSB_HostGetDeviceAddress: /* device address */ + *infoValue = (uint32_t)deviceInstance->setAddress; + break; + + case kUSB_HostGetDeviceControlPipe: /* device control pipe */ + *infoValue = (uint32_t)deviceInstance->controlPipe; + break; + + case kUSB_HostGetHostHandle: /* device host handle */ + *infoValue = (uint32_t)deviceInstance->hostHandle; + break; + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + case kUSB_HostGetDeviceHubNumber: /* device hub address */ + *infoValue = (uint32_t)deviceInstance->hubNumber; + break; + + case kUSB_HostGetDevicePortNumber: /* device port no */ + *infoValue = (uint32_t)deviceInstance->portNumber; + break; + + case kUSB_HostGetDeviceLevel: /* device level */ + *infoValue = (uint32_t)deviceInstance->level; + break; + + case kUSB_HostGetDeviceHSHubNumber: /* device high-speed hub address */ + *infoValue = (uint32_t)deviceInstance->hsHubNumber; + break; + + case kUSB_HostGetDeviceHSHubPort: /* device high-speed hub port no */ + *infoValue = (uint32_t)deviceInstance->hsHubPort; + break; + + case kUSB_HostGetHubThinkTime: /* device hub think time */ + *infoValue = USB_HostHubGetTotalThinkTime(deviceInstance->hostHandle, deviceInstance->hubNumber); + break; +#else + case kUSB_HostGetDeviceHubNumber: /* device hub address */ + case kUSB_HostGetDevicePortNumber: /* device port no */ + case kUSB_HostGetDeviceHSHubNumber: /* device high-speed hub address */ + case kUSB_HostGetDeviceHSHubPort: /* device high-speed hub port no */ + case kUSB_HostGetHubThinkTime: /* device hub think time */ + *infoValue = 0; + break; + case kUSB_HostGetDeviceLevel: /* device level */ + *infoValue = 1; + break; +#endif /* USB_HOST_CONFIG_HUB */ + + case kUSB_HostGetDeviceSpeed: /* device speed */ + *infoValue = (uint32_t)deviceInstance->speed; + break; + + case kUSB_HostGetDevicePID: /* device pid */ + *infoValue = (uint32_t)USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(deviceInstance->deviceDescriptor->idProduct); + break; + + case kUSB_HostGetDeviceVID: /* device vid */ + *infoValue = (uint32_t)USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(deviceInstance->deviceDescriptor->idVendor); + break; + + case kUSB_HostGetDeviceConfigIndex: /* device config index */ + *infoValue = (uint32_t)deviceInstance->configurationValue - 1U; + break; + + case kUSB_HostGetConfigurationDes: /* configuration descriptor pointer */ + *infoValue = (uint32_t)deviceInstance->configurationDesc; + break; + + case kUSB_HostGetConfigurationLength: /* configuration descriptor length */ + *infoValue = (uint32_t)deviceInstance->configurationLen; + break; + + default: + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHelperParseAlternateSetting(usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + usb_host_interface_t *interface) +{ + uint32_t endPosition; + usb_descriptor_union_t *unionDes; + usb_host_ep_t *epParse; + + if (interfaceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (alternateSetting == 0) + { + return kStatus_USB_InvalidParameter; + } + + /* parse configuration descriptor */ + unionDes = (usb_descriptor_union_t *)((usb_host_interface_t *)interfaceHandle) + ->interfaceDesc; /* interface extend descriptor start */ + endPosition = + (uint32_t)unionDes + + ((usb_host_interface_t *)interfaceHandle)->interfaceExtensionLength; /* interface extend descriptor end */ + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + + /* search for the alternate setting interface descriptor */ + while ((uint32_t)unionDes < endPosition) + { + if (unionDes->interface.bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE) + { + if (unionDes->interface.bAlternateSetting == alternateSetting) + { + break; + } + else + { + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + } + else + { + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + } + if ((uint32_t)unionDes >= endPosition) + { + return kStatus_USB_Error; + } + + /* initialize interface handle structure instance */ + interface->interfaceDesc = &unionDes->interface; + interface->alternateSettingNumber = 0; + interface->epCount = 0; + interface->interfaceExtension = NULL; + interface->interfaceExtensionLength = 0; + interface->interfaceIndex = unionDes->interface.bInterfaceNumber; + + /* search for endpoint descriptor start position */ + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPosition) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) + { + if (interface->interfaceExtension == NULL) + { + interface->interfaceExtension = (uint8_t *)unionDes; + } + interface->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + + /* parse endpoint descriptor */ + if (interface->interfaceDesc->bNumEndpoints != 0) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) || + (interface->interfaceDesc->bNumEndpoints > USB_HOST_CONFIG_INTERFACE_MAX_EP)) + { +#ifdef HOST_ECHO + usb_echo("interface descriptor error\n"); +#endif + return kStatus_USB_Error; + } + for (; interface->epCount < interface->interfaceDesc->bNumEndpoints; (interface->epCount)++) + { + if (((uint32_t)unionDes >= endPosition) || + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) + { +#ifdef HOST_ECHO + usb_echo("endpoint descriptor error\n"); +#endif + return kStatus_USB_Error; + } + epParse = (usb_host_ep_t *)&interface->epList[interface->epCount]; + epParse->epDesc = (usb_descriptor_endpoint_t *)unionDes; + epParse->epExtensionLength = 0; + epParse->epExtension = NULL; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPosition) + { + if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE)) + { + if (epParse->epExtension == NULL) + { + epParse->epExtension = (uint8_t *)unionDes; + } + epParse->epExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + } + } + + return kStatus_USB_Success; +} + +void USB_HostGetVersion(uint32_t *version) +{ + if (version) + { + *version = + (uint32_t)USB_MAKE_VERSION(USB_STACK_VERSION_MAJOR, USB_STACK_VERSION_MINOR, USB_STACK_VERSION_BUGFIX); + } +} + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) +/* Send BUS or specific device suspend request */ +usb_status_t USB_HostSuspendDeviceResquest(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_instance_t *hostInstance; + usb_host_device_instance_t *deviceInstance; + usb_status_t status = kStatus_USB_Error; + usb_host_bus_control_t type = kUSB_HostBusSuspend; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + hostInstance = (usb_host_instance_t *)hostHandle; + + hostInstance->suspendedDevice = (void *)deviceHandle; + + if (NULL == deviceHandle) + { +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + status = USB_HostHubSuspendDevice(hostInstance); +#else + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = + hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, &type); +#endif + } + else + { +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + deviceInstance = (usb_host_device_instance_t *)deviceHandle; + if (0 == deviceInstance->hubNumber) + { +#endif + if (hostInstance->deviceList == deviceHandle) + { + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, + kUSB_HostBusControl, &type); + } +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + } + else + { + if (kStatus_USB_Success == USB_HostValidateDevice(hostInstance, deviceHandle)) + { + status = USB_HostHubSuspendDevice(hostInstance); + } + } +#endif + } + if (kStatus_USB_Error == status) + { + hostInstance->suspendedDevice = NULL; + } + return status; +} + +/* Send BUS or specific device resume request */ +usb_status_t USB_HostResumeDeviceResquest(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_instance_t *hostInstance; + usb_host_device_instance_t *deviceInstance; + usb_status_t status = kStatus_USB_Error; + usb_host_bus_control_t type = kUSB_HostBusResume; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + hostInstance = (usb_host_instance_t *)hostHandle; + + if (hostInstance->suspendedDevice != deviceHandle) + { + return kStatus_USB_InvalidParameter; + } + hostInstance->suspendedDevice = (void *)deviceHandle; + + if (NULL == deviceHandle) + { + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = + hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, &type); + } + else + { +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + deviceInstance = (usb_host_device_instance_t *)deviceHandle; + if (0 == deviceInstance->hubNumber) + { +#endif + if (hostInstance->deviceList == deviceHandle) + { + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, + kUSB_HostBusControl, &type); + } +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + } + else + { + if (kStatus_USB_Success == USB_HostValidateDevice(hostInstance, deviceHandle)) + { + status = USB_HostHubResumeDevice(hostInstance); + } + } +#endif + } + + return status; +} +#if ((defined(USB_HOST_CONFIG_LPM_L1)) && (USB_HOST_CONFIG_LPM_L1 > 0U)) +/* Send BUS or specific device suspend request */ +usb_status_t USB_HostL1SleepDeviceResquest(usb_host_handle hostHandle, + usb_device_handle deviceHandle, + uint8_t sleepType) +{ + usb_host_instance_t *hostInstance; + usb_status_t status = kStatus_USB_Error; + usb_host_bus_control_t type = kUSB_HostBusL1Sleep; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + hostInstance = (usb_host_instance_t *)hostHandle; + + hostInstance->suspendedDevice = (void *)deviceHandle; + + if (1U == sleepType) + { + /*#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))*/ + /*To do, incomplete hub L1 suspend device*/ + /*#else*/ + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = + hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, &type); + /*#endif*/ + } + else + { +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) +/*To do, if device hub number is 0, need suspend the bus ,else suspend the corresponding device*/ +#endif + if (hostInstance->deviceList == deviceHandle) + { + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, + &type); + } + } + if (kStatus_USB_Error == status) + { + hostInstance->suspendedDevice = NULL; + } + return status; +} +/* Send BUS or specific device suspend request */ +usb_status_t USB_HostL1SleepDeviceResquestConfig(usb_host_handle hostHandle, uint8_t *lpmParam) +{ + usb_host_instance_t *hostInstance; + usb_status_t status = kStatus_USB_Error; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + hostInstance = (usb_host_instance_t *)hostHandle; + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = + hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostL1Config, lpmParam); + + return status; +} + +/* Send BUS or specific device resume request */ +usb_status_t USB_HostL1ResumeDeviceResquest(usb_host_handle hostHandle, + usb_device_handle deviceHandle, + uint8_t sleepType) +{ + usb_host_instance_t *hostInstance; + + usb_status_t status = kStatus_USB_Error; + usb_host_bus_control_t type = kUSB_HostBusL1Resume; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + hostInstance = (usb_host_instance_t *)hostHandle; + + if (1U == sleepType) + { + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = + hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, &type); + } + else + { +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) +/*To do, if device hub number is 0, need suspend the bus ,else suspend the corresponding device*/ + +#endif + if (hostInstance->deviceList == deviceHandle) + { + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, + &type); + } + } + + return status; +} +#endif +/* Update HW tick(unit is ms) */ +usb_status_t USB_HostUpdateHwTick(usb_host_handle hostHandle, uint64_t tick) +{ + usb_host_instance_t *hostInstance; + usb_status_t status = kStatus_USB_Success; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + hostInstance = (usb_host_instance_t *)hostHandle; + + hostInstance->hwTick = tick; + + return status; +} +#endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_hci.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_hci.h new file mode 100644 index 000000000..3cdd83df3 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host/usb_host_hci.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _USB_HOST_HCI_H_ +#define _USB_HOST_HCI_H_ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief USB host lock */ +#define USB_HostLock() USB_OsaMutexLock(hostInstance->hostMutex) +/*! @brief USB host unlock */ +#define USB_HostUnlock() USB_OsaMutexUnlock(hostInstance->hostMutex) + +/*! + * @addtogroup usb_host_controller_driver + * @{ + */ + +/*! @brief USB host controller control code */ +typedef enum _usb_host_controller_control +{ + kUSB_HostCancelTransfer = 1U, /*!< Cancel transfer code */ + kUSB_HostBusControl, /*!< Bus control code */ + kUSB_HostGetFrameNumber, /*!< Get frame number code */ + kUSB_HostUpdateControlEndpointAddress, /*!< Update control endpoint address */ + kUSB_HostUpdateControlPacketSize, /*!< Update control endpoint maximum packet size */ + kUSB_HostPortAttachDisable, /*!< Disable the port attach event */ + kUSB_HostPortAttachEnable, /*!< Enable the port attach event */ + kUSB_HostL1Config, /*!< L1 suspend Bus control code */ +} usb_host_controller_control_t; + +/*! @brief USB host controller bus control code */ +typedef enum _usb_host_bus_control +{ + kUSB_HostBusReset = 1U, /*!< Reset bus */ + kUSB_HostBusRestart, /*!< Restart bus */ + kUSB_HostBusEnableAttach, /*!< Enable attach */ + kUSB_HostBusDisableAttach, /*!< Disable attach */ + kUSB_HostBusSuspend, /*!< Suspend BUS */ + kUSB_HostBusResume, /*!< Resume BUS */ + kUSB_HostBusL1SuspendInit, /*!< L1 Suspend BUS */ + kUSB_HostBusL1Sleep, /*!< L1 Suspend BUS */ + kUSB_HostBusL1Resume, /*!< L1 Resume BUS */ +} usb_host_bus_control_t; + +/*! @brief USB host controller interface structure */ +typedef struct _usb_host_controller_interface +{ + usb_status_t (*controllerCreate)( + uint8_t controllerId, + usb_host_handle upperLayerHandle, + usb_host_controller_handle *controllerHandle); /*!< Create a controller instance function prototype*/ + usb_status_t (*controllerDestory)( + usb_host_controller_handle controllerHandle); /*!< Destroy a controller instance function prototype*/ + usb_status_t (*controllerOpenPipe)(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle *pipeHandle, + usb_host_pipe_init_t *pipeInit); /*!< Open a controller pipe function prototype*/ + usb_status_t (*controllerClosePipe)( + usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle); /*!< Close a controller pipe function prototype*/ + usb_status_t (*controllerWritePipe)(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); /*!< Write data to a pipe function prototype*/ + usb_status_t (*controllerReadPipe)(usb_host_controller_handle controllerHandle, + usb_host_pipe_handle pipeHandle, + usb_host_transfer_t *transfer); /*!< Read data from a pipe function prototype*/ + usb_status_t (*controllerIoctl)(usb_host_controller_handle controllerHandle, + uint32_t ioctlEvent, + void *ioctlParam); /*!< Control a controller function prototype*/ +} usb_host_controller_interface_t; + +/*! @}*/ + +/*! + * @addtogroup usb_host_drv + * @{ + */ + +/*! @brief USB host instance structure */ +typedef struct _usb_host_instance +{ + void *controllerHandle; /*!< The low level controller handle*/ + host_callback_t deviceCallback; /*!< Device attach/detach callback*/ + usb_osa_mutex_handle hostMutex; /*!< Host layer mutex*/ + usb_host_transfer_t transferList[USB_HOST_CONFIG_MAX_TRANSFERS]; /*!< Transfer resource*/ + usb_host_transfer_t *transferHead; /*!< Idle transfer head*/ + const usb_host_controller_interface_t *controllerTable; /*!< KHCI/EHCI interface*/ + void *deviceList; /*!< Device list*/ +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + void *suspendedDevice; /*!< Suspended device handle*/ + volatile uint64_t hwTick; /*!< Current hw tick(ms)*/ + uint8_t sleepType; /*!< L1 LPM device handle*/ +#endif + uint8_t addressBitMap[16]; /*!< Used for address allocation. The first bit is the address 1, second bit is the + address 2*/ + uint8_t occupied; /*!< 0 - the instance is not occupied; 1 - the instance is occupied*/ + uint8_t controllerId; /*!< The controller ID*/ +} usb_host_instance_t; + +/*! @}*/ + +#endif /* _USB_HOST_HCI_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host_msd_command.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host_msd_command.c new file mode 100644 index 000000000..176d08bfd --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host_msd_command.c @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016, 2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** +* @file host_msd_command.c +* @brief modify usb msd command test function +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2022-02-10 +*/ + +/************************************************* +File name: usb_misc.h +Description: modify usb_echo to KPrintf +Others: take SDK_2.6.1_MIMXRT1052xxxxB/boards/evkbimxrt1050/usb_examples/usb_host_msd_command for references +History: +1. Date: 2022-02-10 +Author: AIIT XUOS Lab +Modification: +1. modify USB_HostMsdCommandTest, delete read10 and write10 test +2. add USB_HostMsdReadApi and USB_HostMsdWriteApi +3. add UsbMountFileSystem() and UsbUnmountFileSystem() +*************************************************/ + +#include "usb_host_config.h" +#include "usb_host.h" +#include "usb_host_msd.h" +#include "host_msd_command.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#if MSD_THROUGHPUT_TEST_ENABLE +#include "fsl_device_registers.h" +#define THROUGHPUT_BUFFER_SIZE (64 * 1024) /* throughput test buffer */ +#define MCU_CORE_CLOCK (120000000) /* mcu core clock, user need to configure it. */ +#endif /* MSD_THROUGHPUT_TEST_ENABLE */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +extern void UsbMountFileSystem(); +extern void UsbUnmountFileSystem(); + +/*! + * @brief host msd ufi command callback. + * + * This function is used as callback function for ufi command. + * + * @param param the host msd command instance pointer. + * @param data data buffer pointer. + * @param dataLength data length. + * @status transfer result status. + */ +static void USB_HostMsdUfiCallback(void *param, uint8_t *data, uint32_t dataLength, usb_status_t status); + +/*! + * @brief host msd control transfer callback. + * + * This function is used as callback function for control transfer . + * + * @param param the host msd command instance pointer. + * @param data data buffer pointer. + * @param dataLength data length. + * @status transfer result status. + */ +static void USB_HostMsdControlCallback(void *param, uint8_t *data, uint32_t dataLength, usb_status_t status); + +/*! + * @brief host msd command test done. + * + * @param msdCommandInstance the host command instance pointer. + */ +static void msd_command_test_done(usb_host_msd_command_instance_t *msdCommandInstance); + +/*! + * @brief host msd command test. + * + * This function implements msd command test. + * + * @param msdCommandInstance the host command instance pointer. + */ +static void USB_HostMsdCommandTest(usb_host_msd_command_instance_t *msdCommandInstance); + +/******************************************************************************* + * Variables + ******************************************************************************/ +extern usb_host_handle g_HostHandle; /* global host handle */ +usb_host_msd_command_instance_t g_MsdCommandInstance = {0}; /* global msd command instance */ +/* command on-going state. It should set to 1 when start command, it is set to 0 in the callback */ +volatile uint8_t ufiIng; +/* command callback status */ +volatile usb_status_t ufiStatus; + +USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) static uint8_t s_TestUfiBuffer[512]; /*!< test buffer */ + +#if MSD_THROUGHPUT_TEST_ENABLE +USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) static uint32_t testThroughputBuffer[THROUGHPUT_BUFFER_SIZE / 4]; /* the buffer for throughput test */ +uint32_t testSizeArray[] = {50 * 1024, 50 * 1024}; /* test time and test size (uint: K) */ +#endif /* MSD_THROUGHPUT_TEST_ENABLE */ + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostMsdUfiCallback(void *param, uint8_t *data, uint32_t dataLength, usb_status_t status) +{ + ufiIng = 0; + ufiStatus = status; +} + +static void USB_HostMsdControlCallback(void *param, uint8_t *data, uint32_t dataLength, usb_status_t status) +{ + usb_host_msd_command_instance_t *msdCommandInstance = (usb_host_msd_command_instance_t *)param; + + if (msdCommandInstance->runWaitState == kUSB_HostMsdRunWaitSetInterface) /* set interface finish */ + { + msdCommandInstance->runWaitState = kUSB_HostMsdRunIdle; + msdCommandInstance->runState = kUSB_HostMsdRunMassStorageTest; + } +} + +static void msd_command_test_done(usb_host_msd_command_instance_t *msdCommandInstance) +{ + usb_echo("........................check USB device done....................\r\n"); +} + +static inline void USB_HostControllerTaskFunction(usb_host_handle hostHandle) +{ +#if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) + USB_HostKhciTaskFunction(hostHandle); +#endif /* USB_HOST_CONFIG_KHCI */ +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) + USB_HostEhciTaskFunction(hostHandle); +#endif /* USB_HOST_CONFIG_EHCI */ +#if ((defined USB_HOST_CONFIG_OHCI) && (USB_HOST_CONFIG_OHCI > 0U)) + USB_HostOhciTaskFunction(g_HostHandle); +#endif /* USB_HOST_CONFIG_OHCI */ +#if ((defined USB_HOST_CONFIG_IP3516HS) && (USB_HOST_CONFIG_IP3516HS > 0U)) + USB_HostIp3516HsTaskFunction(g_HostHandle); +#endif /* USB_HOST_CONFIG_IP3516HS */ +} + +static void USB_HostMsdCommandTest(usb_host_msd_command_instance_t *msdCommandInstance) +{ + usb_status_t status; + uint32_t blockSize = 512; + uint32_t address; + + usb_echo("........................check USB device start....................\r\n"); + + usb_echo("get max logical units...."); + ufiIng = 1; + status = USB_HostMsdGetMaxLun(msdCommandInstance->classHandle, msdCommandInstance->testUfiBuffer, + USB_HostMsdUfiCallback, msdCommandInstance); + if (status != kStatus_USB_Success) + { + usb_echo("error\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + while (ufiIng) /* wait the command */ + { + USB_HostControllerTaskFunction(g_HostHandle); + } + if (ufiStatus == kStatus_USB_Success) /* print the command result */ + { + usb_echo("success, logical units: %d\r\n", msdCommandInstance->testUfiBuffer[0]); + } + else + { + usb_echo("fail\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + + if (msdCommandInstance->deviceState != kStatus_DEV_Attached) + { + msd_command_test_done(msdCommandInstance); + return; + } + usb_echo("test unit ready...."); + ufiIng = 1; + status = USB_HostMsdTestUnitReady(msdCommandInstance->classHandle, 0, USB_HostMsdUfiCallback, msdCommandInstance); + if (status != kStatus_USB_Success) + { + usb_echo("error\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + while (ufiIng) /* wait the command */ + { + USB_HostControllerTaskFunction(g_HostHandle); + } + if ((ufiStatus == kStatus_USB_Success) || (ufiStatus == kStatus_USB_MSDStatusFail)) /* print the command result */ + { + usb_echo("success, unit status: %s\r\n", ufiStatus == kStatus_USB_MSDStatusFail ? "not ready" : "ready"); + } + else + { + usb_echo("fail\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + + if (msdCommandInstance->deviceState != kStatus_DEV_Attached) + { + msd_command_test_done(msdCommandInstance); + return; + } + usb_echo("request sense...."); + ufiIng = 1; + status = USB_HostMsdRequestSense(msdCommandInstance->classHandle, 0, msdCommandInstance->testUfiBuffer, + sizeof(usb_host_ufi_sense_data_t), USB_HostMsdUfiCallback, msdCommandInstance); + if (status != kStatus_USB_Success) + { + usb_echo("error\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + while (ufiIng) /* wait the command */ + { + USB_HostControllerTaskFunction(g_HostHandle); + } + if (ufiStatus == kStatus_USB_Success) /* print the command result */ + { + usb_echo("success\r\n"); + } + else + { + usb_echo("fail\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + + if (msdCommandInstance->deviceState != kStatus_DEV_Attached) + { + msd_command_test_done(msdCommandInstance); + return; + } + usb_echo("inquiry..."); + ufiIng = 1; + status = USB_HostMsdInquiry(msdCommandInstance->classHandle, 0, msdCommandInstance->testUfiBuffer, + sizeof(usb_host_ufi_inquiry_data_t), USB_HostMsdUfiCallback, msdCommandInstance); + if (status != kStatus_USB_Success) + { + usb_echo("error\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + while (ufiIng) /* wait the command */ + { + USB_HostControllerTaskFunction(g_HostHandle); + } + if (ufiStatus == kStatus_USB_Success) /* print the command result */ + { + usb_echo("success\r\n"); + } + else + { + usb_echo("fail\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + + if (msdCommandInstance->deviceState != kStatus_DEV_Attached) + { + msd_command_test_done(msdCommandInstance); + return; + } + usb_echo("read capacity..."); + ufiIng = 1; + status = USB_HostMsdReadCapacity(msdCommandInstance->classHandle, 0, msdCommandInstance->testUfiBuffer, + sizeof(usb_host_ufi_read_capacity_t), USB_HostMsdUfiCallback, msdCommandInstance); + if (status != kStatus_USB_Success) + { + usb_echo("error\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + while (ufiIng) /* wait the command */ + { + USB_HostControllerTaskFunction(g_HostHandle); + } + if (ufiStatus == kStatus_USB_Success) /* print the command result */ + { + address = (uint32_t) & (msdCommandInstance->testUfiBuffer[0]); + address = (uint32_t)((usb_host_ufi_read_capacity_t *)(address))->blockLengthInBytes; + blockSize = USB_LONG_FROM_BIG_ENDIAN_ADDRESS(((uint8_t *)address)); + address = (uint32_t) & (msdCommandInstance->testUfiBuffer[0]); + address = (uint32_t)((usb_host_ufi_read_capacity_t *)(address))->lastLogicalBlockAddress; + usb_echo("success, last logical block:%d block length:%d\r\n", + USB_LONG_FROM_BIG_ENDIAN_ADDRESS(((uint8_t *)address)), blockSize); + } + else + { + usb_echo("fail\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + + if (msdCommandInstance->deviceState != kStatus_DEV_Attached) + { + msd_command_test_done(msdCommandInstance); + return; + } +#if 1 + if (blockSize == 0) + { + blockSize = 512; + } + usb_echo("read(10)..."); + ufiIng = 1; + status = USB_HostMsdRead10(msdCommandInstance->classHandle, 0, 0, msdCommandInstance->testUfiBuffer, blockSize, 1, + USB_HostMsdUfiCallback, msdCommandInstance); + if (status != kStatus_USB_Success) + { + usb_echo("error\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + while (ufiIng) /* wait the command */ + { + USB_HostControllerTaskFunction(g_HostHandle); + } + if (ufiStatus == kStatus_USB_Success) /* print the command result */ + { + usb_echo("success\r\n"); + } + else + { + usb_echo("fail\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + + if (msdCommandInstance->deviceState != kStatus_DEV_Attached) + { + msd_command_test_done(msdCommandInstance); + return; + } + usb_echo("write(10)..."); + ufiIng = 1; + status = USB_HostMsdWrite10(msdCommandInstance->classHandle, 0, 0, msdCommandInstance->testUfiBuffer, blockSize, 1, + USB_HostMsdUfiCallback, msdCommandInstance); + if (status != kStatus_USB_Success) + { + usb_echo("error\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + while (ufiIng) /* wait the command */ + { + USB_HostControllerTaskFunction(g_HostHandle); + } + if (ufiStatus == kStatus_USB_Success) /* print the command result */ + { + usb_echo("success\r\n"); + } + else + { + usb_echo("fail\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } +#endif + +#if MSD_THROUGHPUT_TEST_ENABLE + uint64_t totalTime; + uint32_t testSize; + uint32_t blockAddress; + uint8_t testIndex; + + /* time delay (~100ms) */ + for (testSize = 0; testSize < 400000; ++testSize) + { + __ASM("nop"); + } + + CoreDebug->DEMCR |= (1 << CoreDebug_DEMCR_TRCENA_Pos); + + for (testSize = 0; testSize < (THROUGHPUT_BUFFER_SIZE / 4); ++testSize) + { + testThroughputBuffer[testSize] = testSize; + } + + usb_echo("throughput test:\r\n"); + for (testIndex = 0; testIndex < (sizeof(testSizeArray) / 4); ++testIndex) + { + totalTime = 0; + blockAddress = 0; + testSize = testSizeArray[testIndex] * 1024; + while (testSize) + { + if (msdCommandInstance->deviceState != kStatus_DEV_Attached) + { + msd_command_test_done(msdCommandInstance); + return; + } + ufiIng = 1; + DWT->CYCCNT = 0; + DWT->CTRL |= (1 << DWT_CTRL_CYCCNTENA_Pos); + status = + USB_HostMsdWrite10(msdCommandInstance->classHandle, 0, blockAddress, + (uint8_t *)&testThroughputBuffer[0], THROUGHPUT_BUFFER_SIZE, + (THROUGHPUT_BUFFER_SIZE / blockSize), USB_HostMsdUfiCallback, msdCommandInstance); + if (status != kStatus_USB_Success) + { + usb_echo(" error\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + while (ufiIng) /* wait the command */ + { + USB_HostControllerTaskFunction(g_HostHandle); + } + totalTime += DWT->CYCCNT; + DWT->CTRL &= ~(1U << DWT_CTRL_CYCCNTENA_Pos); + if (ufiStatus != kStatus_USB_Success) + { + usb_echo("fail\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + testSize -= THROUGHPUT_BUFFER_SIZE; + blockAddress += (THROUGHPUT_BUFFER_SIZE / blockSize); + } + testSize = testSizeArray[testIndex]; + usb_echo(" write %dKB data the speed is %d KB/s\r\n", testSize, + (uint32_t)((uint64_t)testSize * (uint64_t)MCU_CORE_CLOCK / (uint64_t)totalTime)); + + totalTime = 0; + blockAddress = 0; + testSize = testSizeArray[testIndex] * 1024; + while (testSize) + { + if (msdCommandInstance->deviceState != kStatus_DEV_Attached) + { + msd_command_test_done(msdCommandInstance); + return; + } + ufiIng = 1; + DWT->CYCCNT = 0; + DWT->CTRL |= (1 << DWT_CTRL_CYCCNTENA_Pos); + status = + USB_HostMsdRead10(msdCommandInstance->classHandle, 0, blockAddress, (uint8_t *)&testThroughputBuffer[0], + THROUGHPUT_BUFFER_SIZE, (THROUGHPUT_BUFFER_SIZE / blockSize), USB_HostMsdUfiCallback, + msdCommandInstance); + if (status != kStatus_USB_Success) + { + usb_echo(" error\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + while (ufiIng) /* wait the command */ + { + USB_HostControllerTaskFunction(g_HostHandle); + } + totalTime += DWT->CYCCNT; + DWT->CTRL &= ~(1U << DWT_CTRL_CYCCNTENA_Pos); + if (ufiStatus != kStatus_USB_Success) + { + usb_echo("fail\r\n"); + msd_command_test_done(msdCommandInstance); + return; + } + testSize -= THROUGHPUT_BUFFER_SIZE; + blockAddress += (THROUGHPUT_BUFFER_SIZE / blockSize); + } + testSize = testSizeArray[testIndex]; + usb_echo(" read %dKB data the speed is %d KB/s\r\n", testSize, + (uint32_t)((uint64_t)testSize * (uint64_t)MCU_CORE_CLOCK / (uint64_t)totalTime)); + } +#endif /* MSD_THROUGHPUT_TEST_ENABLE */ + + UsbMountFileSystem(); + msd_command_test_done(msdCommandInstance); /* all test are done */ +} + +usb_status_t USB_HostMsdReadApi(usb_host_msd_command_instance_t *msdCommandInstance, uint8_t *buffer, uint32_t pos, uint32_t block_size, uint32_t block_num) +{ + if (msdCommandInstance->deviceState == kStatus_DEV_Attached) { + usb_status_t status; + ufiIng = 1; + status = USB_HostMsdRead10(msdCommandInstance->classHandle, 0, pos, buffer, block_size, block_num, USB_HostMsdUfiCallback, msdCommandInstance); + if (status != kStatus_USB_Success) { + usb_echo("UsbHostRead error\r\n"); + return kStatus_USB_Error; + } + + while (ufiIng) { + USB_HostControllerTaskFunction(g_HostHandle); + } + + if (ufiStatus == kStatus_USB_Success){ + return kStatus_USB_Success; + } + } + + return kStatus_USB_Error; +} + +usb_status_t USB_HostMsdWriteApi(usb_host_msd_command_instance_t *msdCommandInstance, uint8_t *buffer, uint32_t pos, uint32_t block_size, uint32_t block_num) +{ + if (msdCommandInstance->deviceState == kStatus_DEV_Attached) { + usb_status_t status; + ufiIng = 1; + status = USB_HostMsdWrite10(msdCommandInstance->classHandle, 0, pos, buffer, block_size, block_num, USB_HostMsdUfiCallback, msdCommandInstance); + if (status != kStatus_USB_Success) { + usb_echo("UsbHostWrite error\r\n"); + return kStatus_USB_Error; + } + + while (ufiIng) { + USB_HostControllerTaskFunction(g_HostHandle); + } + + if (ufiStatus == kStatus_USB_Success) { + return kStatus_USB_Success; + } + } + + return kStatus_USB_Error; +} + + +void USB_HostMsdTask(void *arg) +{ + usb_status_t status; + usb_host_msd_command_instance_t *msdCommandInstance = (usb_host_msd_command_instance_t *)arg; + + if (msdCommandInstance->deviceState != msdCommandInstance->prevDeviceState) + { + msdCommandInstance->prevDeviceState = msdCommandInstance->deviceState; + switch (msdCommandInstance->deviceState) + { + case kStatus_DEV_Idle: + break; + + case kStatus_DEV_Attached: /* deivce is attached and numeration is done */ + status = USB_HostMsdInit(msdCommandInstance->deviceHandle, + &msdCommandInstance->classHandle); /* msd class initialization */ + if (status != kStatus_USB_Success) + { + usb_echo("usb host msd init fail\r\n"); + return; + } + msdCommandInstance->runState = kUSB_HostMsdRunSetInterface; + break; + + case kStatus_DEV_Detached: /* device is detached */ + UsbUnmountFileSystem(); + msdCommandInstance->deviceState = kStatus_DEV_Idle; + msdCommandInstance->runState = kUSB_HostMsdRunIdle; + USB_HostMsdDeinit(msdCommandInstance->deviceHandle, + msdCommandInstance->classHandle); /* msd class de-initialization */ + msdCommandInstance->classHandle = NULL; + + usb_echo("mass storage device detached\r\n"); + break; + + default: + break; + } + } + + /* run state */ + switch (msdCommandInstance->runState) + { + case kUSB_HostMsdRunIdle: + break; + + case kUSB_HostMsdRunSetInterface: /* set msd interface */ + msdCommandInstance->runState = kUSB_HostMsdRunIdle; + msdCommandInstance->runWaitState = kUSB_HostMsdRunWaitSetInterface; + status = USB_HostMsdSetInterface(msdCommandInstance->classHandle, msdCommandInstance->interfaceHandle, 0, + USB_HostMsdControlCallback, msdCommandInstance); + if (status != kStatus_USB_Success) + { + usb_echo("set interface fail\r\n"); + } + break; + + case kUSB_HostMsdRunMassStorageTest: /* set interface succeed */ + USB_HostMsdCommandTest(msdCommandInstance); /* test msd device */ + msdCommandInstance->runState = kUSB_HostMsdRunIdle; + break; + + default: + break; + } +} + +usb_status_t USB_HostMsdEvent(usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode) +{ + usb_status_t status = kStatus_USB_Success; + uint8_t id; + usb_host_configuration_t *configuration; + uint8_t interfaceIndex; + usb_host_interface_t *interface; + uint32_t infoValue; + + switch (eventCode) + { + case kUSB_HostEventAttach: + /* judge whether is configurationHandle supported */ + configuration = (usb_host_configuration_t *)configurationHandle; + for (interfaceIndex = 0; interfaceIndex < configuration->interfaceCount; ++interfaceIndex) + { + interface = &configuration->interfaceList[interfaceIndex]; + id = interface->interfaceDesc->bInterfaceClass; + if (id != USB_HOST_MSD_CLASS_CODE) + { + continue; + } + id = interface->interfaceDesc->bInterfaceSubClass; + if ((id != USB_HOST_MSD_SUBCLASS_CODE_UFI) && (id != USB_HOST_MSD_SUBCLASS_CODE_SCSI)) + { + continue; + } + id = interface->interfaceDesc->bInterfaceProtocol; + if (id != USB_HOST_MSD_PROTOCOL_BULK) + { + continue; + } + else + { + if (g_MsdCommandInstance.deviceState == kStatus_DEV_Idle) + { + /* the interface is supported by the application */ + g_MsdCommandInstance.testUfiBuffer = s_TestUfiBuffer; + g_MsdCommandInstance.deviceHandle = deviceHandle; + g_MsdCommandInstance.interfaceHandle = interface; + g_MsdCommandInstance.configHandle = configurationHandle; + return kStatus_USB_Success; + } + else + { + continue; + } + } + } + status = kStatus_USB_NotSupported; + break; + + case kUSB_HostEventNotSupported: + break; + + case kUSB_HostEventEnumerationDone: + if (g_MsdCommandInstance.configHandle == configurationHandle) + { + if ((g_MsdCommandInstance.deviceHandle != NULL) && (g_MsdCommandInstance.interfaceHandle != NULL)) + { + /* the device enumeration is done */ + if (g_MsdCommandInstance.deviceState == kStatus_DEV_Idle) + { + g_MsdCommandInstance.deviceState = kStatus_DEV_Attached; + + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDevicePID, &infoValue); + usb_echo("mass storage device attached:pid=0x%x", infoValue); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceVID, &infoValue); + usb_echo("vid=0x%x ", infoValue); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + usb_echo("address=%d\r\n", infoValue); + } + else + { + usb_echo("not idle msd instance\r\n"); + status = kStatus_USB_Error; + } + } + } + break; + + case kUSB_HostEventDetach: + if (g_MsdCommandInstance.configHandle == configurationHandle) + { + /* the device is detached */ + g_MsdCommandInstance.configHandle = NULL; + if (g_MsdCommandInstance.deviceState != kStatus_DEV_Idle) + { + g_MsdCommandInstance.deviceState = kStatus_DEV_Detached; + } + } + break; + + default: + break; + } + return status; +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/host_msd_command.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/host_msd_command.h new file mode 100644 index 000000000..18763ce50 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/host_msd_command.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016, 2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _HOST_MSD_COMMAND_H_ +#define _HOST_MSD_COMMAND_H_ + +#include "usb_host.h" +#include "usb_host_msd.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief 1 - execute throughput test; 0 - don't execute throughput test */ +#define MSD_THROUGHPUT_TEST_ENABLE (0U) + +/*! @brief host app device attach/detach status */ +typedef enum _usb_host_app_state +{ + kStatus_DEV_Idle = 0, /*!< there is no device attach/detach */ + kStatus_DEV_Attached, /*!< device is attached */ + kStatus_DEV_Detached, /*!< device is detached */ +} usb_host_app_state_t; + +/*! @brief host app run status */ +typedef enum _usb_host_msd_run_state +{ + kUSB_HostMsdRunIdle = 0, /*!< idle */ + kUSB_HostMsdRunSetInterface, /*!< execute set interface code */ + kUSB_HostMsdRunWaitSetInterface, /*!< wait set interface done */ + kUSB_HostMsdRunMassStorageTest /*!< execute mass storage test code */ +} usb_host_msd_run_state_t; + +/*! @brief USB host msd command instance structure */ +typedef struct _usb_host_msd_command_instance +{ + usb_host_configuration_handle configHandle; /*!< configuration handle */ + usb_device_handle deviceHandle; /*!< device handle */ + usb_host_class_handle classHandle; /*!< class handle */ + usb_host_interface_handle interfaceHandle; /*!< interface handle */ + uint8_t *testUfiBuffer; /*!< test buffer */ + uint8_t prevDeviceState; /*!< device attach/detach previous status */ + uint8_t deviceState; /*!< device attach/detach status */ + uint8_t runWaitState; /*!< application wait status, go to next run status when the wait status success */ + uint8_t runState; /*!< application run status */ +} usb_host_msd_command_instance_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief host msd callback function. + * + * This function should be called in the host callback function. + * + * @param deviceHandle device handle. + * @param configurationHandle attached device's configuration descriptor information. + * @param eventCode callback event code, please reference to enumeration host_event_t. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_NotSupported The configuration don't contain msd interface. + * @retval kStatus_USB_Error There is no idle msd instance. + */ +extern usb_status_t USB_HostMsdEvent(usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode); + +/*! +* @brief host msd command task function. +* +* This function implements the host msd command action, it is used to create task. +* +* @param arg the host msd command instance pointer. +*/ +extern void USB_HostMsdTask(void *arg); + +#endif /* _HOST_MSD_COMMAND_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb.h new file mode 100644 index 000000000..701c5469d --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_H__ +#define __USB_H__ + +#include +#include +#include "fsl_common.h" +#include "usb_osa.h" +#include "usb_misc.h" +#include "usb_spec.h" + + + +/*! + * @addtogroup usb_drv + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief Defines USB stack major version */ +#define USB_STACK_VERSION_MAJOR (2U) +/*! @brief Defines USB stack minor version */ +#define USB_STACK_VERSION_MINOR (2U) +/*! @brief Defines USB stack bugfix version */ +#define USB_STACK_VERSION_BUGFIX (0U) + +/*! @brief USB stack version definition */ +#define USB_MAKE_VERSION(major, minor, bugfix) (((major) << 16) | ((minor) << 8) | (bugfix)) + +#define MAKE_VERSION(major, minor, bugfix) (((major) << 16) | ((minor) << 8) | (bugfix)) + +/*! @brief USB stack component version definition, changed with component in yaml together */ +#define USB_STACK_COMPONENT_VERSION MAKE_VERSION(2, 2, 0) + +/* + * Component ID used by tools + * + * FSL_COMPONENT_ID "middleware.usb.stack_common" + */ + +/*! @brief USB error code */ +typedef enum _usb_status +{ + kStatus_USB_Success = 0x00U, /*!< Success */ + kStatus_USB_Error, /*!< Failed */ + + kStatus_USB_Busy, /*!< Busy */ + kStatus_USB_InvalidHandle, /*!< Invalid handle */ + kStatus_USB_InvalidParameter, /*!< Invalid parameter */ + kStatus_USB_InvalidRequest, /*!< Invalid request */ + kStatus_USB_ControllerNotFound, /*!< Controller cannot be found */ + kStatus_USB_InvalidControllerInterface, /*!< Invalid controller interface */ + + kStatus_USB_NotSupported, /*!< Configuration is not supported */ + kStatus_USB_Retry, /*!< Enumeration get configuration retry */ + kStatus_USB_TransferStall, /*!< Transfer stalled */ + kStatus_USB_TransferFailed, /*!< Transfer failed */ + kStatus_USB_AllocFail, /*!< Allocation failed */ + kStatus_USB_LackSwapBuffer, /*!< Insufficient swap buffer for KHCI */ + kStatus_USB_TransferCancel, /*!< The transfer cancelled */ + kStatus_USB_BandwidthFail, /*!< Allocate bandwidth failed */ + kStatus_USB_MSDStatusFail, /*!< For MSD, the CSW status means fail */ + kStatus_USB_EHCIAttached, + kStatus_USB_EHCIDetached, +} usb_status_t; + +/*! @brief USB host handle type define */ +typedef void *usb_host_handle; + +/*! @brief USB device handle type define. For device stack it is the whole device handle; for host stack it is the + * attached device instance handle*/ +typedef void *usb_device_handle; + +/*! @brief USB OTG handle type define */ +typedef void *usb_otg_handle; + +/*! @brief USB controller ID */ +typedef enum _usb_controller_index +{ + kUSB_ControllerKhci0 = 0U, /*!< KHCI 0U */ + kUSB_ControllerKhci1 = 1U, /*!< KHCI 1U, Currently, there are no platforms which have two KHCI IPs, this is reserved + to be used in the future. */ + kUSB_ControllerEhci0 = 2U, /*!< EHCI 0U */ + kUSB_ControllerEhci1 = 3U, /*!< EHCI 1U, Currently, there are no platforms which have two EHCI IPs, this is reserved + to be used in the future. */ + + kUSB_ControllerLpcIp3511Fs0 = 4U, /*!< LPC USB IP3511 FS controller 0 */ + kUSB_ControllerLpcIp3511Fs1 = + 5U, /*!< LPC USB IP3511 FS controller 1, there are no platforms which have two IP3511 IPs, this is reserved + to be used in the future. */ + + kUSB_ControllerLpcIp3511Hs0 = 6U, /*!< LPC USB IP3511 HS controller 0 */ + kUSB_ControllerLpcIp3511Hs1 = + 7U, /*!< LPC USB IP3511 HS controller 1, there are no platforms which have two IP3511 IPs, this is reserved + to be used in the future. */ + + kUSB_ControllerOhci0 = 8U, /*!< OHCI 0U */ + kUSB_ControllerOhci1 = 9U, /*!< OHCI 1U, Currently, there are no platforms which have two OHCI IPs, this is reserved + to be used in the future. */ + + kUSB_ControllerIp3516Hs0 = 10U, /*!< IP3516HS 0U */ + kUSB_ControllerIp3516Hs1 = + 11U, /*!< IP3516HS 1U, Currently, there are no platforms which have two IP3516HS IPs, this is reserved + to be used in the future. */ + kUSB_ControllerDwc30 = 12U, /*!< DWC3 0U */ + kUSB_ControllerDwc31 = + 13U, /*!< DWC3 1U Currently, there are no platforms which have two Dwc IPs, this is reserved + to be used in the future.*/ +} usb_controller_index_t; + +/** +* @brief USB stack version fields +*/ +typedef struct _usb_version +{ + uint8_t major; /*!< Major */ + uint8_t minor; /*!< Minor */ + uint8_t bugfix; /*!< Bug fix */ +} usb_version_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! @} */ + +#endif /* __USB_H__ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_host_config.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_host_config.h new file mode 100644 index 000000000..b3636302e --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_host_config.h @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _USB_HOST_CONFIG_H_ +#define _USB_HOST_CONFIG_H_ + +/* Host Controller Enable */ +/*! + * @brief host khci instance count, meantime it indicates khci enable or disable. + * - if 0, host khci driver is disable. + * - if greater than 0, host khci driver is enable. + */ +#define USB_HOST_CONFIG_KHCI (0U) + +/*! + * @brief host ehci instance count, meantime it indicates ehci enable or disable. + * - if 0, host ehci driver is disable. + * - if greater than 0, host ehci driver is enable. + */ +#define USB_HOST_CONFIG_EHCI (2U) + +/*! + * @brief host ohci instance count, meantime it indicates ohci enable or disable. + * - if 0, host ohci driver is disable. + * - if greater than 0, host ohci driver is enable. + */ +#define USB_HOST_CONFIG_OHCI (0U) + +/*! + * @brief host ip3516hs instance count, meantime it indicates ohci enable or disable. + * - if 0, host ip3516hs driver is disable. + * - if greater than 0, host ip3516hs driver is enable. + */ +#define USB_HOST_CONFIG_IP3516HS (0U) + +/* Common configuration macros for all controllers */ + +/*! + * @brief host driver instance max count. + * for example: 2 - one for khci, one for ehci. + */ +#define USB_HOST_CONFIG_MAX_HOST \ + (USB_HOST_CONFIG_KHCI + USB_HOST_CONFIG_EHCI + USB_HOST_CONFIG_OHCI + USB_HOST_CONFIG_IP3516HS) + +/*! + * @brief host pipe max count. + * pipe is the host driver resource for device endpoint, one endpoint need one pipe. + */ +#define USB_HOST_CONFIG_MAX_PIPES (16U) + +/*! + * @brief host transfer max count. + * transfer is the host driver resource for data transmission mission, one transmission mission need one transfer. + */ +#define USB_HOST_CONFIG_MAX_TRANSFERS (16U) + +/*! + * @brief the max endpoint for one interface. + * the max endpoint descriptor number that one interface descriptor contain. + */ +#define USB_HOST_CONFIG_INTERFACE_MAX_EP (4U) + +/*! + * @brief the max interface for one configuration. + * the max interface descriptor number that one configuration descriptor can contain. + */ +#define USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE (5U) + +/*! + * @brief the max power for one device. + * the max power the host can provide for one device. + */ +#define USB_HOST_CONFIG_MAX_POWER (250U) + +/*! + * @brief the max retries for enumeration. + * retry time when enumeration fail. + */ +#define USB_HOST_CONFIG_ENUMERATION_MAX_RETRIES (3U) + +/*! + * @brief the max retries for enumeration setup stall. + * the max times for one transfer can stall. + */ +#define USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES (1U) + +/*! + * @brief the max NAK count for one transaction. + * when nak count reach to the value, the transaction fail. + */ +#define USB_HOST_CONFIG_MAX_NAK (3000U) + +/*! @brief Whether the transfer buffer is cache-enabled or not. */ +#ifndef USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE +#define USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE (0U) +#endif +/*! @brief if 1, enable usb compliance test codes; if 0, disable usb compliance test codes. */ +#define USB_HOST_CONFIG_COMPLIANCE_TEST (0U) + +/*! @brief if 1, class driver clear stall automatically; if 0, class driver don't clear stall. */ +#define USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL (0U) + +/* KHCI configuration */ +#if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) + +/*! + * @brief khci dma align fix buffer size. + */ +#define USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER (64U) + +#endif + +/* EHCI configuration */ +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) + +/*! + * @brief ehci periodic frame list size. + * the value can be 1024, 512, 256, 128, 64, 32, 16 or 8. + */ +#define USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE (1024U) + +/*! + * @brief ehci QH max count. + */ +#define USB_HOST_CONFIG_EHCI_MAX_QH (8U) + +/*! + * @brief ehci QTD max count. + */ +#define USB_HOST_CONFIG_EHCI_MAX_QTD (8U) + +/*! + * @brief ehci ITD max count. + */ +#define USB_HOST_CONFIG_EHCI_MAX_ITD (0U) + +/*! + * @brief ehci SITD max count. + */ +#define USB_HOST_CONFIG_EHCI_MAX_SITD (0U) + +#endif + +/* OHCI configuration */ +#if ((defined USB_HOST_CONFIG_OHCI) && (USB_HOST_CONFIG_OHCI)) + +/*! + * @brief ohci ED max count. + */ +#define USB_HOST_CONFIG_OHCI_MAX_ED (16U) + +/*! + * @brief ohci GTD max count. + */ +#define USB_HOST_CONFIG_OHCI_MAX_GTD (16U) + +/*! + * @brief ohci ITD max count. + */ +#define USB_HOST_CONFIG_OHCI_MAX_ITD (8U) + +#endif + +/* OHCI configuration */ +#if ((defined USB_HOST_CONFIG_IP3516HS) && (USB_HOST_CONFIG_IP3516HS)) + +#define USB_HOST_CONFIG_IP3516HS_MAX_PIPE (32U) + +/*! + * @brief ohci ED max count. + */ +#define USB_HOST_CONFIG_IP3516HS_MAX_ATL (32U) + +/*! + * @brief ohci GTD max count. + */ +#define USB_HOST_CONFIG_IP3516HS_MAX_INT (32U) + +/*! + * @brief ohci ITD max count. + */ +#define USB_HOST_CONFIG_IP3516HS_MAX_ISO (0U) + +#endif + +/*! + * @brief host HUB class instance count, meantime it indicates HUB class enable or disable. + * - if 0, host HUB class driver is disable. + * - if greater than 0, host HUB class driver is enable. + */ +#define USB_HOST_CONFIG_HUB (1U) + +/*! + * @brief host HID class instance count, meantime it indicates HID class enable or disable. + * - if 0, host HID class driver is disable. + * - if greater than 0, host HID class driver is enable. + */ +#define USB_HOST_CONFIG_HID (1U) + +/*! + * @brief host MSD class instance count, meantime it indicates MSD class enable or disable. + * - if 0, host MSD class driver is disable. + * - if greater than 0, host MSD class driver is enable. + */ +#define USB_HOST_CONFIG_MSD (1U) + +/*! + * @brief host CDC class instance count, meantime it indicates CDC class enable or disable. + * - if 0, host CDC class driver is disable. + * - if greater than 0, host CDC class driver is enable. + */ +#define USB_HOST_CONFIG_CDC (1U) + +/*! + * @brief host AUDIO class instance count, meantime it indicates AUDIO class enable or disable. + * - if 0, host AUDIO class driver is disable. + * - if greater than 0, host AUDIO class driver is enable. + */ +#define USB_HOST_CONFIG_AUDIO (1U) + +/*! + * @brief host PHDC class instance count, meantime it indicates PHDC class enable or disable. + * - if 0, host PHDC class driver is disable. + * - if greater than 0, host PHDC class driver is enable. + */ +#define USB_HOST_CONFIG_PHDC (1U) + +/*! + * @brief host printer class instance count, meantime it indicates printer class enable or disable. + * - if 0, host printer class driver is disable. + * - if greater than 0, host printer class driver is enable. + */ +#define USB_HOST_CONFIG_PRINTER (1U) + +#endif /* _USB_HOST_CONFIG_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_misc.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_misc.h new file mode 100644 index 000000000..f76a376bc --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_misc.h @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016, 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** +* @file usb_misc.h +* @brief modify usb_echo to KPrintf +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2022-02-10 +*/ + +/************************************************* +File name: usb_misc.h +Description: modify usb_echo to KPrintf +Others: take SDK_2.6.1_MIMXRT1052xxxxB/middleware/usb/include/usb_misc.h for references +History: +1. Date: 2022-02-10 +Author: AIIT XUOS Lab +Modification: +1. add xiuos.h +2. modify usb_echo to KPrintf +*************************************************/ + +#ifndef __USB_MISC_H__ +#define __USB_MISC_H__ + +#include + +#ifndef ENDIANNESS + +#error ENDIANNESS should be defined, and then rebulid the project. + +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Define USB printf */ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +extern int DbgConsole_Printf(const char *fmt_s, ...); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#if defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE < 1) +#define usb_echo printf +#else +#define usb_echo KPrintf +#endif + +#if defined(__ICCARM__) + +#ifndef STRUCT_PACKED +#define STRUCT_PACKED __packed +#endif + +#ifndef STRUCT_UNPACKED +#define STRUCT_UNPACKED +#endif + +#elif defined(__GNUC__) + +#ifndef STRUCT_PACKED +#define STRUCT_PACKED +#endif + +#ifndef STRUCT_UNPACKED +#define STRUCT_UNPACKED __attribute__((__packed__)) +#endif + +#elif defined(__CC_ARM) || (defined(__ARMCC_VERSION)) + +#ifndef STRUCT_PACKED +#define STRUCT_PACKED _Pragma("pack(1U)") +#endif + +#ifndef STRUCT_UNPACKED +#define STRUCT_UNPACKED _Pragma("pack()") +#endif + +#endif + +#define USB_SHORT_GET_LOW(x) (((uint16_t)x) & 0xFFU) +#define USB_SHORT_GET_HIGH(x) ((uint8_t)(((uint16_t)x) >> 8U) & 0xFFU) + +#define USB_LONG_GET_BYTE0(x) ((uint8_t)(((uint32_t)(x))) & 0xFFU) +#define USB_LONG_GET_BYTE1(x) ((uint8_t)(((uint32_t)(x)) >> 8U) & 0xFFU) +#define USB_LONG_GET_BYTE2(x) ((uint8_t)(((uint32_t)(x)) >> 16U) & 0xFFU) +#define USB_LONG_GET_BYTE3(x) ((uint8_t)(((uint32_t)(x)) >> 24U) & 0xFFU) + +#define USB_MEM4_ALIGN_MASK (0x03U) + +/* accessory macro */ +#define USB_MEM4_ALIGN(n) ((n + 3U) & (0xFFFFFFFCu)) +#define USB_MEM32_ALIGN(n) ((n + 31U) & (0xFFFFFFE0u)) +#define USB_MEM64_ALIGN(n) ((n + 63U) & (0xFFFFFFC0u)) + +/* big/little endian */ +#define SWAP2BYTE_CONST(n) ((((n)&0x00FFU) << 8U) | (((n)&0xFF00U) >> 8U)) +#define SWAP4BYTE_CONST(n) \ + ((((n)&0x000000FFU) << 24U) | (((n)&0x0000FF00U) << 8U) | (((n)&0x00FF0000U) >> 8U) | (((n)&0xFF000000U) >> 24U)) + +#define USB_ASSIGN_VALUE_ADDRESS_LONG_BY_BYTE(n, m) \ + { \ + *((uint8_t *)&(n)) = *((uint8_t *)&(m)); \ + *((uint8_t *)&(n) + 1) = *((uint8_t *)&(m) + 1); \ + *((uint8_t *)&(n) + 2) = *((uint8_t *)&(m) + 2); \ + *((uint8_t *)&(n) + 3) = *((uint8_t *)&(m) + 3); \ + } + +#define USB_ASSIGN_VALUE_ADDRESS_SHORT_BY_BYTE(n, m) \ + { \ + *((uint8_t *)&(n)) = *((uint8_t *)&(m)); \ + *((uint8_t *)&(n) + 1) = *((uint8_t *)&(m) + 1); \ + } + +#define USB_ASSIGN_MACRO_VALUE_ADDRESS_LONG_BY_BYTE(n, m) \ + { \ + *((uint8_t *)&(n)) = (uint8_t)m; \ + *((uint8_t *)&(n) + 1) = (uint8_t)(m >> 8); \ + *((uint8_t *)&(n) + 2) = (uint8_t)(m >> 16); \ + *((uint8_t *)&(n) + 3) = (uint8_t)(m >> 24); \ + } + +#define USB_ASSIGN_MACRO_VALUE_ADDRESS_SHORT_BY_BYTE(n, m) \ + { \ + *((uint8_t *)&(n)) = (uint8_t)m; \ + *((uint8_t *)&(n) + 1) = (uint8_t)(m >> 8); \ + } + +#if (ENDIANNESS == USB_BIG_ENDIAN) + +#define USB_SHORT_TO_LITTLE_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_TO_LITTLE_ENDIAN(n) SWAP4BYTE_CONST(n) +#define USB_SHORT_FROM_LITTLE_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_FROM_LITTLE_ENDIAN(n) SWAP2BYTE_CONST(n) + +#define USB_SHORT_TO_BIG_ENDIAN(n) (n) +#define USB_LONG_TO_BIG_ENDIAN(n) (n) +#define USB_SHORT_FROM_BIG_ENDIAN(n) (n) +#define USB_LONG_FROM_BIG_ENDIAN(n) (n) + +#define USB_LONG_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[3] = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + m[2] = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + m[1] = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + m[0] = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(n) \ + ((uint32_t)((((uint8_t)n[3]) << 24U) | (((uint8_t)n[2]) << 16U) | (((uint8_t)n[1]) << 8U) | \ + (((uint8_t)n[0]) << 0U))) + +#define USB_LONG_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + m[1] = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + m[2] = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + m[3] = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_BIG_ENDIAN_ADDRESS(n) \ + ((uint32_t)((((uint8_t)n[0]) << 24U) | (((uint8_t)n[1]) << 16U) | (((uint8_t)n[2]) << 8U) | \ + (((uint8_t)n[3]) << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[1] = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + m[0] = (((uint16_t)(n)) & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(n) ((uint32_t)((((uint8_t)n[1]) << 8U) | (((uint8_t)n[0]) << 0U))) + +#define USB_SHORT_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + m[1] = (((uint16_t)(n)) & 0xFFU); \ + } + +#define USB_SHORT_FROM_BIG_ENDIAN_ADDRESS(n) ((uint32_t)((((uint8_t)n[0]) << 8U) | (((uint8_t)n[1]) << 0U))) + +#define USB_LONG_TO_LITTLE_ENDIAN_DATA(n, m) \ + { \ + *((uint8_t *)&(m) + 3) = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + *((uint8_t *)&(m) + 2) = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + *((uint8_t *)&(m) + 1) = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + *((uint8_t *)&(m) + 0) = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_DATA(n) \ + ((uint32_t)(((*((uint8_t *)&(n) + 3)) << 24U) | ((*((uint8_t *)&(n) + 2)) << 16U) | \ + ((*((uint8_t *)&(n) + 1)) << 8U) | ((*((uint8_t *)&(n))) << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_DATA(n, m) \ + { \ + *((uint8_t *)&(m) + 1) = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + *((uint8_t *)&(m)) = ((((uint16_t)(n))) & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_DATA(n) ((uint32_t)(((*((uint8_t *)&(n) + 1)) << 8U) | ((*((uint8_t *)&(n)))))) + +#else + +#define USB_SHORT_TO_LITTLE_ENDIAN(n) (n) +#define USB_LONG_TO_LITTLE_ENDIAN(n) (n) +#define USB_SHORT_FROM_LITTLE_ENDIAN(n) (n) +#define USB_LONG_FROM_LITTLE_ENDIAN(n) (n) + +#define USB_SHORT_TO_BIG_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_TO_BIG_ENDIAN(n) SWAP4BYTE_CONST(n) +#define USB_SHORT_FROM_BIG_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_FROM_BIG_ENDIAN(n) SWAP4BYTE_CONST(n) + +#define USB_LONG_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[3] = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + m[2] = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + m[1] = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + m[0] = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(n) \ + ((uint32_t)((((uint8_t)n[3]) << 24U) | (((uint8_t)n[2]) << 16U) | (((uint8_t)n[1]) << 8U) | \ + (((uint8_t)n[0]) << 0U))) + +#define USB_LONG_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + m[1] = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + m[2] = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + m[3] = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_BIG_ENDIAN_ADDRESS(n) \ + ((uint32_t)((((uint8_t)n[0]) << 24U) | (((uint8_t)n[1]) << 16U) | (((uint8_t)n[2]) << 8U) | \ + (((uint8_t)n[3]) << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[1] = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + m[0] = (((uint16_t)(n)) & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(n) ((uint32_t)((((uint8_t)n[1]) << 8U) | (((uint8_t)n[0]) << 0U))) + +#define USB_SHORT_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + m[1] = (((uint16_t)(n)) & 0xFFU); \ + } + +#define USB_SHORT_FROM_BIG_ENDIAN_ADDRESS(n) ((uint32_t)((((uint8_t)n[0]) << 8U) | (((uint8_t)n[1]) << 0U))) + +#define USB_LONG_TO_LITTLE_ENDIAN_DATA(n, m) \ + { \ + *((uint8_t *)&(m) + 3) = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + *((uint8_t *)&(m) + 2) = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + *((uint8_t *)&(m) + 1) = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + *((uint8_t *)&(m) + 0) = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_DATA(n) \ + ((uint32_t)(((*((uint8_t *)&(n) + 3)) << 24U) | ((*((uint8_t *)&(n) + 2)) << 16U) | \ + ((*((uint8_t *)&(n) + 1)) << 8U) | ((*((uint8_t *)&(n))) << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_DATA(n, m) \ + { \ + *((uint8_t *)&(m) + 1) = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + *((uint8_t *)&(m)) = ((((uint16_t)(n))) & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_DATA(n) ((uint32_t)(((*((uint8_t *)&(n) + 1)) << 8U) | ((*((uint8_t *)&(n)))))) + +#endif + +/* + * The following MACROs (USB_GLOBAL, USB_BDT, USB_RAM_ADDRESS_ALIGNMENT, etc) are only used for USB device stack. + * The USB device global variables are put into the section m_usb_global and m_usb_bdt or the section + * .bss.m_usb_global and .bss.m_usb_bdt by using the MACRO USB_GLOBAL and USB_BDT. In this way, the USB device + * global variables can be linked into USB dedicated RAM by USB_STACK_USE_DEDICATED_RAM. + * The MACRO USB_STACK_USE_DEDICATED_RAM is used to decide the USB stack uses dedicated RAM or not. The value of + * the macro can be set as 0, USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL, or USB_STACK_DEDICATED_RAM_TYPE_BDT. + * The MACRO USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL means USB device global variables, including USB_BDT and + * USB_GLOBAL, are put into the USB dedicated RAM. This feature can only be enabled when the USB dedicated RAM + * is not less than 2K Bytes. + * The MACRO USB_STACK_DEDICATED_RAM_TYPE_BDT means USB device global variables, only including USB_BDT, are put + * into the USB dedicated RAM, the USB_GLOBAL will be put into .bss section. This feature is used for some SOCs, + * the USB dedicated RAM size is not more than 512 Bytes. + */ +#define USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL 1 +#define USB_STACK_DEDICATED_RAM_TYPE_BDT 2 + +#if defined(__ICCARM__) + +#define USB_WEAK_VAR __attribute__((weak)) +#define USB_WEAK_FUN __attribute__((weak)) +/* disable misra 19.13 */ +_Pragma("diag_suppress=Pm120") +#define USB_ALIGN_PRAGMA(x) _Pragma(#x) + _Pragma("diag_default=Pm120") + +#define USB_RAM_ADDRESS_ALIGNMENT(n) USB_ALIGN_PRAGMA(data_alignment = n) + _Pragma("diag_suppress=Pm120") +#define USB_LINK_SECTION_PART(str) _Pragma(#str) +#define USB_LINK_DMA_INIT_DATA(sec) USB_LINK_SECTION_PART(location = #sec) +#define USB_LINK_USB_GLOBAL _Pragma("location = \"m_usb_global\"") +#define USB_LINK_USB_BDT _Pragma("location = \"m_usb_bdt\"") +#define USB_LINK_USB_GLOBAL_BSS _Pragma("location = \".bss.m_usb_global\"") +#define USB_LINK_USB_BDT_BSS _Pragma("location = \".bss.m_usb_bdt\"") + _Pragma("diag_default=Pm120") +#define USB_LINK_DMA_NONINIT_DATA _Pragma("location = \"m_usb_dma_noninit_data\"") +#define USB_LINK_NONCACHE_NONINIT_DATA _Pragma("location = \"NonCacheable\"") +#elif defined(__CC_ARM) || (defined(__ARMCC_VERSION)) + +#define USB_WEAK_VAR __attribute__((weak)) +#define USB_WEAK_FUN __attribute__((weak)) +#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n))) +#define USB_LINK_DMA_INIT_DATA(sec) __attribute__((section(#sec))) +#define USB_LINK_USB_GLOBAL __attribute__((section("m_usb_global"))) __attribute__((zero_init)) +#define USB_LINK_USB_BDT __attribute__((section("m_usb_bdt"))) __attribute__((zero_init)) +#define USB_LINK_USB_GLOBAL_BSS __attribute__((section(".bss.m_usb_global"))) __attribute__((zero_init)) +#define USB_LINK_USB_BDT_BSS __attribute__((section(".bss.m_usb_bdt"))) __attribute__((zero_init)) +#define USB_LINK_DMA_NONINIT_DATA __attribute__((section("m_usb_dma_noninit_data"))) __attribute__((zero_init)) +#define USB_LINK_NONCACHE_NONINIT_DATA __attribute__((section("NonCacheable"))) __attribute__((zero_init)) + +#elif defined(__GNUC__) + +#define USB_WEAK_VAR __attribute__((weak)) +#define USB_WEAK_FUN __attribute__((weak)) +#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n))) +#define USB_LINK_DMA_INIT_DATA(sec) __attribute__((section(#sec))) +#define USB_LINK_USB_GLOBAL __attribute__((section("m_usb_global, \"aw\", %nobits @"))) +#define USB_LINK_USB_BDT __attribute__((section("m_usb_bdt, \"aw\", %nobits @"))) +#define USB_LINK_USB_GLOBAL_BSS __attribute__((section(".bss.m_usb_global, \"aw\", %nobits @"))) +#define USB_LINK_USB_BDT_BSS __attribute__((section(".bss.m_usb_bdt, \"aw\", %nobits @"))) +#define USB_LINK_DMA_NONINIT_DATA __attribute__((section("m_usb_dma_noninit_data, \"aw\", %nobits @"))) +#define USB_LINK_NONCACHE_NONINIT_DATA __attribute__((section("NonCacheable, \"aw\", %nobits @"))) + +#else +#error The tool-chain is not supported. +#endif + +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE)) || \ + (defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) + +#if ((defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)) && (defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE))) +#define USB_CACHE_LINESIZE MAX(FSL_FEATURE_L2CACHE_LINESIZE_BYTE, FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) +#elif (defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)) +#define USB_CACHE_LINESIZE MAX(FSL_FEATURE_L2CACHE_LINESIZE_BYTE, 0) +#elif (defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)) +#define USB_CACHE_LINESIZE MAX(0, FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) +#else +#define USB_CACHE_LINESIZE 4 +#endif + +#else +#define USB_CACHE_LINESIZE 4 +#endif + +#if (((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U)) || \ + ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))) +#define USB_DATA_ALIGN 64 +#else +#define USB_DATA_ALIGN 4 +#endif + +#define USB_DATA_ALIGN_SIZE MAX(USB_CACHE_LINESIZE, USB_DATA_ALIGN) + +#define USB_DATA_ALIGN_SIZE_MULTIPLE(n) ((n + USB_DATA_ALIGN_SIZE - 1U) & (~(USB_DATA_ALIGN_SIZE - 1U))) + +#if defined(USB_STACK_USE_DEDICATED_RAM) && (USB_STACK_USE_DEDICATED_RAM == USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL) + +#define USB_GLOBAL USB_LINK_USB_GLOBAL +#define USB_BDT USB_LINK_USB_BDT + +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE)) || \ + (defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) +#define USB_DMA_DATA_NONINIT_SUB USB_LINK_DMA_NONINIT_DATA +#define USB_DMA_DATA_INIT_SUB USB_LINK_DMA_INIT_DATA(m_usb_dma_init_data) +#define USB_CONTROLLER_DATA USB_LINK_NONCACHE_NONINIT_DATA +#else +#define USB_DMA_DATA_NONINIT_SUB +#define USB_DMA_DATA_INIT_SUB +#define USB_CONTROLLER_DATA USB_LINK_USB_GLOBAL +#endif + +#elif defined(USB_STACK_USE_DEDICATED_RAM) && (USB_STACK_USE_DEDICATED_RAM == USB_STACK_DEDICATED_RAM_TYPE_BDT) + +#define USB_BDT USB_LINK_USB_BDT + +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE)) || \ + (defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) +#define USB_GLOBAL USB_LINK_DMA_NONINIT_DATA +#define USB_DMA_DATA_NONINIT_SUB USB_LINK_DMA_NONINIT_DATA +#define USB_DMA_DATA_INIT_SUB USB_LINK_DMA_INIT_DATA(m_usb_dma_init_data) +#define USB_CONTROLLER_DATA USB_LINK_NONCACHE_NONINIT_DATA +#else +#define USB_GLOBAL USB_LINK_USB_GLOBAL_BSS +#define USB_DMA_DATA_NONINIT_SUB +#define USB_DMA_DATA_INIT_SUB +#define USB_CONTROLLER_DATA +#endif + +#else + +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE)) || \ + (defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) + +#define USB_GLOBAL USB_LINK_DMA_NONINIT_DATA +#define USB_BDT USB_LINK_NONCACHE_NONINIT_DATA +#define USB_DMA_DATA_NONINIT_SUB USB_LINK_DMA_NONINIT_DATA +#define USB_DMA_DATA_INIT_SUB USB_LINK_DMA_INIT_DATA(m_usb_dma_init_data) +#define USB_CONTROLLER_DATA USB_LINK_NONCACHE_NONINIT_DATA + +#else +#define USB_GLOBAL USB_LINK_USB_GLOBAL_BSS +#define USB_BDT USB_LINK_USB_BDT_BSS +#define USB_DMA_DATA_NONINIT_SUB +#define USB_DMA_DATA_INIT_SUB +#define USB_CONTROLLER_DATA +#endif + +#endif + +#define USB_DMA_NONINIT_DATA_ALIGN(n) USB_RAM_ADDRESS_ALIGNMENT(n) USB_DMA_DATA_NONINIT_SUB +#define USB_DMA_INIT_DATA_ALIGN(n) USB_RAM_ADDRESS_ALIGNMENT(n) USB_DMA_DATA_INIT_SUB + +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE)) || \ + (defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) +#define USB_DMA_DATA_NONCACHEABLE USB_LINK_NONCACHE_NONINIT_DATA + +#else +#define USB_DMA_DATA_NONCACHEABLE +#endif + +#define USB_GLOBAL_DEDICATED_RAM USB_LINK_USB_GLOBAL + +/* #define USB_RAM_ADDRESS_NONCACHEREG_ALIGNMENT(n, var) AT_NONCACHEABLE_SECTION_ALIGN(var, n) */ +/* #define USB_RAM_ADDRESS_NONCACHEREG(var) AT_NONCACHEABLE_SECTION(var) */ + +#endif /* __USB_MISC_H__ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_spec.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_spec.h new file mode 100644 index 000000000..650ba1cb3 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/include/usb_spec.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_SPEC_H__ +#define __USB_SPEC_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* USB speed (the value cannot be changed because EHCI QH use the value directly)*/ +#define USB_SPEED_FULL (0x00U) +#define USB_SPEED_LOW (0x01U) +#define USB_SPEED_HIGH (0x02U) +#define USB_SPEED_SUPER (0x04U) + +/* Set up packet structure */ +typedef struct _usb_setup_struct +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} usb_setup_struct_t; + +/* USB standard descriptor endpoint type */ +#define USB_ENDPOINT_CONTROL (0x00U) +#define USB_ENDPOINT_ISOCHRONOUS (0x01U) +#define USB_ENDPOINT_BULK (0x02U) +#define USB_ENDPOINT_INTERRUPT (0x03U) + +/* USB standard descriptor transfer direction (cannot change the value because iTD use the value directly) */ +#define USB_OUT (0U) +#define USB_IN (1U) + +/* USB standard descriptor length */ +#define USB_DESCRIPTOR_LENGTH_DEVICE (0x12U) +#define USB_DESCRIPTOR_LENGTH_CONFIGURE (0x09U) +#define USB_DESCRIPTOR_LENGTH_INTERFACE (0x09U) +#define USB_DESCRIPTOR_LENGTH_ENDPOINT (0x07U) +#define USB_DESCRIPTOR_LENGTH_ENDPOINT_COMPANION (0x06U) +#define USB_DESCRIPTOR_LENGTH_DEVICE_QUALITIER (0x0AU) +#define USB_DESCRIPTOR_LENGTH_OTG_DESCRIPTOR (5U) +#define USB_DESCRIPTOR_LENGTH_BOS_DESCRIPTOR (5U) +#define USB_DESCRIPTOR_LENGTH_DEVICE_CAPABILITY_USB20_EXTENSION (0x07U) +#define USB_DESCRIPTOR_LENGTH_DEVICE_CAPABILITY_SUPERSPEED (0x0AU) + +/* USB Device Capability Type Codes */ +#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY_WIRELESS (0x01U) +#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY_USB20_EXTENSION (0x02U) +#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY_SUPERSPEED (0x03U) + +/* USB standard descriptor type */ +#define USB_DESCRIPTOR_TYPE_DEVICE (0x01U) +#define USB_DESCRIPTOR_TYPE_CONFIGURE (0x02U) +#define USB_DESCRIPTOR_TYPE_STRING (0x03U) +#define USB_DESCRIPTOR_TYPE_INTERFACE (0x04U) +#define USB_DESCRIPTOR_TYPE_ENDPOINT (0x05U) +#define USB_DESCRIPTOR_TYPE_DEVICE_QUALITIER (0x06U) +#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION (0x07U) +#define USB_DESCRIPTOR_TYPE_INTERFAACE_POWER (0x08U) +#define USB_DESCRIPTOR_TYPE_OTG (0x09U) +#define USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION (0x0BU) +#define USB_DESCRIPTOR_TYPE_BOS (0x0F) +#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY (0x10) + +#define USB_DESCRIPTOR_TYPE_HID (0x21U) +#define USB_DESCRIPTOR_TYPE_HID_REPORT (0x22U) +#define USB_DESCRIPTOR_TYPE_HID_PHYSICAL (0x23U) + +#define USB_DESCRIPTOR_TYPE_ENDPOINT_COMPANION (0x30U) + +/* USB standard request type */ +#define USB_REQUEST_TYPE_DIR_MASK (0x80U) +#define USB_REQUEST_TYPE_DIR_SHIFT (7U) +#define USB_REQUEST_TYPE_DIR_OUT (0x00U) +#define USB_REQUEST_TYPE_DIR_IN (0x80U) + +#define USB_REQUEST_TYPE_TYPE_MASK (0x60U) +#define USB_REQUEST_TYPE_TYPE_SHIFT (5U) +#define USB_REQUEST_TYPE_TYPE_STANDARD (0U) +#define USB_REQUEST_TYPE_TYPE_CLASS (0x20U) +#define USB_REQUEST_TYPE_TYPE_VENDOR (0x40U) + +#define USB_REQUEST_TYPE_RECIPIENT_MASK (0x1FU) +#define USB_REQUEST_TYPE_RECIPIENT_SHIFT (0U) +#define USB_REQUEST_TYPE_RECIPIENT_DEVICE (0x00U) +#define USB_REQUEST_TYPE_RECIPIENT_INTERFACE (0x01U) +#define USB_REQUEST_TYPE_RECIPIENT_ENDPOINT (0x02U) +#define USB_REQUEST_TYPE_RECIPIENT_OTHER (0x03U) + +/* USB standard request */ +#define USB_REQUEST_STANDARD_GET_STATUS (0x00U) +#define USB_REQUEST_STANDARD_CLEAR_FEATURE (0x01U) +#define USB_REQUEST_STANDARD_SET_FEATURE (0x03U) +#define USB_REQUEST_STANDARD_SET_ADDRESS (0x05U) +#define USB_REQUEST_STANDARD_GET_DESCRIPTOR (0x06U) +#define USB_REQUEST_STANDARD_SET_DESCRIPTOR (0x07U) +#define USB_REQUEST_STANDARD_GET_CONFIGURATION (0x08U) +#define USB_REQUEST_STANDARD_SET_CONFIGURATION (0x09U) +#define USB_REQUEST_STANDARD_GET_INTERFACE (0x0AU) +#define USB_REQUEST_STANDARD_SET_INTERFACE (0x0BU) +#define USB_REQUEST_STANDARD_SYNCH_FRAME (0x0CU) + +/* USB standard request GET Status */ +#define USB_REQUEST_STANDARD_GET_STATUS_DEVICE_SELF_POWERED_SHIFT (0U) +#define USB_REQUEST_STANDARD_GET_STATUS_DEVICE_REMOTE_WARKUP_SHIFT (1U) + +#define USB_REQUEST_STANDARD_GET_STATUS_ENDPOINT_HALT_MASK (0x01U) +#define USB_REQUEST_STANDARD_GET_STATUS_ENDPOINT_HALT_SHIFT (0U) + +#define USB_REQUEST_STANDARD_GET_STATUS_OTG_STATUS_SELECTOR (0xF000U) + +/* USB standard request CLEAR/SET feature */ +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT (0U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP (1U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_TEST_MODE (2U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_B_HNP_ENABLE (3U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_A_HNP_SUPPORT (4U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_A_ALT_HNP_SUPPORT (5U) + +/* USB standard descriptor configure bmAttributes */ +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_D7_MASK (0x80U) +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_D7_SHIFT (7U) + +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_SELF_POWERED_MASK (0x40U) +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_SELF_POWERED_SHIFT (6U) + +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_REMOTE_WAKEUP_MASK (0x20U) +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_REMOTE_WAKEUP_SHIFT (5U) + +/* USB standard descriptor endpoint bmAttributes */ +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK (0x80U) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT (7U) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT (0U) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN (0x80U) + +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK (0x0FU) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_SHFIT (0U) + +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK (0x03U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_NUMBER_SHFIT (0U) + +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_MASK (0x0CU) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_SHFIT (2U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_NO_SYNC (0x00U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_ASYNC (0x04U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_ADAPTIVE (0x08U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_SYNC (0x0CU) + +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_MASK (0x30U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_SHFIT (4U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_DATA_ENDPOINT (0x00U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_FEEDBACK_ENDPOINT (0x10U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_IMPLICIT_FEEDBACK_DATA_ENDPOINT (0x20U) + +#define USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK (0x07FFu) +#define USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK (0x1800u) +#define USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_SHFIT (11U) + +/* USB standard descriptor otg bmAttributes */ +#define USB_DESCRIPTOR_OTG_ATTRIBUTES_SRP_MASK (0x01u) +#define USB_DESCRIPTOR_OTG_ATTRIBUTES_HNP_MASK (0x02u) +#define USB_DESCRIPTOR_OTG_ATTRIBUTES_ADP_MASK (0x04u) + +/* USB standard descriptor device capability usb20 extension bmAttributes */ +#define USB_DESCRIPTOR_DEVICE_CAPABILITY_USB20_EXTENSION_LPM_MASK (0x02U) +#define USB_DESCRIPTOR_DEVICE_CAPABILITY_USB20_EXTENSION_LPM_SHIFT (1U) +#define USB_DESCRIPTOR_DEVICE_CAPABILITY_USB20_EXTENSION_BESL_MASK (0x04U) +#define USB_DESCRIPTOR_DEVICE_CAPABILITY_USB20_EXTENSION_BESL_SHIFT (2U) + + +/* Language structure */ +typedef struct _usb_language +{ + uint8_t **string; /* The Strings descriptor array */ + uint32_t *length; /* The strings descriptor length array */ + uint16_t languageId; /* The language id of current language */ +} usb_language_t; + +typedef struct _usb_language_list +{ + uint8_t *languageString; /* The String 0U pointer */ + uint32_t stringLength; /* The String 0U Length */ + usb_language_t *languageList; /* The language list */ + uint8_t count; /* The language count */ +} usb_language_list_t; + +typedef struct _usb_descriptor_common +{ + uint8_t bLength; /* Size of this descriptor in bytes */ + uint8_t bDescriptorType; /* DEVICE Descriptor Type */ + uint8_t bData[1]; /* Data */ +} usb_descriptor_common_t; + +typedef struct _usb_descriptor_device +{ + uint8_t bLength; /* Size of this descriptor in bytes */ + uint8_t bDescriptorType; /* DEVICE Descriptor Type */ + uint8_t bcdUSB[2]; /* UUSB Specification Release Number in Binary-Coded Decimal, e.g. 0x0200U */ + uint8_t bDeviceClass; /* Class code */ + uint8_t bDeviceSubClass; /* Sub-Class code */ + uint8_t bDeviceProtocol; /* Protocol code */ + uint8_t bMaxPacketSize0; /* Maximum packet size for endpoint zero */ + uint8_t idVendor[2]; /* Vendor ID (assigned by the USB-IF) */ + uint8_t idProduct[2]; /* Product ID (assigned by the manufacturer) */ + uint8_t bcdDevice[2]; /* Device release number in binary-coded decimal */ + uint8_t iManufacturer; /* Index of string descriptor describing manufacturer */ + uint8_t iProduct; /* Index of string descriptor describing product */ + uint8_t iSerialNumber; /* Index of string descriptor describing the device serial number */ + uint8_t bNumConfigurations; /* Number of possible configurations */ +} usb_descriptor_device_t; + +typedef struct _usb_descriptor_configuration +{ + uint8_t bLength; /* Descriptor size in bytes = 9U */ + uint8_t bDescriptorType; /* CONFIGURATION type = 2U or 7U */ + uint8_t wTotalLength[2]; /* Length of concatenated descriptors */ + uint8_t bNumInterfaces; /* Number of interfaces, this configuration. */ + uint8_t bConfigurationValue; /* Value to set this configuration. */ + uint8_t iConfiguration; /* Index to configuration string */ + uint8_t bmAttributes; /* Configuration characteristics */ + uint8_t bMaxPower; /* Maximum power from bus, 2 mA units */ +} usb_descriptor_configuration_t; + +typedef struct _usb_descriptor_interface +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} usb_descriptor_interface_t; + +typedef struct _usb_descriptor_endpoint +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint8_t wMaxPacketSize[2]; + uint8_t bInterval; +} usb_descriptor_endpoint_t; + +typedef struct _usb_descriptor_endpoint_companion +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bMaxBurst; + uint8_t bmAttributes; + uint8_t wBytesPerInterval[2]; +} usb_descriptor_endpoint_companion_t; + +typedef struct _usb_descriptor_binary_device_object_store +{ + uint8_t bLength; /* Descriptor size in bytes = 5U */ + uint8_t bDescriptorType; /* BOS Descriptor type = 0FU*/ + uint8_t wTotalLength[2]; /*Length of this descriptor and all of its sub descriptors*/ + uint8_t bNumDeviceCaps; /*The number of separate device capability descriptors in the BOS*/ +} usb_descriptor_bos_t; + +typedef struct _usb_descriptor_usb20_extension +{ + uint8_t bLength; /* Descriptor size in bytes = 7U */ + uint8_t bDescriptorType; /* DEVICE CAPABILITY Descriptor type = 0x10U*/ + uint8_t bDevCapabilityType; /*Length of this descriptor and all of its sub descriptors*/ + uint8_t bmAttributes[4]; /*Bitmap encoding of supported device level features.*/ +} usb_descriptor_usb20_extension_t; +typedef struct _usb_descriptor_super_speed_device_capability +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bmAttributes; + uint8_t wSpeedsSupported[2]; + uint8_t bFunctionalitySupport; + uint8_t bU1DevExitLat; + uint8_t wU2DevExitLat[2]; +} usb_bos_device_capability_susperspeed_desc_t; +typedef union _usb_descriptor_union +{ + usb_descriptor_common_t common; /* Common descriptor */ + usb_descriptor_device_t device; /* Device descriptor */ + usb_descriptor_configuration_t configuration; /* Configuration descriptor */ + usb_descriptor_interface_t interface; /* Interface descriptor */ + usb_descriptor_endpoint_t endpoint; /* Endpoint descriptor */ + usb_descriptor_endpoint_companion_t endpointCompanion; /* Endpoint companion descriptor */ +} usb_descriptor_union_t; + +#endif /* __USB_SPEC_H__ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/Makefile new file mode 100644 index 000000000..8b4cc292c --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/Makefile @@ -0,0 +1,3 @@ +SRC_FILES += usb_osa_bm.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa.h new file mode 100644 index 000000000..a54e4f8d4 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa.h @@ -0,0 +1,577 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_OSA_H__ +#define __USB_OSA_H__ + +/*! + * @addtogroup usb_os_abstraction + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Define big endian */ +#define USB_BIG_ENDIAN (0U) +/*! @brief Define little endian */ +#define USB_LITTLE_ENDIAN (1U) + +/*! @brief Define current endian */ +#define ENDIANNESS USB_LITTLE_ENDIAN + +/*! @brief Define USB OSA event handle */ +typedef void *usb_osa_event_handle; + +/*! @brief Define USB OSA semaphore handle */ +typedef void *usb_osa_sem_handle; + +/*! @brief Define USB OSA mutex handle */ +typedef void *usb_osa_mutex_handle; + +/*! @brief Define USB OSA message queue handle */ +typedef void *usb_osa_msgq_handle; + +/*! @brief USB OSA error code */ +typedef enum _usb_osa_status +{ + kStatus_USB_OSA_Success = 0x00U, /*!< Success */ + kStatus_USB_OSA_Error, /*!< Failed */ + kStatus_USB_OSA_TimeOut, /*!< Timeout occurs while waiting */ +} usb_osa_status_t; + +/*! @brief The event flags are cleared automatically or manually.*/ +typedef enum _usb_osa_event_mode +{ + kUSB_OsaEventManualClear = 0U, /*!< The flags of the event is cleared manually. */ + kUSB_OsaEventAutoClear = 1U, /*!< The flags of the event is cleared automatically. */ +} usb_osa_event_mode_t; + +#define USB_STACK_BM +/* Include required header file based on RTOS selection */ +#if defined(USB_STACK_BM) + +#include "usb_osa_bm.h" + +#elif defined(USB_STACK_FREERTOS) + +#include "usb_osa_freertos.h" + +#elif defined(USB_STACK_UCOSII) + +#include "usb_osa_ucosii.h" + +#elif defined(USB_STACK_UCOSIII) + +#include "usb_osa_ucosiii.h" + +#else +#if defined(SDK_OS_BAREMETAL) + +#define USB_STACK_BM +#include "usb_osa_bm.h" + +#elif defined(SDK_OS_FREE_RTOS) + +#define USB_STACK_FREERTOS +#include "usb_osa_freertos.h" + +#elif defined(SDK_OS_UCOSII) + +#define USB_STACK_UCOSII +#include "usb_osa_ucosii.h" + +#elif defined(SDK_OS_UCOSIII) + +#define USB_STACK_UCOSIII +#include "usb_osa_ucosiii.h" + +#else + +#error Not define RTOS in file "usb_osa.h". +#endif +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name USB OSA Memory Management + * @{ + */ + +/*! + * @brief Reserves the requested amount of memory in bytes. + * + * The function is used to reserve the requested amount of memory in bytes and initializes it to 0. + * + * @param length Amount of bytes to reserve. + * + * @return Pointer to the reserved memory. NULL if memory can't be allocated. + */ +void *USB_OsaMemoryAllocate(uint32_t length); + +/*! + * @brief Frees the memory previously reserved. + * + * The function is used to free the memory block previously reserved. + * + * @param p Pointer to the start of the memory block previously reserved. + * + */ +extern void USB_OsaMemoryFree(void *p); + +/* @} */ + +/*! + * @name USB OSA Event + * @{ + */ + +/*! + * @brief Creates an event object with all flags cleared. + * + * This function creates an event object and sets its clear mode. If the clear mode + * is kUSB_OsaEventAutoClear, when a task gets the event flags, these flags are + * cleared automatically. If the clear mode is kUSB_OsaEventManualClear, the flags must + * be cleared manually. + * + * @param handle It is an out parameter, which is used to return the pointer of the event object. + * @param flag The event is auto-clear or manual-clear. See the enumeration #usb_osa_event_mode_t. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_event_handle eventHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaEventCreate(&eventHandle, kUSB_OsaEventManualClear); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventCreate(usb_osa_event_handle *handle, uint32_t flag); + +/*! + * @brief Destroys a created event object. + * + * @param handle Pointer to the event object. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaEventDestroy(eventHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventDestroy(usb_osa_event_handle handle); + +/*! + * @brief Sets an event flag. + * + * Sets specified flags for an event object. + * + * @param handle Pointer to the event object. + * @param bitMask Event flags to be set. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaEventSet(eventHandle, 0x01U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventSet(usb_osa_event_handle handle, uint32_t bitMask); + +/*! + * @brief Waits for an event flag. + * + * This function waits for a combination of flags to be set in an event object. + * An applications can wait for any/all bits to be set. This function can + * get the flags that wake up the waiting task. + * + * @param handle Pointer to the event object. + * @param bitMask Event flags to wait. + * @param flag Wait all flags or any flag to be set. 0U - wait any flag, others, wait all flags. + * @param timeout The maximum number of milliseconds to wait for the event. + * If the wait condition is not met, passing 0U + * waits indefinitely when the environment is an RTOS and returns the kStatus_OSA_Timeout + * immediately. Pass any value for the bare metal. + * @param bitSet Flags that wake up the waiting task are obtained by this parameter. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + uint32_t bitSet; + ... + usbOsaStatus = USB_OsaEventWait(eventHandle, 0x01U, 0U, 0U, &bitSet); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventWait( + usb_osa_event_handle handle, uint32_t bitMask, uint32_t flag, uint32_t timeout, uint32_t *bitSet); + +/*! + * @brief Checks an event flag. + * + * This function checks for a combination of flags to be set in an event object. + * + * @param handle Pointer to the event object. + * @param bitMask Event flags to check. + * @param bitSet Flags have been set. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + uint32_t bitSet; + ... + usbOsaStatus = USB_OsaEventCheck(eventHandle, 0x01U, &bitSet); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventCheck(usb_osa_event_handle handle, uint32_t bitMask, uint32_t *bitSet); + +/*! + * @brief Clears an event flag. + * + * This function clears flags of an event object. + * + * @param handle Pointer to the event object + * @param bitMask Event flags to be cleared. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaEventClear(eventHandle, 0x01U); + @endcode + */ +extern usb_osa_status_t USB_OsaEventClear(usb_osa_event_handle handle, uint32_t bitMask); +/* @} */ + +/*! + * @name USB OSA Semaphore + * @{ + */ + +/*! + * @brief Creates a semaphore with a given value. + * + * This function creates a semaphore and sets the default count. + * + * @param handle It is an out parameter, which is used to return pointer of the semaphore object. + * @param count Initializes a value of the semaphore. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaSemCreate(&semHandle, 1U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemCreate(usb_osa_sem_handle *handle, uint32_t count); + +/*! + * @brief Destroys a semaphore object. + * + * This function destroys a semaphore object. + * + * @param handle Pointer to the semaphore. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaSemDestroy(semHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemDestroy(usb_osa_sem_handle handle); + +/*! + * @brief Posts a semaphore. + * + * This function wakes up a task waiting on the semaphore. If a task is not pending, increases the semaphore's + value. + * + * @param handle Pointer to the semaphore. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaSemPost(semHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemPost(usb_osa_sem_handle handle); + +/*! + * @brief Waits on a semaphore. + * + * This function checks the semaphore's value. If it is positive, it decreases the semaphore's value and return + kStatus_OSA_Success. + * + * @param handle Pointer to the semaphore. + * @param timeout The maximum number of milliseconds to wait for the semaphore. + * If the wait condition is not met, passing 0U + * waits indefinitely when environment is RTOS. And return kStatus_OSA_Timeout + * immediately for bare metal no matter what value has been passed. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaSemWait(semHandle, 0U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemWait(usb_osa_sem_handle handle, uint32_t timeout); +/* @} */ + +/*! + * @name USB OSA Mutex + * @{ + */ + +/*! + * @brief Creates a mutex. + * + * This function creates a mutex and sets it to an unlocked status. + * + * @param handle It is out parameter, which is used to return the pointer of the mutex object. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaMutexCreate(&mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexCreate(usb_osa_mutex_handle *handle); + +/*! + * @brief Destroys a mutex. + * + * This function destroys a mutex and sets it to an unlocked status. + * + * @param handle Pointer to the mutex. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMutexDestroy(mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexDestroy(usb_osa_mutex_handle handle); + +/*! + * @brief Waits for a mutex and locks it. + * + * This function checks the mutex status. If it is unlocked, it locks it and returns the + * kStatus_OSA_Success. Otherwise, it waits forever to lock in RTOS and returns the + * kStatus_OSA_Success immediately for bare metal. + * + * @param handle Pointer to the mutex. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMutexLock(mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexLock(usb_osa_mutex_handle handle); + +/*! + * @brief Unlocks a mutex. + * + * This function unlocks a mutex. + * + * @param handle Pointer to the mutex. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMutexUnlock(mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexUnlock(usb_osa_mutex_handle handle); +/* @} */ + +/*! + * @name USB OSA Message Queue + * @{ + */ + +/*! + * @brief Creates a message queue. + * + * This function creates a message queue. + * + * @param handle It is an out parameter, which is used to return a pointer of the message queue object. + * @param count The count of elements in the queue. + * @param size Size of every elements in words. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaMsgqCreate(msgqHandle, 8U, 4U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqCreate(usb_osa_msgq_handle *handle, uint32_t count, uint32_t size); + +/*! + * @brief Destroys a message queue. + * + * This function destroys a message queue. + * + * @param handle Pointer to a message queue. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqDestroy(msgqHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqDestroy(usb_osa_msgq_handle handle); + +/*! + * @brief Sends a message. + * + * This function sends a message to the tail of the message queue. + * + * @param handle Pointer to a message queue. + * @param msg The pointer to a message to be put into the queue. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + message_struct_t message; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqSend(msgqHandle, &message); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqSend(usb_osa_msgq_handle handle, void *msg); + +/*! + * @brief Receives a message. + * + * This function receives a message from the head of the message queue. + * + * @param handle Pointer to a message queue. + * @param msg The pointer to save a received message. + * @param timeout The maximum number of milliseconds to wait for a message. + * If the wait condition is not met, passing 0U + * waits indefinitely when an environment is RTOS and returns the kStatus_OSA_Timeout + * immediately for bare metal. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + message_struct_t message; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqRecv(msgqHandle, &message, 0U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqRecv(usb_osa_msgq_handle handle, void *msg, uint32_t timeout); + +/*! + * @brief Checks a message queue and receives a message if the queue is not empty. + * + * This function checks a message queue and receives a message if the queue is not empty. + * + * @param handle Pointer to a message queue. + * @param msg The pointer to save a received message. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + message_struct_t message; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqCheck(msgqHandle, &message); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqCheck(usb_osa_msgq_handle handle, void *msg); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/* @} */ + +#endif /* __USB_OSA_H__ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa_bm.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa_bm.c new file mode 100644 index 000000000..9512fb699 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa_bm.c @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "stdint.h" +#include "usb.h" +#include "usb_osa.h" +#include "stdlib.h" +#include "fsl_device_registers.h" +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define USB_OSA_BM_EVENT_COUNT (4U) +#define USB_OSA_BM_SEM_COUNT (1U) +#define USB_OSA_BM_MSGQ_COUNT (1U) +#define USB_OSA_BM_MSG_COUNT (8U) +#define USB_OSA_BM_MSG_SIZE (4U) + +/* BM Event status structure */ +typedef struct _usb_osa_event_struct +{ + uint32_t value; /* Event mask */ + uint32_t flag; /* Event flags, includes auto clear flag */ + uint8_t isUsed; /* Is used */ +} usb_osa_event_struct_t; + +/* BM semaphore status structure */ +typedef struct _usb_osa_sem_struct +{ + uint32_t value; /* Semaphore count */ + uint8_t isUsed; /* Is used */ +} usb_osa_sem_struct_t; + +/* BM msg status structure */ +typedef struct _usb_osa_msg_struct +{ + uint32_t msg[USB_OSA_BM_MSG_SIZE]; /* Message entity pointer */ +} usb_osa_msg_struct_t; + +/* BM msgq status structure */ +typedef struct _usb_osa_msgq_struct +{ + usb_osa_msg_struct_t msgs[USB_OSA_BM_MSG_COUNT]; /* Message entity list */ + uint32_t count; /* Max message entity count */ + uint32_t msgSize; /* Size of each message */ + uint32_t msgCount; /* Valid messages */ + uint32_t index; /* The first empty message entity index */ + uint32_t current; /* The vaild message index */ + uint8_t isUsed; /* Is used */ +} usb_osa_msgq_struct_t; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_osa_sem_struct_t + s_UsbBmSemStruct[USB_OSA_BM_SEM_COUNT]; +USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_osa_event_struct_t + s_UsbBmEventStruct[USB_OSA_BM_EVENT_COUNT]; +USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_osa_msgq_struct_t + s_UsbBmMsgqStruct[USB_OSA_BM_MSGQ_COUNT]; + +/******************************************************************************* + * Code + ******************************************************************************/ + +void *USB_OsaMemoryAllocate(uint32_t length) +{ + void *p = (void *)malloc(length); + uint8_t *temp = (uint8_t *)p; + if (p) + { + for (uint32_t count = 0U; count < length; count++) + { + temp[count] = 0U; + } + } + return p; +} + +void USB_OsaMemoryFree(void *p) +{ + free(p); +} + +void USB_OsaEnterCritical(uint32_t *sr) +{ + *sr = DisableGlobalIRQ(); + + + __ASM("CPSID i"); +} + +void USB_OsaExitCritical(uint32_t sr) +{ + EnableGlobalIRQ(sr); +} + +usb_osa_status_t USB_OsaEventCreate(usb_osa_event_handle *handle, uint32_t flag) +{ + usb_osa_event_struct_t *event = NULL; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + for (uint32_t i = 0; i < USB_OSA_BM_EVENT_COUNT; i++) + { + if (0 == s_UsbBmEventStruct[i].isUsed) + { + event = &s_UsbBmEventStruct[i]; + break; + } + } + + if (NULL == event) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + event->value = 0U; + event->flag = flag; + event->isUsed = 1; + *handle = event; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaEventDestroy(usb_osa_event_handle handle) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + event->isUsed = 0; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventSet(usb_osa_event_handle handle, uint32_t bitMask) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + event->value |= bitMask; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventWait( + usb_osa_event_handle handle, uint32_t bitMask, uint32_t flag, uint32_t timeout, uint32_t *bitSet) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + uint32_t bits; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + bits = event->value & bitMask; + if (flag) + { + if (bits != bitMask) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + } + else + { + if (!bits) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + } + if (bitSet) + { + *bitSet = bits; + } + if (event->flag) + { + event->value &= ~bits; + } + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventCheck(usb_osa_event_handle handle, uint32_t bitMask, uint32_t *bitSet) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + uint32_t bits; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + bits = event->value & bitMask; + + if (!bits) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + if (bitSet) + { + *bitSet = bits; + } + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventClear(usb_osa_event_handle handle, uint32_t bitMask) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + uint32_t bits; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + bits = event->value & bitMask; + event->value &= ~bits; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaSemCreate(usb_osa_sem_handle *handle, uint32_t count) +{ + usb_osa_sem_struct_t *sem = NULL; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + for (uint32_t i = 0; i < USB_OSA_BM_SEM_COUNT; i++) + { + if (0 == s_UsbBmSemStruct[i].isUsed) + { + sem = &s_UsbBmSemStruct[i]; + break; + } + } + if (NULL == sem) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + sem->value = count; + sem->isUsed = 1; + *handle = sem; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaSemDestroy(usb_osa_sem_handle handle) +{ + usb_osa_sem_struct_t *sem = (usb_osa_sem_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + sem->isUsed = 0; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaSemPost(usb_osa_sem_handle handle) +{ + usb_osa_sem_struct_t *sem = (usb_osa_sem_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + sem->value++; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaSemWait(usb_osa_sem_handle handle, uint32_t timeout) +{ + usb_osa_sem_struct_t *sem = (usb_osa_sem_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + if (sem->value) + { + sem->value--; + } + else + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMutexCreate(usb_osa_mutex_handle *handle) +{ + if (!handle) + { + return kStatus_USB_OSA_Error; + } + *handle = (usb_osa_mutex_handle)0xFFFF0000U; + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMutexDestroy(usb_osa_mutex_handle handle) +{ + return kStatus_USB_OSA_Success; +} +usb_osa_status_t USB_OsaMutexLock(usb_osa_mutex_handle handle) +{ + return kStatus_USB_OSA_Success; +} +usb_osa_status_t USB_OsaMutexUnlock(usb_osa_mutex_handle handle) +{ + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqCreate(usb_osa_msgq_handle *handle, uint32_t count, uint32_t size) +{ + usb_osa_msgq_struct_t *msgq = NULL; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + + for (uint32_t i = 0; i < USB_OSA_BM_MSGQ_COUNT; i++) + { + if (0 == s_UsbBmMsgqStruct[i].isUsed) + { + msgq = &s_UsbBmMsgqStruct[i]; + break; + } + } + if ((NULL == msgq) || (count > USB_OSA_BM_MSG_COUNT) || (size > USB_OSA_BM_MSG_SIZE)) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + msgq->count = count; + msgq->msgSize = size; + msgq->msgCount = 0U; + msgq->index = 0U; + msgq->current = 0U; + msgq->isUsed = 1; + *handle = msgq; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqDestroy(usb_osa_msgq_handle handle) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + msgq->isUsed = 0; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqSend(usb_osa_msgq_handle handle, void *msg) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + usb_osa_msg_struct_t *msgEntity; + uint32_t *p; + uint32_t *q; + uint32_t count; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + if (msgq->msgCount >= msgq->count) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + msgEntity = &msgq->msgs[msgq->index]; + p = (uint32_t *)&msgEntity->msg[0]; + q = (uint32_t *)msg; + + for (count = 0U; count < msgq->msgSize; count++) + { + p[count] = q[count]; + } + + if (0U == msgq->msgCount) + { + msgq->current = msgq->index; + } + + msgq->msgCount++; + msgq->index++; + msgq->index = msgq->index % msgq->count; + + USB_OSA_EXIT_CRITICAL(); + + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqRecv(usb_osa_msgq_handle handle, void *msg, uint32_t timeout) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + usb_osa_msg_struct_t *msgEntity; + uint32_t *p; + uint32_t *q; + uint32_t count; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + if (msgq->msgCount < 1U) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + + msgEntity = &msgq->msgs[msgq->current]; + q = (uint32_t *)&msgEntity->msg[0]; + p = (uint32_t *)msg; + + for (count = 0U; count < msgq->msgSize; count++) + { + p[count] = q[count]; + } + + msgq->msgCount--; + msgq->current++; + msgq->current = msgq->current % msgq->count; + + USB_OSA_EXIT_CRITICAL(); + + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqCheck(usb_osa_msgq_handle handle, void *msg) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + uint32_t msgCount; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + msgCount = msgq->msgCount; + USB_OSA_EXIT_CRITICAL(); + + if (msgCount) + { + if (kStatus_USB_OSA_Success == USB_OsaMsgqRecv(msgq, msg, 0U)) + { + return kStatus_USB_OSA_Success; + } + } + + return kStatus_USB_OSA_Error; +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa_bm.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa_bm.h new file mode 100644 index 000000000..ad0612141 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/osa/usb_osa_bm.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_OSA_BM_H__ +#define __USB_OSA_BM_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define USB_OSA_SR_ALLOC() uint32_t usbOsaCurrentSr; +#define USB_OSA_ENTER_CRITICAL() USB_OsaEnterCritical(&usbOsaCurrentSr) +#define USB_OSA_EXIT_CRITICAL() USB_OsaExitCritical(usbOsaCurrentSr) + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +extern void USB_OsaEnterCritical(uint32_t *sr); +extern void USB_OsaExitCritical(uint32_t sr); + +#if defined(__cplusplus) +} +#endif + +#endif /* __USB_OSA_BM_H__ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/Makefile new file mode 100644 index 000000000..a18326f77 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/Makefile @@ -0,0 +1,3 @@ +SRC_FILES += usb_phy.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/usb_phy.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/usb_phy.c new file mode 100644 index 000000000..ab472c214 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/usb_phy.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 - 2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb.h" +#include "fsl_device_registers.h" + +#include "usb_phy.h" + +void *USB_EhciPhyGetBase(uint8_t controllerId) +{ + void *usbPhyBase = NULL; +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + uint32_t instance; + uint32_t newinstance = 0; + uint32_t usbphy_base_temp[] = USBPHY_BASE_ADDRS; + uint32_t usbphy_base[] = USBPHY_BASE_ADDRS; + + if (controllerId < kUSB_ControllerEhci0) + { + return NULL; + } + + if ((controllerId == kUSB_ControllerEhci0) || (controllerId == kUSB_ControllerEhci1)) + { + controllerId = controllerId - kUSB_ControllerEhci0; + } + else if ((controllerId == kUSB_ControllerLpcIp3511Hs0) || (controllerId == kUSB_ControllerLpcIp3511Hs1)) + { + controllerId = controllerId - kUSB_ControllerLpcIp3511Hs0; + } + else if ((controllerId == kUSB_ControllerIp3516Hs0) || (controllerId == kUSB_ControllerIp3516Hs1)) + { + controllerId = controllerId - kUSB_ControllerIp3516Hs0; + } + else + { + } + + for (instance = 0; instance < (sizeof(usbphy_base_temp) / sizeof(usbphy_base_temp[0])); instance++) + { + if (usbphy_base_temp[instance]) + { + usbphy_base[newinstance++] = usbphy_base_temp[instance]; + } + } + if (controllerId > newinstance) + { + return NULL; + } + + usbPhyBase = (void *)usbphy_base[controllerId]; +#endif + return usbPhyBase; +} + +/*! + * @brief ehci phy initialization. + * + * This function initialize ehci phy IP. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + * @param[in] freq the external input clock. + * for example: if the external input clock is 16M, the parameter freq should be 16000000. + * + * @retval kStatus_USB_Success cancel successfully. + * @retval kStatus_USB_Error the freq value is incorrect. + */ +uint32_t USB_EhciPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return kStatus_USB_Error; + } + +#if ((defined FSL_FEATURE_SOC_ANATOP_COUNT) && (FSL_FEATURE_SOC_ANATOP_COUNT > 0U)) + ANATOP->HW_ANADIG_REG_3P0.RW = + (ANATOP->HW_ANADIG_REG_3P0.RW & + (~(ANATOP_HW_ANADIG_REG_3P0_OUTPUT_TRG(0x1F) | ANATOP_HW_ANADIG_REG_3P0_ENABLE_ILIMIT_MASK))) | + ANATOP_HW_ANADIG_REG_3P0_OUTPUT_TRG(0x17) | ANATOP_HW_ANADIG_REG_3P0_ENABLE_LINREG_MASK; + ANATOP->HW_ANADIG_USB2_CHRG_DETECT.SET = + ANATOP_HW_ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B_MASK | ANATOP_HW_ANADIG_USB2_CHRG_DETECT_EN_B_MASK; +#endif + +#if (defined USB_ANALOG) + USB_ANALOG->INSTANCE[controllerId - kUSB_ControllerEhci0].CHRG_DETECT_SET = USB_ANALOG_CHRG_DETECT_CHK_CHRG_B(1) | USB_ANALOG_CHRG_DETECT_EN_B(1); +#endif + +#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT))) + + usbPhyBase->TRIM_OVERRIDE_EN = 0x001fU; /* override IFR value */ +#endif + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK; /* support LS device. */ + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL3_MASK; /* support external FS Hub with LS device connected. */ + /* PWD register provides overall control of the PHY power state */ + usbPhyBase->PWD = 0U; + if ((kUSB_ControllerIp3516Hs0 == controllerId) || (kUSB_ControllerIp3516Hs1 == controllerId) || + (kUSB_ControllerLpcIp3511Hs0 == controllerId) || (kUSB_ControllerLpcIp3511Hs0 == controllerId)) + { + usbPhyBase->CTRL_SET = USBPHY_CTRL_SET_ENAUTOCLR_CLKGATE_MASK; + usbPhyBase->CTRL_SET = USBPHY_CTRL_SET_ENAUTOCLR_PHY_PWD_MASK; + } + if (NULL != phyConfig) + { + /* Decode to trim the nominal 17.78mA current source for the High Speed TX drivers on USB_DP and USB_DM. */ + usbPhyBase->TX = + ((usbPhyBase->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) | + (USBPHY_TX_D_CAL(phyConfig->D_CAL) | USBPHY_TX_TXCAL45DP(phyConfig->TXCAL45DP) | + USBPHY_TX_TXCAL45DM(phyConfig->TXCAL45DM))); + } +#endif + + return kStatus_USB_Success; +} + +/*! + * @brief ehci phy initialization for suspend and resume. + * + * This function initialize ehci phy IP for suspend and resume. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + * @param[in] freq the external input clock. + * for example: if the external input clock is 16M, the parameter freq should be 16000000. + * + * @retval kStatus_USB_Success cancel successfully. + * @retval kStatus_USB_Error the freq value is incorrect. + */ +uint32_t USB_EhciLowPowerPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return kStatus_USB_Error; + } + +#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT))) + usbPhyBase->TRIM_OVERRIDE_EN = 0x001fU; /* override IFR value */ +#endif + +#if ((defined USBPHY_CTRL_AUTORESUME_EN_MASK) && (USBPHY_CTRL_AUTORESUME_EN_MASK > 0U)) + usbPhyBase->CTRL |= USBPHY_CTRL_AUTORESUME_EN_MASK; +#else + usbPhyBase->CTRL |= USBPHY_CTRL_ENAUTO_PWRON_PLL_MASK; +#endif + usbPhyBase->CTRL |= USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK | USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK; + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK; /* support LS device. */ + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL3_MASK; /* support external FS Hub with LS device connected. */ + /* PWD register provides overall control of the PHY power state */ + usbPhyBase->PWD = 0U; +#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT)) && (!(defined FSL_FEATURE_USBHSD_USB_RAM))) + /* now the 480MHz USB clock is up, then configure fractional divider after PLL with PFD + * pfd clock = 480MHz*18/N, where N=18~35 + * Please note that USB1PFDCLK has to be less than 180MHz for RUN or HSRUN mode + */ + usbPhyBase->ANACTRL |= USBPHY_ANACTRL_PFD_FRAC(24); /* N=24 */ + usbPhyBase->ANACTRL |= USBPHY_ANACTRL_PFD_CLK_SEL(1); /* div by 4 */ + + usbPhyBase->ANACTRL &= ~USBPHY_ANACTRL_DEV_PULLDOWN_MASK; + usbPhyBase->ANACTRL &= ~USBPHY_ANACTRL_PFD_CLKGATE_MASK; + while (!(usbPhyBase->ANACTRL & USBPHY_ANACTRL_PFD_STABLE_MASK)) + { + } +#endif + if (NULL != phyConfig) + { + /* Decode to trim the nominal 17.78mA current source for the High Speed TX drivers on USB_DP and USB_DM. */ + usbPhyBase->TX = + ((usbPhyBase->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) | + (USBPHY_TX_D_CAL(phyConfig->D_CAL) | USBPHY_TX_TXCAL45DP(phyConfig->TXCAL45DP) | + USBPHY_TX_TXCAL45DM(phyConfig->TXCAL45DM))); + } +#endif + + return kStatus_USB_Success; +} + +/*! + * @brief ehci phy de-initialization. + * + * This function de-initialize ehci phy IP. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + */ +void USB_EhciPhyDeinit(uint8_t controllerId) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return; + } +#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT))) + usbPhyBase->PLL_SIC &= ~USBPHY_PLL_SIC_PLL_POWER_MASK; /* power down PLL */ + usbPhyBase->PLL_SIC &= ~USBPHY_PLL_SIC_PLL_EN_USB_CLKS_MASK; /* disable USB clock output from USB PHY PLL */ +#endif + usbPhyBase->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* set to 1U to gate clocks */ +#endif +} + +/*! + * @brief ehci phy disconnect detection enable or disable. + * + * This function enable/disable host ehci disconnect detection. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + * @param[in] enable + * 1U - enable; + * 0U - disable; + */ +void USB_EhcihostPhyDisconnectDetectCmd(uint8_t controllerId, uint8_t enable) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return; + } + + if (enable) + { + usbPhyBase->CTRL |= USBPHY_CTRL_ENHOSTDISCONDETECT_MASK; + } + else + { + usbPhyBase->CTRL &= (~USBPHY_CTRL_ENHOSTDISCONDETECT_MASK); + } +#endif +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/usb_phy.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/usb_phy.h new file mode 100644 index 000000000..752df48ea --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/phy/usb_phy.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 - 2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __USB_PHY_H__ +#define __USB_PHY_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +typedef struct _usb_phy_config_struct +{ + uint8_t D_CAL; /* Decode to trim the nominal 17.78mA current source */ + uint8_t TXCAL45DP; /* Decode to trim the nominal 45-Ohm series termination resistance to the USB_DP output pin */ + uint8_t TXCAL45DM; /* Decode to trim the nominal 45-Ohm series termination resistance to the USB_DM output pin */ +} usb_phy_config_struct_t; + +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************************************* + * API + ******************************************************************************/ +/*! + * @brief EHCI PHY get USB phy bass address. + * + * This function is used to get USB phy bass address. + * + * @param[in] controllerId EHCI controller ID; See the #usb_controller_index_t. + * + * @retval USB phy bass address. + */ +extern void *USB_EhciPhyGetBase(uint8_t controllerId); + +/*! + * @brief EHCI PHY initialization. + * + * This function initializes the EHCI PHY IP. + * + * @param[in] controllerId EHCI controller ID; See the #usb_controller_index_t. + * @param[in] freq The external input clock. + * + * @retval kStatus_USB_Success Cancel successfully. + * @retval kStatus_USB_Error The freq value is incorrect. + */ +extern uint32_t USB_EhciPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig); + +/*! + * @brief ehci phy initialization for suspend and resume. + * + * This function initialize ehci phy IP for suspend and resume. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + * @param[in] freq the external input clock. + * for example: if the external input clock is 16M, the parameter freq should be 16000000. + * + * @retval kStatus_USB_Success cancel successfully. + * @retval kStatus_USB_Error the freq value is incorrect. + */ +extern uint32_t USB_EhciLowPowerPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig); + +/*! + * @brief EHCI PHY deinitialization. + * + * This function deinitializes the EHCI PHY IP. + * + * @param[in] controllerId EHCI controller ID; See #usb_controller_index_t. + */ +extern void USB_EhciPhyDeinit(uint8_t controllerId); + +/*! + * @brief EHCI PHY disconnect detection enable or disable. + * + * This function enable/disable the host EHCI disconnect detection. + * + * @param[in] controllerId EHCI controller ID; See #usb_controller_index_t. + * @param[in] enable + * 1U - enable; + * 0U - disable; + */ +extern void USB_EhcihostPhyDisconnectDetectCmd(uint8_t controllerId, uint8_t enable); + +#if defined(__cplusplus) +} +#endif + +#endif /* __USB_PHY_H__ */ diff --git a/Ubiquitous/XiUOS/board/stm32f103-nano/.defconfig b/Ubiquitous/XiUOS/board/stm32f103-nano/.defconfig index cfc19af53..bc0280cc8 100644 --- a/Ubiquitous/XiUOS/board/stm32f103-nano/.defconfig +++ b/Ubiquitous/XiUOS/board/stm32f103-nano/.defconfig @@ -26,7 +26,7 @@ CONFIG_BSP_USING_UART1=y # CONFIG_BSP_USING_UART4 is not set # CONFIG_BSP_USING_UART5 is not set # CONFIG_BSP_USING_USB is not set -# CONFIG_BSP_USING_USBH is not set +# CONFIG_BSP_USING_STM32_USBH is not set # # Hardware feature diff --git a/Ubiquitous/XiUOS/board/stm32f407-st-discovery/.defconfig b/Ubiquitous/XiUOS/board/stm32f407-st-discovery/.defconfig index d5f673277..4ecb3a27b 100644 --- a/Ubiquitous/XiUOS/board/stm32f407-st-discovery/.defconfig +++ b/Ubiquitous/XiUOS/board/stm32f407-st-discovery/.defconfig @@ -26,7 +26,7 @@ CONFIG_BSP_USING_UART3=y # CONFIG_BSP_USING_UART4 is not set # CONFIG_BSP_USING_UART5 is not set #CONFIG_BSP_USING_USB is not set -#CONFIG_BSP_USING_USBH is not set +#CONFIG_BSP_USING_STM32_USBH is not set # # Hardware feature diff --git a/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/Kconfig b/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/Kconfig index 4bbfcb82c..283313b3b 100755 --- a/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/Kconfig +++ b/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/Kconfig @@ -98,7 +98,7 @@ endif menuconfig BSP_USING_USB bool "Using USB device" default n -select BSP_USING_USBH +select BSP_USING_STM32_USBH select RESOURCES_USB select RESOURCES_USB_HOST select USBH_MSTORAGE diff --git a/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/usb/Kconfig b/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/usb/Kconfig index 1aeabc314..69d2536d9 100644 --- a/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/usb/Kconfig +++ b/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/usb/Kconfig @@ -1,4 +1,4 @@ -config BSP_USING_USBH +config BSP_USING_STM32_USBH bool "Using usb host" default y config USB_BUS_NAME diff --git a/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/usb/usbh.c b/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/usb/usbh.c index 6363fd221..98f45734e 100644 --- a/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/usb/usbh.c +++ b/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/usb/usbh.c @@ -31,7 +31,7 @@ Modification: *************************************************/ #include -#include +#include #include #include #include diff --git a/Ubiquitous/XiUOS/board/stm32f407zgt6/.defconfig b/Ubiquitous/XiUOS/board/stm32f407zgt6/.defconfig index c9163eae2..ac3157109 100644 --- a/Ubiquitous/XiUOS/board/stm32f407zgt6/.defconfig +++ b/Ubiquitous/XiUOS/board/stm32f407zgt6/.defconfig @@ -26,7 +26,7 @@ CONFIG_BSP_USING_UART3=y # CONFIG_BSP_USING_UART4 is not set # CONFIG_BSP_USING_UART5 is not set #CONFIG_BSP_USING_USB is not set -#CONFIG_BSP_USING_USBH is not set +#CONFIG_BSP_USING_STM32_USBH is not set # # Hardware feature diff --git a/Ubiquitous/XiUOS/kernel/thread/init.c b/Ubiquitous/XiUOS/kernel/thread/init.c index 94a3d1881..6fa7a56ab 100644 --- a/Ubiquitous/XiUOS/kernel/thread/init.c +++ b/Ubiquitous/XiUOS/kernel/thread/init.c @@ -27,7 +27,7 @@ #include #include -#ifdef BSP_USING_USBH +#ifdef BSP_USING_USB #include "connect_usb.h" #endif @@ -123,9 +123,12 @@ struct InitSequenceDesc env_init[] = }; struct InitSequenceDesc communication_init[] = { -#ifdef BSP_USING_USBH +#ifdef BSP_USING_STM32_USBH { "STM32USBHostRegister", STM32USBHostRegister }, { "hw usb", Stm32HwUsbInit }, +#endif +#ifdef BSP_USING_NXP_USBH + { "nxp hw usb", Imrt1052HwUsbHostInit }, #endif { " NONE ", NONE }, }; diff --git a/Ubiquitous/XiUOS/path_kernel.mk b/Ubiquitous/XiUOS/path_kernel.mk index 58dc83c47..ace806d36 100755 --- a/Ubiquitous/XiUOS/path_kernel.mk +++ b/Ubiquitous/XiUOS/path_kernel.mk @@ -176,6 +176,11 @@ KERNELPATHS :=-I$(BSP_ROOT) \ -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/usb/nxp_usb_driver/host \ + -I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/host/class \ + -I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/include \ + -I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/osa \ + -I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/phy \ -I$(BSP_ROOT)/third_party_driver/ethernet \ -I$(BSP_ROOT)/third_party_driver/ethernet/ksz8081 \ -I$(BSP_ROOT)/third_party_driver/MIMXRT1052 \ diff --git a/Ubiquitous/XiUOS/resources/include/device.h b/Ubiquitous/XiUOS/resources/include/device.h index db9799b2a..48280f3a4 100644 --- a/Ubiquitous/XiUOS/resources/include/device.h +++ b/Ubiquitous/XiUOS/resources/include/device.h @@ -53,7 +53,7 @@ #include #include #ifdef RESOURCES_USB_HOST -#include +#include #endif #endif diff --git a/Ubiquitous/XiUOS/resources/include/usb_common.h b/Ubiquitous/XiUOS/resources/include/stm32_usb_common.h similarity index 99% rename from Ubiquitous/XiUOS/resources/include/usb_common.h rename to Ubiquitous/XiUOS/resources/include/stm32_usb_common.h index 45ebd6f4d..a7e3a0229 100644 --- a/Ubiquitous/XiUOS/resources/include/usb_common.h +++ b/Ubiquitous/XiUOS/resources/include/stm32_usb_common.h @@ -11,7 +11,7 @@ */ /** -* @file usb_common.h +* @file stm32_usb_common.h * @brief define usb function and struct * @version 1.0 * @author AIIT XUOS Lab @@ -19,7 +19,7 @@ */ /************************************************* -File name: usb_common.h +File name: stm32_usb_common.h Description: define usb function and common struct Others: take RT-Thread v4.0.2/components/drivers/include/drivers/usb_common.h for references https://github.com/RT-Thread/rt-thread/tree/v4.0.2 diff --git a/Ubiquitous/XiUOS/resources/include/usb_host.h b/Ubiquitous/XiUOS/resources/include/stm32_usb_host.h similarity index 98% rename from Ubiquitous/XiUOS/resources/include/usb_host.h rename to Ubiquitous/XiUOS/resources/include/stm32_usb_host.h index 473b647fb..c79ba3086 100644 --- a/Ubiquitous/XiUOS/resources/include/usb_host.h +++ b/Ubiquitous/XiUOS/resources/include/stm32_usb_host.h @@ -9,7 +9,7 @@ */ /** -* @file usb_host.h +* @file stm32_usb_host.h * @brief define usb host function and struct * @version 1.0 * @author AIIT XUOS Lab @@ -17,7 +17,7 @@ */ /************************************************* -File name: usb_host.h +File name: stm32_usb_host.h Description: define usb host function and struct Others: take RT-Thread v4.0.2/components/drivers/include/drivers/usb_host.h for references https://github.com/RT-Thread/rt-thread/tree/v4.0.2 @@ -34,7 +34,7 @@ Modification: #include -#include +#include #ifdef __cplusplus extern "C" { diff --git a/Ubiquitous/XiUOS/resources/usb/third_party_usb/Makefile b/Ubiquitous/XiUOS/resources/usb/third_party_usb/Makefile index 06f346bbc..97642cfd3 100644 --- a/Ubiquitous/XiUOS/resources/usb/third_party_usb/Makefile +++ b/Ubiquitous/XiUOS/resources/usb/third_party_usb/Makefile @@ -1,3 +1,5 @@ -SRC_DIR := usbhost +ifeq ($(CONFIG_BSP_USING_STM32_USBH),y) + SRC_DIR := usbhost +endif include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/class/mass.c b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/class/mass.c index ad543b51f..23403252b 100644 --- a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/class/mass.c +++ b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/class/mass.c @@ -30,7 +30,7 @@ Modification: *************************************************/ #include -#include +#include #include "mass.h" #ifdef USBH_MSTORAGE diff --git a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/class/udisk.c b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/class/udisk.c index 4b02e1394..200b6e0b3 100644 --- a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/class/udisk.c +++ b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/class/udisk.c @@ -31,7 +31,7 @@ Modification: #include -#include +#include #include "mass.h" #if defined(FS_VFS) diff --git a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/core.c b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/core.c index 26c594327..2ad722538 100644 --- a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/core.c +++ b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/core.c @@ -30,7 +30,7 @@ Modification: *************************************************/ #include -#include +#include static struct uinstance dev[USB_MAX_DEVICE]; diff --git a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/driver.c b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/driver.c index 56260f9b2..16e636788 100644 --- a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/driver.c +++ b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/driver.c @@ -31,7 +31,7 @@ Modification: #include #include -#include +#include static DoubleLinklistType DriverList; diff --git a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/hub.c b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/hub.c index 52d2c8121..edf4480cb 100644 --- a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/hub.c +++ b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/hub.c @@ -30,7 +30,7 @@ Modification: *************************************************/ #include -#include +#include #define USB_THREAD_STACK_SIZE 4096 diff --git a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/usbhost.c b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/usbhost.c index f257a4ff5..1026ae308 100644 --- a/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/usbhost.c +++ b/Ubiquitous/XiUOS/resources/usb/third_party_usb/usbhost/core/usbhost.c @@ -30,7 +30,7 @@ Modification: *************************************************/ #include -#include +#include #define USB_HOST_CONTROLLER_NAME "usbh" From 9339ffe2fdd4817a496f7abc023dfa83f719c2c2 Mon Sep 17 00:00:00 2001 From: Liu_Weichao Date: Thu, 17 Feb 2022 16:29:41 +0800 Subject: [PATCH 5/5] fix USB write error using fatfs function --- .../third_party_driver/usb/connect_usb.c | 4 +- .../usb/nxp_usb_driver/host_msd_command.c | 88 +++++++++++++------ 2 files changed, 64 insertions(+), 28 deletions(-) diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/connect_usb.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/connect_usb.c index dc530f79f..a05ee262d 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/connect_usb.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/connect_usb.c @@ -36,7 +36,7 @@ extern usb_host_msd_command_instance_t g_MsdCommandInstance; usb_host_handle g_HostHandle; extern usb_status_t USB_HostMsdReadApi(usb_host_msd_command_instance_t *msdCommandInstance, uint8_t *buffer, uint32_t pos, uint32_t block_size, uint32_t block_num); -extern usb_status_t USB_HostMsdWriteApi(usb_host_msd_command_instance_t *msdCommandInstance, uint8_t *buffer, uint32_t pos, uint32_t block_size, uint32_t block_num); +extern usb_status_t USB_HostMsdWriteApi(usb_host_msd_command_instance_t *msdCommandInstance, const uint8_t *buffer, uint32_t pos, uint32_t block_size, uint32_t block_num); //USB HOST ISR void UsbOtg2IrqHandler(int irqn, void *arg) @@ -177,7 +177,7 @@ static uint32 UsbHostWrite(void *dev, struct BusBlockWriteParam *write_param) { usb_status_t status; - status = USB_HostMsdWriteApi(&g_MsdCommandInstance, (uint8 *)write_param->buffer, write_param->pos, USB_SINGLE_BLOCK_SIZE, write_param->size); + status = USB_HostMsdWriteApi(&g_MsdCommandInstance, (const uint8 *)write_param->buffer, write_param->pos, USB_SINGLE_BLOCK_SIZE, write_param->size); if (kStatus_USB_Success == status) { return write_param->size; } diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host_msd_command.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host_msd_command.c index 176d08bfd..78cb4af70 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host_msd_command.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/usb/nxp_usb_driver/host_msd_command.c @@ -485,51 +485,87 @@ static void USB_HostMsdCommandTest(usb_host_msd_command_instance_t *msdCommandIn usb_status_t USB_HostMsdReadApi(usb_host_msd_command_instance_t *msdCommandInstance, uint8_t *buffer, uint32_t pos, uint32_t block_size, uint32_t block_num) { + usb_status_t status, ret = kStatus_USB_Error; + uint32_t retry = 2; + if (msdCommandInstance->deviceState == kStatus_DEV_Attached) { - usb_status_t status; ufiIng = 1; - status = USB_HostMsdRead10(msdCommandInstance->classHandle, 0, pos, buffer, block_size, block_num, USB_HostMsdUfiCallback, msdCommandInstance); - if (status != kStatus_USB_Success) { - usb_echo("UsbHostRead error\r\n"); - return kStatus_USB_Error; - } - while (ufiIng) { - USB_HostControllerTaskFunction(g_HostHandle); - } + while (retry--) { + status = USB_HostMsdRead10(msdCommandInstance->classHandle, 0, pos, buffer, (uint32_t)(block_size * block_num), block_num, USB_HostMsdUfiCallback, msdCommandInstance); + if (status != kStatus_USB_Success) { + usb_echo("UsbHostRead error\r\n"); + ret = kStatus_USB_Error; + } else { + while (ufiIng) { + USB_HostControllerTaskFunction(g_HostHandle); + } - if (ufiStatus == kStatus_USB_Success){ - return kStatus_USB_Success; + if (ufiStatus == kStatus_USB_Success) { + ret = kStatus_USB_Success; + break; + } else { + ret = kStatus_USB_Error; + } + } } } - return kStatus_USB_Error; + return ret; } -usb_status_t USB_HostMsdWriteApi(usb_host_msd_command_instance_t *msdCommandInstance, uint8_t *buffer, uint32_t pos, uint32_t block_size, uint32_t block_num) +usb_status_t USB_HostMsdWriteApi(usb_host_msd_command_instance_t *msdCommandInstance, const uint8_t *buffer, uint32_t pos, uint32_t block_size, uint32_t block_num) { - if (msdCommandInstance->deviceState == kStatus_DEV_Attached) { - usb_status_t status; + usb_status_t fatfs_code = kStatus_USB_Error; + usb_status_t status = kStatus_USB_Success; + uint32_t retry = 2; + const uint8_t *transferBuf; + uint32_t sectorCount; + uint32_t sectorIndex; + + if (!block_num) + { + return kStatus_USB_Error; + } + + transferBuf = buffer; + sectorCount = block_num; + sectorIndex = pos; + + while (retry--) + { ufiIng = 1; - status = USB_HostMsdWrite10(msdCommandInstance->classHandle, 0, pos, buffer, block_size, block_num, USB_HostMsdUfiCallback, msdCommandInstance); - if (status != kStatus_USB_Success) { - usb_echo("UsbHostWrite error\r\n"); + if (msdCommandInstance == NULL) + { return kStatus_USB_Error; } - - while (ufiIng) { - USB_HostControllerTaskFunction(g_HostHandle); + status = USB_HostMsdWrite10(msdCommandInstance->classHandle, 0, sectorIndex, (uint8_t *)transferBuf, + (uint32_t)(block_size * sectorCount), sectorCount, USB_HostMsdUfiCallback, NULL); + if (status != kStatus_USB_Success) + { + fatfs_code = kStatus_USB_Error; } - - if (ufiStatus == kStatus_USB_Success) { - return kStatus_USB_Success; + else + { + while (ufiIng) + { + USB_HostControllerTaskFunction(g_HostHandle); + } + if (ufiStatus == kStatus_USB_Success) + { + fatfs_code = kStatus_USB_Success; + break; + } + else + { + fatfs_code = kStatus_USB_Busy; + } } } - return kStatus_USB_Error; + return fatfs_code; } - void USB_HostMsdTask(void *arg) { usb_status_t status;