[提问]小安派 AiPi-Eyes-Rx TF卡槽

[复制链接]
查看1823 | 回复11 | 2024-1-19 14:13:23 | 显示全部楼层 |阅读模式

本帖最后由 WT_0213 于 2024-1-19 15:00 编辑

发现小安派AiPi-Eyes-R1和AiPi-Eyes-R2都有预留TF卡槽的位置,未焊接卡槽。

如果 AiPi-Eyes-Rx 补焊 TF卡槽,是否可以直接使用。与哪些硬件冲突呢。

想要在TF卡里面存一些图片或者音视频文件。是否可行。

如果可行的话,希望官方大佬能出个相关的教程,自带的存储有限存不了太多东西。 😄

sdcard

sdh_sdcard.h

/**
 * @file sdh_sdcard.h
 * @brief
 *
 * Copyright (c) 2021 Bouffalolab team
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 */

#ifndef _SDH_SDCARD_H
#define _SDH_SDCARD_H

#include <stdint.h>

#if defined(BL808)
#include "bl808_common.h"
#include "bl808_glb.h"
#include "bl808_sdh.h"
#elif defined(BL606P)
#include "bl606p_common.h"
#include "bl606p_glb.h"
#include "bl606p_sdh.h"
#elif defined(BL616)
#include "bl616_common.h"
#include "bl616_glb.h"
#include "bl616_sdh.h"
#elif defined(BL628)
#include "bl628_common.h"
#include "bl628_glb.h"
#include "bl628_smih.h"
#else
#define _SDH_SDCARD_CHECK
#endif

#ifndef _SDH_SDCARD_CHECK
#define _SDH_SDCARD_CHECK

/*! @brief Reverse byte sequence in uint32_t */
#define SWAP_WORD_BYTE_SEQUENCE(x) (__REV(x))

/*! @brief Default block size */
#define SDH_DEFAULT_BLOCK_SIZE     (512U)

typedef enum {
    SD_OK = 0,
    SD_CMD_ERROR,
    SD_DataCfg_ERROR,
    SD_WAITING,
} SD_Error;

/*! @brief Type used for all status and error return values. */
typedef int32_t status_t;
/*! @brief Construct a status code value from a group and code number. */
#define MAKE_STATUS(group, code) ((((group)*100) + (code)))

/*! @brief Status group numbers. */
enum _status_groups {
    StatusGroup_Generic = 0, /*!< Group number for generic status codes. */
    StatusGroup_SDH = 1,     /*!< Group number for SDHC status code */
};

/*! @brief Generic status return codes. */
enum _generic_status {
    Status_Success = MAKE_STATUS(StatusGroup_Generic, 0),
    Status_Fail = MAKE_STATUS(StatusGroup_Generic, 1),
    Status_OutOfRange = MAKE_STATUS(StatusGroup_Generic, 2),
    Status_InvalidArgument = MAKE_STATUS(StatusGroup_Generic, 3),
    Status_Timeout = MAKE_STATUS(StatusGroup_Generic, 4),

};
/*! @brief SD/MMC card API's running status. */
enum _sdmmc_status {
    Status_SDH_NotSupportYet = MAKE_STATUS(StatusGroup_SDH, 0U),                      /*!< Haven't supported */
    Status_SDH_TransferFailed = MAKE_STATUS(StatusGroup_SDH, 1U),                     /*!< Send command failed */
    Status_SDH_SetCardBlockSizeFailed = MAKE_STATUS(StatusGroup_SDH, 2U),             /*!< Set block size failed */
    Status_SDH_HostNotSupport = MAKE_STATUS(StatusGroup_SDH, 3U),                     /*!< Host doesn't support */
    Status_SDH_CardNotSupport = MAKE_STATUS(StatusGroup_SDH, 4U),                     /*!< Card doesn't support */
    Status_SDH_AllSendCidFailed = MAKE_STATUS(StatusGroup_SDH, 5U),                   /*!< Send CID failed */
    Status_SDH_SendRelativeAddressFailed = MAKE_STATUS(StatusGroup_SDH, 6U),          /*!< Send relative address failed */
    Status_SDH_SendCsdFailed = MAKE_STATUS(StatusGroup_SDH, 7U),                      /*!< Send CSD failed */
    Status_SDH_SelectCardFailed = MAKE_STATUS(StatusGroup_SDH, 8U),                   /*!< Select card failed */
    Status_SDH_SendScrFailed = MAKE_STATUS(StatusGroup_SDH, 9U),                      /*!< Send SCR failed */
    Status_SDH_SetDataBusWidthFailed = MAKE_STATUS(StatusGroup_SDH, 10U),             /*!< Set bus width failed */
    Status_SDH_GoIdleFailed = MAKE_STATUS(StatusGroup_SDH, 11U),                      /*!< Go idle failed */
    Status_SDH_HandShakeOperationConditionFailed = MAKE_STATUS(StatusGroup_SDH, 12U), /*!< Send Operation Condition failed */
    Status_SDH_SendApplicationCommandFailed = MAKE_STATUS(StatusGroup_SDH, 13U),      /*!< Send application command failed */
    Status_SDH_SwitchFailed = MAKE_STATUS(StatusGroup_SDH, 14U),                      /*!< Switch command failed */
    Status_SDH_StopTransmissionFailed = MAKE_STATUS(StatusGroup_SDH, 15U),            /*!< Stop transmission failed */
    Status_SDH_WaitWriteCompleteFailed = MAKE_STATUS(StatusGroup_SDH, 16U),           /*!< Wait write complete failed */
    Status_SDH_SetBlockCountFailed = MAKE_STATUS(StatusGroup_SDH, 17U),               /*!< Set block count failed */
    Status_SDH_SetRelativeAddressFailed = MAKE_STATUS(StatusGroup_SDH, 18U),          /*!< Set relative address failed */
    Status_SDH_SwitchBusTimingFailed = MAKE_STATUS(StatusGroup_SDH, 19U),             /*!< Switch high speed failed */
    Status_SDH_SendExtendedCsdFailed = MAKE_STATUS(StatusGroup_SDH, 20U),             /*!< Send EXT_CSD failed */
    Status_SDH_ConfigureBootFailed = MAKE_STATUS(StatusGroup_SDH, 21U),               /*!< Configure boot failed */
    Status_SDH_ConfigureExtendedCsdFailed = MAKE_STATUS(StatusGroup_SDH, 22U),        /*!< Configure EXT_CSD failed */
    Status_SDH_EnableHighCapacityEraseFailed = MAKE_STATUS(StatusGroup_SDH, 23U),     /*!< Enable high capacity erase failed */
    Status_SDH_SendTestPatternFailed = MAKE_STATUS(StatusGroup_SDH, 24U),             /*!< Send test pattern failed */
    Status_SDH_ReceiveTestPatternFailed = MAKE_STATUS(StatusGroup_SDH, 25U),          /*!< Receive test pattern failed */
    Status_SDH_SDIO_ResponseError = MAKE_STATUS(StatusGroup_SDH, 26U),                /*!< sdio response error */
    Status_SDH_SDIO_InvalidArgument = MAKE_STATUS(StatusGroup_SDH, 27U),              /*!< sdio invalid argument response error */
    Status_SDH_SDIO_SendOperationConditionFail = MAKE_STATUS(StatusGroup_SDH, 28U),   /*!< sdio send operation condition fail */
    Status_SDH_InvalidVoltage = MAKE_STATUS(StatusGroup_SDH, 29U),                    /*!<  invaild voltage */
    Status_SDH_SDIO_SwitchHighSpeedFail = MAKE_STATUS(StatusGroup_SDH, 30U),          /*!<  switch to high speed fail */
    Status_SDH_SDIO_ReadCISFail = MAKE_STATUS(StatusGroup_SDH, 31U),                  /*!<  read CIS fail */
    Status_SDH_SDIO_InvalidCard = MAKE_STATUS(StatusGroup_SDH, 32U),                  /*!<  invaild SDIO card */
    Status_SDH_TuningFail = MAKE_STATUS(StatusGroup_SDH, 33U),                        /*!<  tuning fail */
    Status_SDH_SwitchVoltageFail = MAKE_STATUS(StatusGroup_SDH, 34U),                 /*!< switch voltage fail*/
    Status_SDH_ReTuningRequest = MAKE_STATUS(StatusGroup_SDH, 35U),                   /*!<  retuning request */
    Status_SDH_SetDriverStrengthFail = MAKE_STATUS(StatusGroup_SDH, 36U),             /*!<  set driver strength fail */
    Status_SDH_SetPowerClassFail = MAKE_STATUS(StatusGroup_SDH, 37U),                 /*!<  set power class fail */
    Status_SDH_HostNotReady = MAKE_STATUS(StatusGroup_SDH, 38U),                      /*!<  host controller not ready */
    Status_SDH_CardDetectFailed = MAKE_STATUS(StatusGroup_SDH, 39U),                  /*!<  card detect failed */
    Status_SDH_CmdResponseError = MAKE_STATUS(StatusGroup_SDH, 40U),                  /*!<  cmd response timeout */
    Status_SDH_SendSsrFailed = MAKE_STATUS(StatusGroup_SDH, 41U),                     /*!< Send SSR failed */
};
/**
  * @brief  SDIO Transfer state
  */
typedef enum {
    SD_TRANSFER_OK = 0,
    SD_TRANSFER_BUSY = 1,
    SD_TRANSFER_ERROR
} SDTransferState;

/**
  * @brief  SD Card States
  */
typedef enum {
    SD_CARD_READY = ((uint32_t)0x00000001),
    SD_CARD_IDENTIFICATION = ((uint32_t)0x00000002),
    SD_CARD_STANDBY = ((uint32_t)0x00000003),
    SD_CARD_TRANSFER = ((uint32_t)0x00000004),
    SD_CARD_SENDING = ((uint32_t)0x00000005),
    SD_CARD_RECEIVING = ((uint32_t)0x00000006),
    SD_CARD_PROGRAMMING = ((uint32_t)0x00000007),
    SD_CARD_DISCONNECTED = ((uint32_t)0x00000008),
    SD_CARD_ERROR = ((uint32_t)0x000000FF)
} SDCardState;

/**
  * @brief  Card Specific Data: CSD Register
  */
typedef struct
{
    uint8_t CSDStruct;           /*!< CSD structure */
    uint8_t SysSpecVersion;      /*!< System specification version */
    uint8_t Reserved1;           /*!< Reserved */
    uint8_t TAAC;                /*!< Data read access-time 1 */
    uint8_t NSAC;                /*!< Data read access-time 2 in CLK cycles */
    uint8_t MaxBusClkFrec;       /*!< Max. bus clock frequency */
    uint16_t CardComdClasses;    /*!< Card command classes */
    uint8_t RdBlockLen;          /*!< Max. read data block length */
    uint8_t PartBlockRead;       /*!< Partial blocks for read allowed */
    uint8_t WrBlockMisalign;     /*!< Write block misalignment */
    uint8_t RdBlockMisalign;     /*!< Read block misalignment */
    uint8_t DSRImpl;             /*!< DSR implemented */
    uint8_t Reserved2;           /*!< Reserved */
    uint32_t DeviceSize;         /*!< Device Size */
    uint8_t MaxRdCurrentVDDMin;  /*!< Max. read current @ VDD min */
    uint8_t MaxRdCurrentVDDMax;  /*!< Max. read current @ VDD max */
    uint8_t MaxWrCurrentVDDMin;  /*!< Max. write current @ VDD min */
    uint8_t MaxWrCurrentVDDMax;  /*!< Max. write current @ VDD max */
    uint8_t DeviceSizeMul;       /*!< Device size multiplier */
    uint8_t EraseGrSize;         /*!< Erase group size */
    uint8_t EraseGrMul;          /*!< Erase group size multiplier */
    uint8_t WrProtectGrSize;     /*!< Write protect group size */
    uint8_t WrProtectGrEnable;   /*!< Write protect group enable */
    uint8_t ManDeflECC;          /*!< Manufacturer default ECC */
    uint8_t WrSpeedFact;         /*!< Write speed factor */
    uint8_t MaxWrBlockLen;       /*!< Max. write data block length */
    uint8_t WriteBlockPaPartial; /*!< Partial blocks for write allowed */
    uint8_t Reserved3;           /*!< Reserded */
    uint8_t ContentProtectAppli; /*!< Content protection application */
    uint8_t FileFormatGrouop;    /*!< File format group */
    uint8_t CopyFlag;            /*!< Copy flag (OTP) */
    uint8_t PermWrProtect;       /*!< Permanent write protection */
    uint8_t TempWrProtect;       /*!< Temporary write protection */
    uint8_t FileFormat;          /*!< File Format */
    uint8_t ECC;                 /*!< ECC code */
} SD_CSD;

/**
  * @brief  Card Identification Data: CID Register
  */
typedef struct
{
    uint8_t ManufacturerID; /*!< ManufacturerID */
    uint8_t OEM_AppliID[3]; /*!< OEM/Application ID end with 0 for str display*/
    uint8_t ProdName[6];    /*!< Product Name part1 end with 0 for str display*/
    uint8_t ProdRev;        /*!< Product Revision */
    uint32_t ProdSN;        /*!< Product Serial Number */
    uint8_t month;          /*!< Reserved1 */
    uint32_t year;          /*!< Manufacturing Date */
} SD_CID;

/**
  * @brief SD Card Status
  */
typedef struct
{
    uint8_t DAT_BUS_WIDTH;
    uint8_t SECURED_MODE;
    uint16_t SD_CARD_TYPE;
    uint32_t SIZE_OF_PROTECTED_AREA;
    uint8_t SPEED_CLASS;
    uint8_t PERFORMANCE_MOVE;
    uint8_t AU_SIZE;
    uint16_t ERASE_SIZE;
    uint8_t ERASE_TIMEOUT;
    uint8_t ERASE_OFFSET;
} SD_CardStatus;

/*******************************************************************************
 * Definitions
 ******************************************************************************/
/*! @brief OCR register in SD card */
enum _sd_ocr_flag {

    SD_OcrHostCapacitySupportFlag = (1U << 30U),                   /*!< Card capacity status */
    SD_OcrCardCapacitySupportFlag = SD_OcrHostCapacitySupportFlag, /*!< Card capacity status */
    SD_OcrSwitch18RequestFlag = (1U << 24U),                       /*!< Switch to 1.8V request */
    SD_OcrSwitch18AcceptFlag = SD_OcrSwitch18RequestFlag,          /*!< Switch to 1.8V accepted */
    SD_OcrVdd27_28Flag = (1U << 15U),                              /*!< VDD 2.7-2.8 */
    SD_OcrVdd28_29Flag = (1U << 16U),                              /*!< VDD 2.8-2.9 */
    SD_OcrVdd29_30Flag = (1U << 17U),                              /*!< VDD 2.9-3.0 */
    SD_OcrVdd30_31Flag = (1U << 18U),                              /*!< VDD 2.9-3.0 */
    SD_OcrVdd31_32Flag = (1U << 19U),                              /*!< VDD 3.0-3.1 */
    SD_OcrVdd32_33Flag = (1U << 20U),                              /*!< VDD 3.1-3.2 */
    SD_OcrVdd33_34Flag = (1U << 21U),                              /*!< VDD 3.2-3.3 */
    SD_OcrVdd34_35Flag = (1U << 22U),                              /*!< VDD 3.3-3.4 */
    SD_OcrVdd35_36Flag = (1U << 23U),                              /*!< VDD 3.4-3.5 */
};
/*! @brief SD card flags */
enum _sd_card_flag {
    SD_SupportHighCapacityFlag = (1U << 1U),     /*!< Support high capacity */
    SD_Support4BitWidthFlag = (1U << 2U),        /*!< Support 4-bit data width */
    SD_SupportSdhcFlag = (1U << 3U),             /*!< Card is SDHC */
    SD_SupportSdxcFlag = (1U << 4U),             /*!< Card is SDXC */
    SD_SupportVoltage180v = (1U << 5U),          /*!< card support 1.8v voltage*/
    SD_SupportSetBlockCountCmd = (1U << 6U),     /*!< card support cmd23 flag*/
    SD_SupportSpeedClassControlCmd = (1U << 7U), /*!< card support speed class control flag */
};
/*! @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[5];       /*!< 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 SCR register flags */
enum _sd_scr_flag {
    SD_ScrDataStatusAfterErase = (1U << 0U), /*!< Data status after erases [55:55] */
    SD_ScrSdSpecification3 = (1U << 1U),     /*!< Specification version 3.00 or higher [47:47]*/
};
/*! @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 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 SD Status register */
typedef struct _sd_ssr {
    uint8_t dataBusWidth;         /*!< Data Bus Width [511:510] 0b00--1line, 0b10--4line*/
    uint8_t secureMode;           /*!< Secure Mode [509] */
    uint16_t SDCardType;          /*!< SD Card Type [495:480] */
    uint32_t sizeOfProtectedArea; /*!< Size Of Protected area [479:448] */
    uint8_t speedClass;           /*!< speed classes [447:440] */
    uint8_t performanceMove;      /*!< performance move [439:432] */
    uint8_t AUSize;               /*!< AU size [431:428] */

    uint16_t eraseSize;    /*!< erase size [423:408] */
    uint8_t eraseTimeOut;  /*!< erase timeout [407:402] */
    uint8_t eraseOffset;   /*!< erase offset [401:400] */
    uint8_t UHSSpeedGrade; /*!< UHS speed grade [399:396] */
    uint8_t UHSAUSize;     /*!< UHS AU size [395:392] */
} sd_ssr_t;
/*!
 * @brief SD card state
 *
 * Define the card structure including the necessary fields to identify and describe the card.
 */
typedef struct _sd_card {
    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 rawSsr[16U];     /*!< 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_ssr_t ssr;             /*!< SCR */
    uint32_t blockCount;      /*!< Card total block number */
    uint32_t blockSize;       /*!< Card block size */
} sd_card_t;
/**
  * @brief SDIO Commands  Index
  */
#define SD_CMD_GO_IDLE_STATE                      ((uint8_t)0)
#define SD_CMD_SEND_OP_COND                       ((uint8_t)1)
#define SD_CMD_ALL_SEND_CID                       ((uint8_t)2)
#define SD_CMD_SET_REL_ADDR                       ((uint8_t)3) /*!< SDIO_SEND_REL_ADDR for SD Card */
#define SD_CMD_SET_DSR                            ((uint8_t)4)
#define SD_CMD_SDIO_SEN_OP_COND                   ((uint8_t)5)
#define SD_CMD_HS_SWITCH                          ((uint8_t)6)
#define SD_CMD_SEL_DESEL_CARD                     ((uint8_t)7)
#define SD_CMD_HS_SEND_EXT_CSD                    ((uint8_t)8)
#define SDIO_SEND_IF_COND                         ((uint8_t)8)
#define SD_CMD_SEND_CSD                           ((uint8_t)9)
#define SD_CMD_SEND_CID                           ((uint8_t)10)
#define SD_CMD_READ_DAT_UNTIL_STOP                ((uint8_t)11) /*!< SD Card doesn't support it */
#define SD_CMD_STOP_TRANSMISSION                  ((uint8_t)12)
#define SD_CMD_SEND_STATUS                        ((uint8_t)13)
#define SD_CMD_HS_BUSTEST_READ                    ((uint8_t)14)
#define SD_CMD_GO_INACTIVE_STATE                  ((uint8_t)15)
#define SD_CMD_SET_BLOCKLEN                       ((uint8_t)16)
#define SD_CMD_READ_SINGLE_BLOCK                  ((uint8_t)17)
#define SD_CMD_READ_MULT_BLOCK                    ((uint8_t)18)
#define SD_CMD_HS_BUSTEST_WRITE                   ((uint8_t)19)
#define SD_CMD_WRITE_DAT_UNTIL_STOP               ((uint8_t)20) /*!< SD Card doesn't support it */
#define SD_CMD_SET_BLOCK_COUNT                    ((uint8_t)23) /*!< SD Card doesn't support it */
#define SD_CMD_WRITE_SINGLE_BLOCK                 ((uint8_t)24)
#define SD_CMD_WRITE_MULT_BLOCK                   ((uint8_t)25)
#define SD_CMD_PROG_CID                           ((uint8_t)26) /*!< reserved for manufacturers */
#define SD_CMD_PROG_CSD                           ((uint8_t)27)
#define SD_CMD_SET_WRITE_PROT                     ((uint8_t)28)
#define SD_CMD_CLR_WRITE_PROT                     ((uint8_t)29)
#define SD_CMD_SEND_WRITE_PROT                    ((uint8_t)30)
#define SD_CMD_SD_ERASE_GRP_START                 ((uint8_t)32) /*!< To set the address of the first write
                                                                  block to be erased. (For SD card only) */
#define SD_CMD_SD_ERASE_GRP_END                   ((uint8_t)33) /*!< To set the address of the last write block of the
                                                                  continuous range to be erased. (For SD card only) */
#define SD_CMD_ERASE_GRP_START                    ((uint8_t)35) /*!< To set the address of the first write block to be erased.
                                                                  (For MMC card only spec 3.31) */

#define SD_CMD_ERASE_GRP_END                      ((uint8_t)36) /*!< To set the address of the last write block of the
                                                                  continuous range to be erased. (For MMC card only spec 3.31) */

#define SD_CMD_ERASE                              ((uint8_t)38)
#define SD_CMD_FAST_IO                            ((uint8_t)39) /*!< SD Card doesn't support it */
#define SD_CMD_GO_IRQ_STATE                       ((uint8_t)40) /*!< SD Card doesn't support it */
#define SD_CMD_LOCK_UNLOCK                        ((uint8_t)42)
#define SD_CMD_APP_CMD                            ((uint8_t)55)
#define SD_CMD_GEN_CMD                            ((uint8_t)56)
#define SD_CMD_NO_CMD                             ((uint8_t)64)

/**
  * @brief Following commands are SD Card Specific commands.
  *        SDIO_APP_CMD :CMD55 should be sent before sending these commands.
  */
#define SD_CMD_APP_SD_SET_BUSWIDTH                ((uint8_t)6)  /*!< For SD Card only */
#define SD_CMD_SD_APP_STAUS                       ((uint8_t)13) /*!< For SD Card only */
#define SD_CMD_SD_APP_SEND_NUM_WRITE_BLOCKS       ((uint8_t)22) /*!< For SD Card only */
#define SD_CMD_SD_APP_OP_COND                     ((uint8_t)41) /*!< For SD Card only */
#define SD_CMD_SD_APP_SET_CLR_CARD_DETECT         ((uint8_t)42) /*!< For SD Card only */
#define SD_CMD_SD_APP_SEND_SCR                    ((uint8_t)51) /*!< For SD Card only */
#define SD_CMD_SDIO_RW_DIRECT                     ((uint8_t)52) /*!< For SD I/O Card only */
#define SD_CMD_SDIO_RW_EXTENDED                   ((uint8_t)53) /*!< For SD I/O Card only */

/**
  * @brief Following commands are SD Card Specific security commands.
  *        SDIO_APP_CMD should be sent before sending these commands.
  */
#define SD_CMD_SD_APP_GET_MKB                     ((uint8_t)43) /*!< For SD Card only */
#define SD_CMD_SD_APP_GET_MID                     ((uint8_t)44) /*!< For SD Card only */
#define SD_CMD_SD_APP_SET_CER_RN1                 ((uint8_t)45) /*!< For SD Card only */
#define SD_CMD_SD_APP_GET_CER_RN2                 ((uint8_t)46) /*!< For SD Card only */
#define SD_CMD_SD_APP_SET_CER_RES2                ((uint8_t)47) /*!< For SD Card only */
#define SD_CMD_SD_APP_GET_CER_RES1                ((uint8_t)48) /*!< For SD Card only */
#define SD_CMD_SD_APP_SECURE_READ_MULTIPLE_BLOCK  ((uint8_t)18) /*!< For SD Card only */
#define SD_CMD_SD_APP_SECURE_WRITE_MULTIPLE_BLOCK ((uint8_t)25) /*!< For SD Card only */
#define SD_CMD_SD_APP_SECURE_ERASE                ((uint8_t)38) /*!< For SD Card only */
#define SD_CMD_SD_APP_CHANGE_SECURE_AREA          ((uint8_t)49) /*!< For SD Card only */
#define SD_CMD_SD_APP_SECURE_WRITE_MKB            ((uint8_t)48) /*!< For SD Card only */

/**
  * @brief  Mask for errors Card Status R1 (CSR Register)
  */
#define SD_CSR_ADDR_OUT_OF_RANGE                  ((uint32_t)0x80000000)
#define SD_CSR_ADDR_MISALIGNED                    ((uint32_t)0x40000000)
#define SD_CSR_BLOCK_LEN_ERR                      ((uint32_t)0x20000000)
#define SD_CSR_ERASE_SEQ_ERR                      ((uint32_t)0x10000000)
#define SD_CSR_BAD_ERASE_PARAM                    ((uint32_t)0x08000000)
#define SD_CSR_WRITE_PROT_VIOLATION               ((uint32_t)0x04000000)
#define SD_CSR_LOCK_UNLOCK_FAILED                 ((uint32_t)0x01000000)
#define SD_CSR_COM_CRC_FAILED                     ((uint32_t)0x00800000)
#define SD_CSR_ILLEGAL_CMD                        ((uint32_t)0x00400000)
#define SD_CSR_CARD_ECC_FAILED                    ((uint32_t)0x00200000)
#define SD_CSR_CC_ERROR                           ((uint32_t)0x00100000)
#define SD_CSR_GENERAL_UNKNOWN_ERROR              ((uint32_t)0x00080000)
#define SD_CSR_STREAM_READ_UNDERRUN               ((uint32_t)0x00040000)
#define SD_CSR_STREAM_WRITE_OVERRUN               ((uint32_t)0x00020000)
#define SD_CSR_CID_CSD_OVERWRIETE                 ((uint32_t)0x00010000)
#define SD_CSR_WP_ERASE_SKIP                      ((uint32_t)0x00008000)
#define SD_CSR_CARD_ECC_DISABLED                  ((uint32_t)0x00004000)
#define SD_CSR_ERASE_RESET                        ((uint32_t)0x00002000)
#define SD_CSR_AKE_SEQ_ERROR                      ((uint32_t)0x00000008)
#define SD_CSR_ERRORBITS                          ((uint32_t)0xFDFFE008)

#define SD_MAX_VOLT_TRIAL                         ((uint32_t)0x0000FFFF)
#define SD_ALLZERO                                ((uint32_t)0x00000000)

#define SD_WIDE_BUS_SUPPORT                       ((uint32_t)0x00040000)
#define SD_SINGLE_BUS_SUPPORT                     ((uint32_t)0x00010000)
#define SD_CARD_LOCKED                            ((uint32_t)0x02000000)

#define SD_0TO7BITS                               ((uint32_t)0x000000FF)
#define SD_8TO15BITS                              ((uint32_t)0x0000FF00)
#define SD_16TO23BITS                             ((uint32_t)0x00FF0000)
#define SD_24TO31BITS                             ((uint32_t)0xFF000000)
#define SD_MAX_DATA_LENGTH                        ((uint32_t)0x01FFFFFF)
/**
  * @brief  Masks for R7 Response
  */
#define SD_VOLTAGE_WINDOW_SD                      ((uint32_t)0x00100000)
#define SD_HIGH_CAPACITY                          ((uint32_t)0x40000000)
#define SD_STD_CAPACITY                           ((uint32_t)0x00000000)
#define SD_CHECK_PATTERN                          ((uint32_t)0x000001AA)

/**
  * @brief Supported SD Memory Cards
  */
#define SDIO_STD_CAPACITY_SD_CARD_V1_1            ((uint32_t)0x00000000)
#define SDIO_STD_CAPACITY_SD_CARD_V2_0            ((uint32_t)0x00000001)
#define SDIO_HIGH_CAPACITY_SD_CARD                ((uint32_t)0x00000002)
#define SDIO_MULTIMEDIA_CARD                      ((uint32_t)0x00000003)
#define SDIO_SECURE_DIGITAL_IO_CARD               ((uint32_t)0x00000004)
#define SDIO_HIGH_SPEED_MULTIMEDIA_CARD           ((uint32_t)0x00000005)
#define SDIO_SECURE_DIGITAL_IO_COMBO_CARD         ((uint32_t)0x00000006)
#define SDIO_HIGH_CAPACITY_MMC_CARD               ((uint32_t)0x00000007)

/*! @brief SD group number */
typedef enum _sd_group_num {
    SDH_GroupTimingMode = 0U,     /*!< acess mode group*/
    SDH_GroupCommandSystem = 1U,  /*!< command system group*/
    SDH_GroupDriverStrength = 2U, /*!< driver strength group*/
    SDH_GroupCurrentLimit = 3U,   /*!< current limit group*/
} sd_group_num;

/*! @brief SD card timing mode flags */
typedef enum _sd_timing_mode {
    SDH_TimingSDR12DefaultMode = 0U,   /*!< Identification mode & SDR12 */
    SDH_TimingSDR25HighSpeedMode = 1U, /*!< High speed mode & SDR25 */
    SDH_TimingSDR50Mode = 2U,          /*!< SDR50 mode*/
    SDH_TimingSDR104Mode = 3U,         /*!< SDR104 mode */
    SDH_TimingDDR50Mode = 4U,          /*!< DDR50 mode */
} sd_timing_mode_t;

/*! @brief SD card specification version number */
enum _sd_specification_version {
    SD_SpecificationVersion1_0 = (1U << 0U), /*!< SD card version 1.0-1.01 */
    SD_SpecificationVersion1_1 = (1U << 1U), /*!< SD card version 1.10 */
    SD_SpecificationVersion2_0 = (1U << 2U), /*!< SD card version 2.00 */
    SD_SpecificationVersion3_0 = (1U << 3U), /*!< SD card version 3.0 */
};

/*! @brief SD card switch mode */
typedef enum _sd_switch_mode {
    SDH_SwitchCheck = 0U, /*!< SD switch mode 0: check function */
    SDH_SwitchSet = 1U,   /*!< SD switch mode 1: set function */
} sd_switch_mode_t;

// #define SDH_DEBUG
#ifdef SDH_DEBUG
#define SDH_MSG(a, ...) printf(a, ##__VA_ARGS__)
#else
#define SDH_MSG(a, ...)
#endif

/*
bus_wide shoud be SDH_DATA_BUS_WIDTH_1BIT/SDH_DATA_BUS_WIDTH_4BITS/SDH_DATA_BUS_WIDTH_8BITS
*/
status_t SDH_ClockSet(uint32_t clockInit, uint32_t clockSrc, uint32_t clockTransfer);
status_t SDH_Init(uint32_t bus_wide, sd_card_t *pOutCardInfo);
status_t SD_Erase(uint32_t startaddr, uint32_t endaddr);
status_t SDH_ReadMultiBlocks(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);
status_t SDH_WriteMultiBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);

#endif
#endif

sdh_sdcard.c

/**
 * @file sdh_sdcard.c
 * @brief
 *
 * Copyright (c) 2021 Bouffalolab team
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 */

#if defined(BL616) || defined(BL808) || defined(BL628) || defined(BL606P)

#include "sdh_sdcard.h"
#include "bflb_mtimer.h"
#include "bflb_l1c.h"

#define SDIO_CMDTIMEOUT_MS   (1000)
#define SDIO_SDCARD_INT_MODE (0) /* Interrupt mode, which can be paired with the OS */

/* Private variables ---------------------------------------------------------*/

static uint32_t sdhClockInit = 100ul;
static uint32_t sdhClockSrc = 100ul;
static uint32_t sdhClockTransfer = 100ul;

static sd_card_t *pSDCardInfo = NULL;
static SDH_Cfg_Type SDH_Cfg_Type_Instance;

#if SDIO_SDCARD_INT_MODE
static volatile SD_Error SDH_DataWaitStatus = SD_WAITING;
static volatile SD_Error SDH_CMDWaitStatus = SD_WAITING;

static SDH_Trans_Callback_Cfg_Type SDH_Trans_Callback_Cfg_TypeInstance;
static SDH_Handle_Cfg_Type SDH_Handle_Cfg_TypeInstance;
#endif

static SDH_DMA_Cfg_Type SDH_DMA_Cfg_TypeInstance;
/*causion: ADMA related variables must on OCRAM or shared ram*/
static __attribute__((aligned(32), section(".noncacheable"))) SDH_ADMA2_Desc_Type adma2Entries[16];

/* Private function prototypes -----------------------------------------------*/
static void SD_DecodeCid(sd_card_t *card, uint32_t *rawCid);
static void SD_DecodeCsd(sd_card_t *card, uint32_t *rawCsd);
static void SD_DecodeScr(sd_card_t *card, uint32_t *rawScr);
#if SDIO_SDCARD_INT_MODE
static void SDH_INT_Init(void);
#endif
static status_t SDH_SendCardCommand(SDH_CMD_Cfg_Type *cmd);
static void SDH_HostInit(void);
static status_t SDH_GoIdle(void);
static status_t SD_SendApplicationCmd(uint32_t relativeAddress);
static status_t SD_SendInterfaceCondition(void);
static status_t SD_ApplicationSendOperationCondition(sd_card_t *card, uint32_t argument);
static status_t SD_AllSendCid(sd_card_t *card);
static status_t SD_SendRca(sd_card_t *card);
static status_t SD_SendCsd(sd_card_t *card);
static status_t SD_SelectCard(sd_card_t *card, BL_Fun_Type NewState);
static status_t SD_SendScr(sd_card_t *card);
static status_t SD_SendSsr(sd_card_t *card);
static status_t SD_SetDataBusWidth(sd_card_t *card, SDH_Data_Bus_Width_Type width);
static status_t SD_SwitchFunction(uint32_t mode, uint32_t group, uint32_t number, uint32_t status[16]);
static status_t SD_SelectFunction(uint32_t group, uint32_t function);
static status_t SD_SetBlockSize(uint32_t blockSize);
static status_t SDH_SDCardInit(uint32_t bus_wide, sd_card_t *card);
static status_t WaitInProgramming(void);
static status_t IsCardProgramming(uint8_t *pstatus);
static status_t SDH_CardTransferNonBlocking(SDH_DMA_Cfg_Type *dmaCfg, SDH_Trans_Cfg_Type *transfer);

static void SD_DecodeCid(sd_card_t *card, uint32_t *rawCid)
{
    sd_cid_t *cid;

    cid = &(card->cid);
    cid->manufacturerID = (uint8_t)((rawCid[3U] & 0xFF0000U) >> 16U);
    cid->applicationID = (uint16_t)((rawCid[3U] & 0xFFFFU) >> 0U);

    cid->productName[0U] = (uint8_t)((rawCid[1U] & 0xFF000000U) >> 24);
    cid->productName[1U] = (uint8_t)((rawCid[2U] & 0xFF) >> 0U);
    cid->productName[2U] = (uint8_t)((rawCid[2U] & 0xFF00U) >> 8U);
    cid->productName[3U] = (uint8_t)((rawCid[2U] & 0xFF0000U) >> 16U);
    cid->productName[4U] = (uint8_t)((rawCid[2U] & 0xFF000000U) >> 24U);

    cid->productVersion = (uint8_t)((rawCid[1U] & 0xFF0000U) >> 16U);

    cid->productSerialNumber = (uint32_t)((rawCid[1U] & 0xFFFFU) << 16U);
    cid->productSerialNumber |= (uint32_t)((rawCid[0U] & 0xFFFF0000U) >> 16U);

    cid->manufacturerData = (uint16_t)((rawCid[0U] & 0xFFFU) >> 0U);
}
static void SD_DecodeCsd(sd_card_t *card, uint32_t *rawCsd)
{
    sd_csd_t *csd;

    csd = &(card->csd);
    csd->csdStructure = (uint8_t)((rawCsd[3U] & 0xC00000U) >> 22U);
    csd->dataReadAccessTime1 = (uint8_t)((rawCsd[3U] & 0xFF00U) >> 8U);
    csd->dataReadAccessTime2 = (uint8_t)((rawCsd[3U] & 0xFFU) >> 0U);

    csd->transferSpeed = (uint8_t)((rawCsd[2U] & 0xFF000000U) >> 24);
    csd->cardCommandClass = (uint16_t)((rawCsd[2U] & 0xFFF000U) >> 12U);
    csd->readBlockLength = (uint8_t)((rawCsd[2U] & 0xF00U) >> 8U);

    switch (csd->csdStructure) {
        /*csd version 1.1*/
        case 0:
            csd->deviceSize = (uint32_t)((rawCsd[2U] & 0x3U) << 10U);
            csd->deviceSize |= (uint32_t)((rawCsd[1U] & 0xFFC00000U) >> 22U);

            csd->deviceSizeMultiplier = (uint8_t)((rawCsd[1U] & 0x380U) >> 7U);

            /* Get card total block count and block size. */
            card->blockCount = ((csd->deviceSize + 1U) << (csd->deviceSizeMultiplier + 2U));
            card->blockSize = (1U << (csd->readBlockLength));

            if (card->blockSize != SDH_DEFAULT_BLOCK_SIZE) {
                card->blockCount = (card->blockCount * card->blockSize);
                card->blockSize = SDH_DEFAULT_BLOCK_SIZE;
                card->blockCount = (card->blockCount / card->blockSize);
            }

            break;

        /*csd version 2.0*/
        case 1:
            card->blockSize = SDH_DEFAULT_BLOCK_SIZE;
            csd->deviceSize = (uint32_t)((rawCsd[1U] & 0x3FFFFF00U) >> 8U);

            if (csd->deviceSize >= 0xFFFFU) {
                card->flags |= SD_SupportSdxcFlag;
            }

            card->blockCount = ((csd->deviceSize + 1U) * 1024U);
            break;

        default:
            break;
    }
}
static void SD_DecodeScr(sd_card_t *card, uint32_t *rawScr)
{
    sd_scr_t *scr;

    scr = &(card->scr);
    scr->scrStructure = (uint8_t)((rawScr[1U] & 0xF0000000U) >> 28U);
    scr->sdSpecification = (uint8_t)((rawScr[1U] & 0xF000000U) >> 24U);

    if ((uint8_t)((rawScr[1U] & 0x800000U) >> 23U)) {
        scr->flags |= SD_ScrDataStatusAfterErase;
    }

    scr->sdSecurity = (uint8_t)((rawScr[1U] & 0x700000U) >> 20U);
    scr->sdBusWidths = (uint8_t)((rawScr[1U] & 0xF0000U) >> 16U);

    if ((uint8_t)((rawScr[0U] & 0x8000U) >> 15U)) {
        scr->flags |= SD_ScrSdSpecification3;
    }

    scr->extendedSecurity = (uint8_t)((rawScr[1U] & 0x7800U) >> 10U);
    scr->commandSupport = (uint8_t)(rawScr[1U] & 0x3U);
    scr->reservedForManufacturer = rawScr[0U];

    /* Get specification version. */
    switch (scr->sdSpecification) {
        case 0U:
            card->version = SD_SpecificationVersion1_0;
            break;

        case 1U:
            card->version = SD_SpecificationVersion1_1;
            break;

        case 2U:
            card->version = SD_SpecificationVersion2_0;

            if (card->scr.flags & SD_ScrSdSpecification3) {
                card->version = SD_SpecificationVersion3_0;
            }

            break;

        default:
            break;
    }

    if (card->scr.sdBusWidths & 0x4U) {
        card->flags |= SD_Support4BitWidthFlag;
    }

    /* speed class control cmd */
    if (card->scr.commandSupport & 0x01U) {
        card->flags |= SD_SupportSpeedClassControlCmd;
    }

    /* set block count cmd */
    if (card->scr.commandSupport & 0x02U) {
        card->flags |= SD_SupportSetBlockCountCmd;
    }
}

#if SDIO_SDCARD_INT_MODE
/*!< SDH transfer complete callback */
void SDH_DataTransferFinished_CallBack(SDH_Handle_Cfg_Type *handle, SDH_Stat_Type status, void *userData)
{
    //bflb_platform_printf("Interrupt occurs! intFlag=0x%02x,\r\n",handle->intFlag);
    if (status != SDH_STAT_SUCCESS) {
        SDH_DataWaitStatus = SD_DataCfg_ERROR;
    } else {
        SDH_DataWaitStatus = SD_OK;
    }
}
/*!< SDH transfer complete callback */
void SDH_CMDTransferFinished_CallBack(SDH_Handle_Cfg_Type *handle, SDH_Stat_Type status, void *userData)
{
    //bflb_platform_printf("Interrupt occurs! intFlag=0x%02x,\r\n",handle->intFlag);
    if (status != SDH_STAT_SUCCESS) {
        SDH_CMDWaitStatus = SD_CMD_ERROR;
    } else {
        SDH_CMDWaitStatus = SD_OK;
    }
}

extern void SDH_MMC1_IRQHandler(void);
static void sdh_isr(int irq, void *arg)
{
    SDH_MMC1_IRQHandler();
}
/****************************************************************************/ /**
 * @brief  SDH INT init
 *
 * @param  None
 *
 * @return None
 *
*******************************************************************************/
static void SDH_INT_Init(void)
{
    bflb_irq_attach(33, sdh_isr, NULL);
    bflb_irq_enable(33);

    SDH_EnableIntStatus(SDH_INT_ALL);
    SDH_DisableIntSource(SDH_INT_ALL);
    SDH_Trans_Callback_Cfg_TypeInstance.SDH_CallBack_TransferFinished = SDH_DataTransferFinished_CallBack;
    SDH_Trans_Callback_Cfg_TypeInstance.SDH_CMDCallBack_TransferFinished = SDH_CMDTransferFinished_CallBack;
    SDH_InstallHandleCallback(&SDH_Handle_Cfg_TypeInstance, &SDH_Trans_Callback_Cfg_TypeInstance, NULL);
}
#endif

static status_t SDH_SendCardCommand(SDH_CMD_Cfg_Type *cmd)
{
    status_t errorstatus = Status_Success;
    SD_Error sd_status;
    uint32_t time_node;

    SDH_ClearIntStatus(SDH_INT_CMD_COMPLETED | SDH_INT_CMD_ERRORS);

    SDH_SendCommand(cmd);
    time_node = (uint32_t)bflb_mtimer_get_time_ms();

#if SDIO_SDCARD_INT_MODE

    SDH_CMDWaitStatus = SD_WAITING;
    SDH_EnableIntSource(SDH_INT_CMD_COMPLETED | SDH_INT_CMD_ERRORS);

    /*wait for Xfer status. might pending here in multi-task OS*/
    while (SDH_CMDWaitStatus == SD_WAITING) {
        if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("SDH send CMD%ld timeout: %ld ms\r\n", cmd->index, (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            SDH_DisableIntSource(SDH_INT_CMD_COMPLETED | SDH_INT_CMD_ERRORS);
            return Status_Timeout;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }
    sd_status = SDH_CMDWaitStatus;
    SDH_DisableIntSource(SDH_INT_CMD_COMPLETED | SDH_INT_CMD_ERRORS);

#else

    uint32_t intFlag;
    while (1) {
        intFlag = SDH_GetIntStatus();
        if (intFlag & SDH_INT_CMD_ERRORS) {
            sd_status = SD_CMD_ERROR;
            break;

        } else if (intFlag & SDH_INT_CMD_COMPLETED) {
            sd_status = SD_OK;
            break;

        } else if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("SDH send CMD%ld timeout: %ld ms\r\n", cmd->index, (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            return Status_Timeout;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }
    SDH_ClearIntStatus(intFlag & (SDH_INT_CMD_ERRORS | SDH_INT_CMD_COMPLETED));

#endif

    // SDH_MSG("SDH send CMD%ld used time : %d\r\n", cmd->index, (uint32_t)bflb_mtimer_get_time_ms() - time_node);

    if (sd_status != SD_OK) {
        SDH_MSG("SDH send CMD%ld error\r\n", cmd->index);
        errorstatus = Status_SDH_CmdResponseError;
    } else {
        SDH_GetCmdResp(cmd);
        SDH_MSG("SDH send CMD%ld success\r\n", cmd->index);
    }

    return errorstatus;
}

static void SDH_HostInit(void)
{
    GLB_Set_SDH_CLK(ENABLE, GLB_SDH_CLK_WIFIPLL_96M, 7);

    /* initialise SDH controller*/
    SDH_Cfg_Type_Instance.vlot18Enable = DISABLE;
    SDH_Cfg_Type_Instance.highSpeed = ENABLE;
    SDH_Cfg_Type_Instance.dataWidth = SDH_DATA_BUS_WIDTH_1BIT;
    SDH_Cfg_Type_Instance.volt = SDH_VOLTAGE_3P3V;
    SDH_Cfg_Type_Instance.srcClock = sdhClockSrc;
    SDH_Cfg_Type_Instance.busClock = sdhClockInit;
    SDH_Ctrl_Init(&SDH_Cfg_Type_Instance);

    /*setup timeout counter*/
    SDH_Set_Timeout(0x0e);

    /*power on host controller*/
    SDH_Powon();
}

/*
* GO_IDLE_STATE, send card to reset state
*/
static status_t SDH_GoIdle(void)
{
    status_t errorstatus = Status_Success;
    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    /*CMD0: GO_IDLE_STATE, send card to reset state*/
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_GO_IDLE_STATE;
    SDH_CMD_Cfg_TypeInstance.argument = 0;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_NONE;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);
    return errorstatus;
}

static status_t SD_SendApplicationCmd(uint32_t relativeAddress)
{
    status_t errorstatus = Status_Success;
    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    /* send CMD55 */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_APP_CMD;
    SDH_CMD_Cfg_TypeInstance.argument = relativeAddress;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        return Status_SDH_CmdResponseError;
    } else if (SDH_CMD_Cfg_TypeInstance.response[0] & SD_CSR_ERRORBITS) {
        return Status_SDH_CmdResponseError;
    }

    return errorstatus;
}

static status_t SD_SendInterfaceCondition(void)
{
    status_t errorstatus = Status_Success;
    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    /* CMD8: SEND_IF_COND */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_HS_SEND_EXT_CSD;
    SDH_CMD_Cfg_TypeInstance.argument = SD_CHECK_PATTERN;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R7;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        return Status_SDH_CmdResponseError;
    }

    SDH_MSG("Response to CMD8 is: 0x%02x.\r\n", SDH_CMD_Cfg_TypeInstance.response[0]);

    if ((SDH_CMD_Cfg_TypeInstance.response[0U] & 0xFFU) != (SD_CHECK_PATTERN & 0xff)) {
        return Status_SDH_CardNotSupport;
    }

    return errorstatus;
}

static status_t SD_ApplicationSendOperationCondition(sd_card_t *card, uint32_t argument)
{
    status_t errorstatus = Status_Success;
    uint32_t response = 0, count = 0, validvoltage = 0;
    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    do {
        if (Status_Success != (errorstatus = SD_SendApplicationCmd(0))) {
            return errorstatus;
        }

        /*ACMD41*/
        SDH_CMD_Cfg_TypeInstance.index = SD_CMD_SD_APP_OP_COND;
        SDH_CMD_Cfg_TypeInstance.argument = argument;
        SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
        SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R3;
        SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

        errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

        if (errorstatus != Status_Success) {
            return Status_SDH_CmdResponseError;
        }

        response = SDH_CMD_Cfg_TypeInstance.response[0];
        validvoltage = (((response >> 31) == 1) ? 1 : 0);
        count++;
    } while ((!validvoltage) && (count < SD_MAX_VOLT_TRIAL));

    if (count == SD_MAX_VOLT_TRIAL) {
        return Status_Timeout;
    } else {
        card->ocr = response;

        if (response &= SD_OcrHostCapacitySupportFlag) {
            /* change from sdsc to sdhc */
            card->flags |= SD_SupportHighCapacityFlag;
        }
    }

    return errorstatus;
}
static status_t SD_AllSendCid(sd_card_t *card)
{
    status_t errorstatus = Status_Success;
    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    /* CMD2: SD_CMD_ALL_SEND_CID */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_ALL_SEND_CID;
    SDH_CMD_Cfg_TypeInstance.argument = 0;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R2;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        return Status_SDH_CmdResponseError;
    }

    card->rawCid[0] = SDH_CMD_Cfg_TypeInstance.response[0];
    card->rawCid[1] = SDH_CMD_Cfg_TypeInstance.response[1];
    card->rawCid[2] = SDH_CMD_Cfg_TypeInstance.response[2];
    card->rawCid[3] = SDH_CMD_Cfg_TypeInstance.response[3];

    SD_DecodeCid(card, card->rawCid);

    return errorstatus;
}

static status_t SD_SendRca(sd_card_t *card)
{
    status_t errorstatus = Status_Success;
    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    /*CMD3: send relative card address*/
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_SET_REL_ADDR;
    SDH_CMD_Cfg_TypeInstance.argument = 0;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R6;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        return Status_SDH_CmdResponseError;
    }

    card->relativeAddress = SDH_CMD_Cfg_TypeInstance.response[0] >> 16;

    return errorstatus;
}

static status_t SD_SendCsd(sd_card_t *card)
{
    status_t errorstatus = Status_Success;
    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    /*CMD9: send card-specific data(CSD)*/
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_SEND_CSD;
    SDH_CMD_Cfg_TypeInstance.argument = (uint32_t)((card->relativeAddress) << 16);
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R2;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        return Status_SDH_CmdResponseError;
    }

    card->rawCsd[0] = SDH_CMD_Cfg_TypeInstance.response[0];
    card->rawCsd[1] = SDH_CMD_Cfg_TypeInstance.response[1];
    card->rawCsd[2] = SDH_CMD_Cfg_TypeInstance.response[2];
    card->rawCsd[3] = SDH_CMD_Cfg_TypeInstance.response[3];

    SD_DecodeCsd(card, card->rawCsd);

    return errorstatus;
}

static status_t SD_SelectCard(sd_card_t *card, BL_Fun_Type NewState)
{
    status_t errorstatus = Status_Success;
    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    /* CMD7: select/deselect specified card */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_SEL_DESEL_CARD;

    if (NewState == ENABLE) {
        SDH_CMD_Cfg_TypeInstance.argument = (uint32_t)((card->relativeAddress) << 16);
        SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1B;
    } else {
        SDH_CMD_Cfg_TypeInstance.argument = 0;
        SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_NONE;
    }

    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        return Status_SDH_TransferFailed;
    } else if ((NewState == ENABLE) && (SDH_CMD_Cfg_TypeInstance.response[0] & SD_CSR_ERRORBITS)) {
        return Status_SDH_CmdResponseError;
    }

    return errorstatus;
}

/* get CSR */
static status_t SD_SendScr(sd_card_t *card)
{
    status_t errorstatus = Status_Success;
    SDH_Stat_Type stat = SDH_STAT_SUCCESS;
    SD_Error sd_status;

    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;
    SDH_Data_Cfg_Type SDH_Data_Cfg_TypeInstance;
    uint32_t tempscr[2] = { 0, 0 };
    uint32_t time_node;

    /* send CMD55 */
    errorstatus = SD_SendApplicationCmd((uint32_t)((card->relativeAddress) << 16));

    if (errorstatus != Status_Success) {
        goto out;
    }

    /*!< Set Block Size To 8 Bytes */
    SDH_Data_Cfg_TypeInstance.enableAutoCommand12 = DISABLE;
    SDH_Data_Cfg_TypeInstance.enableAutoCommand23 = DISABLE;
    SDH_Data_Cfg_TypeInstance.enableIgnoreError = DISABLE;
    SDH_Data_Cfg_TypeInstance.dataType = SDH_TRANS_DATA_NORMAL;
    SDH_Data_Cfg_TypeInstance.blockSize = 8;
    SDH_Data_Cfg_TypeInstance.blockCount = 1;
    SDH_Data_Cfg_TypeInstance.rxDataLen = 0;
    SDH_Data_Cfg_TypeInstance.rxData = tempscr;
    SDH_Data_Cfg_TypeInstance.txDataLen = 0;
    SDH_Data_Cfg_TypeInstance.txData = NULL;
    /* Config the data transfer parameter */
    stat = SDH_ConfigDataTranfer(&SDH_Data_Cfg_TypeInstance);

    if (SDH_STAT_SUCCESS != stat) {
        return Status_SDH_TransferFailed;
    }

    /*!< Send ACMD51 SD_APP_SEND_SCR with argument as 0 */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_SD_APP_SEND_SCR;
    SDH_CMD_Cfg_TypeInstance.argument = 0;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_DATA_PRESENT;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        goto out;
    } else if (SDH_CMD_Cfg_TypeInstance.response[0] & SD_CSR_ERRORBITS) {
        errorstatus = Status_SDH_CmdResponseError;
        goto out;
    }

    /* Waiting for CSR data */
    time_node = (uint32_t)bflb_mtimer_get_time_ms();

#if SDIO_SDCARD_INT_MODE

    SDH_DataWaitStatus = SD_WAITING;
    SDH_EnableIntSource(SDH_INT_BUFFER_READ_READY | SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);

    /*wait for Xfer status. might pending here in multi-task OS*/
    while (SDH_DataWaitStatus == SD_WAITING) {
        if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("sdh get csr data timeout: %ld ms\r\n", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            SDH_DisableIntSource(SDH_INT_BUFFER_READ_READY | SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);
            errorstatus = Status_Timeout;
            goto out;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }

    SDH_DisableIntSource(SDH_INT_BUFFER_READ_READY | SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);
    sd_status = SDH_DataWaitStatus;

#else

    uint32_t intFlag;
    while (1) {
        intFlag = SDH_GetIntStatus();
        if (intFlag & SDH_INT_DATA_ERRORS || intFlag & SDH_INT_DMA_ERROR) {
            sd_status = SD_DataCfg_ERROR;
            break;

        } else if (intFlag & SDH_INT_BUFFER_READ_READY || intFlag & SDH_INT_DATA_COMPLETED) {
            sd_status = SD_OK;
            break;

        } else if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("SDH get csr data timeout: %ld ms\r\n", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            return Status_Timeout;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }
    SDH_ClearIntStatus(intFlag);

#endif

    if (sd_status == SD_OK) {
        SDH_ReadDataPort(&SDH_Data_Cfg_TypeInstance);
        card->rawScr[1] = ((tempscr[0] & SD_0TO7BITS) << 24) | ((tempscr[0] & SD_8TO15BITS) << 8) | ((tempscr[0] & SD_16TO23BITS) >> 8) | ((tempscr[0] & SD_24TO31BITS) >> 24);
        card->rawScr[0] = ((tempscr[1] & SD_0TO7BITS) << 24) | ((tempscr[1] & SD_8TO15BITS) << 8) | ((tempscr[1] & SD_16TO23BITS) >> 8) | ((tempscr[1] & SD_24TO31BITS) >> 24);
        SD_DecodeScr(card, card->rawScr);
        SDH_MSG("SDH get csr success\r\n");
    } else {
        errorstatus = Status_SDH_TransferFailed;
        SDH_MSG("SDH get csr failed\r\n");
        goto out;
    }

out:
    return errorstatus;
}

/* get SSR */
static status_t SD_SendSsr(sd_card_t *card)
{
    status_t errorstatus = Status_Success;
    SDH_Stat_Type stat = SDH_STAT_SUCCESS;
    SD_Error sd_status;
    uint32_t time_node;

    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;
    SDH_Data_Cfg_Type SDH_Data_Cfg_TypeInstance;

    errorstatus = SD_SendApplicationCmd((uint32_t)((card->relativeAddress) << 16));

    if (errorstatus != Status_Success) {
        goto out;
    }

    /*!< Set Block Size To 512 Bytes */
    SDH_Data_Cfg_TypeInstance.enableAutoCommand12 = DISABLE;
    SDH_Data_Cfg_TypeInstance.enableAutoCommand23 = DISABLE;
    SDH_Data_Cfg_TypeInstance.enableIgnoreError = DISABLE;
    SDH_Data_Cfg_TypeInstance.dataType = SDH_TRANS_DATA_NORMAL;
    SDH_Data_Cfg_TypeInstance.blockSize = 64;
    SDH_Data_Cfg_TypeInstance.blockCount = 1;
    SDH_Data_Cfg_TypeInstance.rxDataLen = 0;
    SDH_Data_Cfg_TypeInstance.rxData = card->rawSsr;
    SDH_Data_Cfg_TypeInstance.txDataLen = 0;
    SDH_Data_Cfg_TypeInstance.txData = NULL;
    /* Config the data transfer parameter */
    stat = SDH_ConfigDataTranfer(&SDH_Data_Cfg_TypeInstance);

    if (SDH_STAT_SUCCESS != stat) {
        return Status_SDH_TransferFailed;
    }

    /*!< Send ACMD13 SD_APP_SEND_SCR with argument as 0 */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_SD_APP_STAUS;
    SDH_CMD_Cfg_TypeInstance.argument = 0;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_DATA_PRESENT;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        goto out;
    } else if (SDH_CMD_Cfg_TypeInstance.response[0] & SD_CSR_ERRORBITS) {
        errorstatus = Status_SDH_CmdResponseError;
        goto out;
    }

    /* Waiting for SSR data */
    time_node = (uint32_t)bflb_mtimer_get_time_ms();

#if SDIO_SDCARD_INT_MODE

    SDH_DataWaitStatus = SD_WAITING;
    SDH_EnableIntSource(SDH_INT_BUFFER_READ_READY | SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);

    /*wait for Xfer status. might pending here in multi-task OS*/
    while (SDH_DataWaitStatus == SD_WAITING) {
        if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("SDH get ssr data timeout: %ld ms\r\n", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            SDH_DisableIntSource(SDH_INT_BUFFER_READ_READY | SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);
            errorstatus = Status_Timeout;
            goto out;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }

    SDH_DisableIntSource(SDH_INT_BUFFER_READ_READY | SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);
    sd_status = SDH_DataWaitStatus;

#else

    uint32_t intFlag;
    while (1) {
        intFlag = SDH_GetIntStatus();
        if (intFlag & SDH_INT_DATA_ERRORS || intFlag & SDH_INT_DMA_ERROR) {
            sd_status = SD_DataCfg_ERROR;
            break;

        } else if (intFlag & SDH_INT_BUFFER_READ_READY || intFlag & SDH_INT_DATA_COMPLETED) {
            sd_status = SD_OK;
            break;

        } else if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("SDH get ssr data timeout: %ld ms\r\n", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            errorstatus = Status_Timeout;
            goto out;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }
    SDH_ClearIntStatus(intFlag);

#endif

    if (sd_status == SD_OK) {
        SDH_ReadDataPort(&SDH_Data_Cfg_TypeInstance);
        SDH_MSG("SDH get ssr success\r\n");
    } else {
        errorstatus = Status_SDH_TransferFailed;
        SDH_MSG("SDH get ssr failed\r\n");
        goto out;
    }

out:
    return errorstatus;
}

/* Set Data Bus Width */
static status_t SD_SetDataBusWidth(sd_card_t *card, SDH_Data_Bus_Width_Type width)
{
    status_t errorstatus = Status_Success;
    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    if (width == SDH_DATA_BUS_WIDTH_1BIT) {
        SDH_CMD_Cfg_TypeInstance.argument = 0;
    } else if (width == SDH_DATA_BUS_WIDTH_4BITS) {
        SDH_CMD_Cfg_TypeInstance.argument = 2;
    } else {
        return Status_InvalidArgument;
    }

    errorstatus = SD_SendApplicationCmd((uint32_t)((card->relativeAddress) << 16));

    if (errorstatus != Status_Success) {
        goto out;
    }

    /*!< Send ACMD6 APP_CMD with argument as 2 for wide bus mode */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_APP_SD_SET_BUSWIDTH;

    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        goto out;
    } else if (SDH_CMD_Cfg_TypeInstance.response[0] & SD_CSR_ERRORBITS) {
        errorstatus = Status_SDH_CmdResponseError;
        goto out;
    }

    GLB_Set_SDH_CLK(ENABLE, GLB_SDH_CLK_WIFIPLL_96M, 1);

    /* reinitialise SDH controller*/
    SDH_Cfg_Type_Instance.vlot18Enable = DISABLE;
    SDH_Cfg_Type_Instance.highSpeed = ENABLE;
    SDH_Cfg_Type_Instance.dataWidth = width;
    SDH_Cfg_Type_Instance.volt = SDH_VOLTAGE_3P3V;
    SDH_Cfg_Type_Instance.srcClock = sdhClockSrc;
    SDH_Cfg_Type_Instance.busClock = sdhClockTransfer;
    SDH_Ctrl_Init(&SDH_Cfg_Type_Instance);

out:
    return errorstatus;
}

/* switch function
   mode: 0 check function, 1 set function
   group: group number,1~6
   number:
 */
static status_t SD_SwitchFunction(uint32_t mode, uint32_t group, uint32_t number, uint32_t status[16])
{
    status_t errorstatus = Status_Success;
    SDH_Stat_Type stat = SDH_STAT_SUCCESS;
    SD_Error sd_status;
    uint32_t time_node;

    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;
    SDH_Data_Cfg_Type SDH_Data_Cfg_TypeInstance;

    /*!< Set Block Size To 64 Bytes */
    SDH_Data_Cfg_TypeInstance.enableAutoCommand12 = DISABLE;
    SDH_Data_Cfg_TypeInstance.enableAutoCommand23 = DISABLE;
    SDH_Data_Cfg_TypeInstance.enableIgnoreError = DISABLE;
    SDH_Data_Cfg_TypeInstance.dataType = SDH_TRANS_DATA_NORMAL;
    SDH_Data_Cfg_TypeInstance.blockSize = 64;
    SDH_Data_Cfg_TypeInstance.blockCount = 1;
    SDH_Data_Cfg_TypeInstance.rxDataLen = 0;
    SDH_Data_Cfg_TypeInstance.rxData = status;
    SDH_Data_Cfg_TypeInstance.txDataLen = 0;
    SDH_Data_Cfg_TypeInstance.txData = NULL;
    /* Config the data transfer parameter */
    stat = SDH_ConfigDataTranfer(&SDH_Data_Cfg_TypeInstance);

    if (SDH_STAT_SUCCESS != stat) {
        return Status_SDH_TransferFailed;
    }

    /*!< Send CMD6 SD_CMD_HS_SWITCH with argument as 0 */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_HS_SWITCH;
    SDH_CMD_Cfg_TypeInstance.argument = (mode << 31U | 0x00FFFFFFU);
    SDH_CMD_Cfg_TypeInstance.argument &= ~((uint32_t)(0xFU) << (group * 4U));
    SDH_CMD_Cfg_TypeInstance.argument |= (number << (group * 4U));
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_DATA_PRESENT;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        goto out;
    } else if (SDH_CMD_Cfg_TypeInstance.response[0] & SD_CSR_ERRORBITS) {
        errorstatus = Status_SDH_CmdResponseError;
        goto out;
    }

    /* Waiting for CSR data */
    time_node = (uint32_t)bflb_mtimer_get_time_ms();

#if SDIO_SDCARD_INT_MODE

    SDH_DataWaitStatus = SD_WAITING;
    SDH_EnableIntSource(SDH_INT_BUFFER_READ_READY | SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR);

    /*wait for Xfer status. might pending here in multi-task OS*/
    while (SDH_DataWaitStatus == SD_WAITING) {
        if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("SDH get CMD6 status data timeout: %ld ms\r\n", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            SDH_DisableIntSource(SDH_INT_BUFFER_READ_READY | SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR);
            errorstatus = Status_Timeout;
            goto out;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }

    SDH_DisableIntSource(SDH_INT_BUFFER_READ_READY | SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR);
    sd_status = SDH_DataWaitStatus;

#else

    uint32_t intFlag;
    while (1) {
        intFlag = SDH_GetIntStatus();
        if (intFlag & SDH_INT_DATA_ERRORS || intFlag & SDH_INT_DMA_ERROR) {
            sd_status = SD_DataCfg_ERROR;
            break;

        } else if (intFlag & SDH_INT_BUFFER_READ_READY || intFlag & SDH_INT_DATA_COMPLETED) {
            sd_status = SD_OK;
            break;

        } else if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("SDH get CMD6 status data timeout: %ld ms\r\n", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            return Status_Timeout;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }
    SDH_ClearIntStatus(intFlag);

#endif

    if (sd_status == SD_OK) {
        SDH_ReadDataPort(&SDH_Data_Cfg_TypeInstance);
        SDH_MSG("SDH get CMD6 status data success\r\n");
    } else {
        errorstatus = Status_SDH_TransferFailed;
        SDH_MSG("SDH get CMD6 status data failed\r\n");
        goto out;
    }

out:
    return errorstatus;
}

/*  */
static __USED status_t SD_SelectFunction(uint32_t group, uint32_t function)
{
    status_t errorstatus = Status_Success;
    uint32_t cmd6Status[16] = { 0 };
    uint16_t functionGroupInfo[6U] = { 0 };
    uint32_t currentFunctionStatus = 0U;

    uint32_t i;

    /* Check if card support high speed mode. */
    if (Status_Success != SD_SwitchFunction(SDH_SwitchCheck, group, function, cmd6Status)) {
        return Status_SDH_SDIO_SwitchHighSpeedFail;
    }

    for (i = 0; i < 16; i++) {
        SDH_MSG("cmd6Status[%d]=0x%x.\r\n", i, cmd6Status[i]);
    }

    /* 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. */
    cmd6Status[0U] = SWAP_WORD_BYTE_SEQUENCE(cmd6Status[0U]);
    cmd6Status[1U] = SWAP_WORD_BYTE_SEQUENCE(cmd6Status[1U]);
    cmd6Status[2U] = SWAP_WORD_BYTE_SEQUENCE(cmd6Status[2U]);
    cmd6Status[3U] = SWAP_WORD_BYTE_SEQUENCE(cmd6Status[3U]);
    cmd6Status[4U] = SWAP_WORD_BYTE_SEQUENCE(cmd6Status[4U]);

    functionGroupInfo[5U] = (uint16_t)cmd6Status[0U];
    functionGroupInfo[4U] = (uint16_t)(cmd6Status[1U] >> 16U);
    functionGroupInfo[3U] = (uint16_t)(cmd6Status[1U]);
    functionGroupInfo[2U] = (uint16_t)(cmd6Status[2U] >> 16U);
    functionGroupInfo[1U] = (uint16_t)(cmd6Status[2U]);
    functionGroupInfo[0U] = (uint16_t)(cmd6Status[3U] >> 16U);
    currentFunctionStatus = ((cmd6Status[3U] & 0xFFFFU) << 8U) | (cmd6Status[4U] >> 24U);

    for (i = 0; i < 6; i++) {
        SDH_MSG("functionGroupInfo[%d]=0x%x.\r\n", i, functionGroupInfo[i]);
    }

    SDH_MSG("currentFunctionStatus = 0x%x.\r\n", currentFunctionStatus);

    /* check if function is support */
    if (((functionGroupInfo[group] & (1 << function)) == 0U) ||
        ((currentFunctionStatus >> (group * 4U)) & 0xFU) != function) {
        return Status_SDH_SDIO_SwitchHighSpeedFail;
    }

    /* Check if card support high speed mode. */
    if (Status_Success != SD_SwitchFunction(SDH_SwitchSet, group, function, cmd6Status)) {
        return Status_SDH_SDIO_SwitchHighSpeedFail;
    }

    /* 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. */
    cmd6Status[3U] = SWAP_WORD_BYTE_SEQUENCE(cmd6Status[3U]);
    cmd6Status[4U] = SWAP_WORD_BYTE_SEQUENCE(cmd6Status[4U]);

    /* 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 = ((cmd6Status[3U] & 0xFFFFU) << 8U) | (cmd6Status[4U] >> 24U);
    SDH_MSG("currentFunctionStatus = 0x%x.\r\n", currentFunctionStatus);

    if (((currentFunctionStatus >> (group * 4U)) & 0xFU) != function) {
        return Status_SDH_SDIO_SwitchHighSpeedFail;
    }

    return errorstatus;
}

static status_t SD_SetBlockSize(uint32_t blockSize)
{
    status_t errorstatus = Status_Success;
    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    /*!< Set Block Size for SDSC Card,cmd16,no impact on SDHC card */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_SET_BLOCKLEN;
    SDH_CMD_Cfg_TypeInstance.argument = (uint32_t)blockSize;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        goto out;
    } else if (SDH_CMD_Cfg_TypeInstance.response[0] & SD_CSR_ERRORBITS) {
        errorstatus = Status_SDH_CmdResponseError;
        goto out;
    }

out:
    return errorstatus;
}

static status_t SDH_SDCardInit(uint32_t bus_wide, sd_card_t *card)
{
    status_t errorstatus = Status_Success;
    uint32_t applicationCommand41Argument = SD_OcrVdd33_34Flag | SD_OcrVdd32_33Flag;

    /* reset variables */
    card->flags = 0U;

    SDH_MSG("SD CARD GO IDEL...\r\n");
    errorstatus = SDH_GoIdle();

    if (errorstatus != SD_OK) {
        return Status_SDH_GoIdleFailed;
    }

    SDH_MSG("SD CARD GO IDEL END\r\n");

    for (uint16_t i = 0; i < 4; i++) {
        /* send CMD8 */
        errorstatus = SD_SendInterfaceCondition();
        /* check response */
        if (errorstatus == Status_Success) {
            /* SDHC or SDXC card */
            applicationCommand41Argument |= SD_OcrHostCapacitySupportFlag;
            card->flags |= SD_SupportSdhcFlag;
            break;
        } else {
            /* Try sending CMD8 again */
            SDH_MSG("Try sending CMD8 again:%d\r\n", i + 1);
            errorstatus = SDH_GoIdle();
            if (errorstatus != Status_Success) {
                return Status_SDH_GoIdleFailed;
            }
        }
    }

    /* Set card interface condition according to SDHC capability and card's supported interface condition. */
    errorstatus = SD_ApplicationSendOperationCondition(card, applicationCommand41Argument);

    if (errorstatus != Status_Success) {
        return Status_SDH_SendApplicationCommandFailed;
    }

    SDH_MSG("\r\nOCR is: 0x%02x.\r\n", card->ocr);
    SDH_MSG("\t SDHC supported[%s].\r\n\r\n", ((card->flags & SD_SupportHighCapacityFlag) ? "YES" : "NO"));

    errorstatus = SD_AllSendCid(card);

    if (errorstatus != Status_Success) {
        return Status_SDH_AllSendCidFailed;
    }

    SDH_MSG("\r\nCID is: 0x%02x-0x%02x-0x%02x-0x%02x.\r\n",
            card->rawCid[0], card->rawCid[1], card->rawCid[2], card->rawCid[3]);
    SDH_MSG("\t manufacturerID is: 0x%02x.\r\n", card->cid.manufacturerID);
    SDH_MSG("\t applicationID is: %c%c.\r\n", (card->cid.applicationID) >> 8, card->cid.applicationID);
    SDH_MSG("\t productName is: %c%c%c%c%c.\r\n",
            card->cid.productName[0], card->cid.productName[1], card->cid.productName[2], card->cid.productName[3], card->cid.productName[4]);
    SDH_MSG("\t manufacturerData is: 0x%02x.\r\n\r\n", card->cid.manufacturerData);

    errorstatus = SD_SendRca(card);

    if (errorstatus != Status_Success) {
        return Status_SDH_SendRelativeAddressFailed;
    }

    SDH_MSG("\r\nRCA is: 0x%02x.\r\n\r\n", card->relativeAddress);

    errorstatus = SD_SendCsd(card);

    if (errorstatus != Status_Success) {
        return Status_SDH_SendCsdFailed;
    }

    SDH_MSG("\r\nCSD is: 0x%02x-0x%02x-0x%02x-0x%02x.\r\n",
            card->rawCsd[0], card->rawCsd[1], card->rawCsd[2], card->rawCsd[3]);
    SDH_MSG("\t CSD Version is: %s .\r\n", card->csd.csdStructure ? "csd version 2.0" : "csd version 1.0");
    SDH_MSG("\t blockLen=%d, blockCounter=%d, CardSize is %d[MBytes].\r\n\r\n", card->blockSize, card->blockCount, (card->blockCount) >> 11);

    errorstatus = SD_SelectCard(card, ENABLE);

    if (errorstatus != Status_Success) {
        return Status_SDH_SelectCardFailed;
    }

    errorstatus = SD_SendScr(card);

    if (errorstatus != Status_Success) {
        return Status_SDH_SendScrFailed;
    }

    SDH_MSG("\r\nSCR is: 0x%x-0x%x.\r\n", card->rawScr[0], card->rawScr[1]);
    SDH_MSG("\t SD Spec Version is: [0x%02x]%s.\r\n", card->version,
            (card->version & SD_SpecificationVersion3_0) ? "V3.0" : ((card->version & SD_SpecificationVersion2_0) ? "V2.0" : ((card->version & SD_SpecificationVersion1_1) ? "V1.1" : "V1.0")));
    SDH_MSG("\t Erased bit is %d.\r\n", (card->scr.flags & SD_ScrDataStatusAfterErase));
    SDH_MSG("\t 4-line supported[%s].\r\n", ((card->flags & SD_Support4BitWidthFlag) ? "YES" : "NO"));
    SDH_MSG("\t SetBlockCountCmd supported[%s].\r\n", ((card->flags & SD_SupportSetBlockCountCmd) ? "YES" : "NO"));
    SDH_MSG("\t SDXC supported[%s].\r\n\r\n", ((card->flags & SD_SupportSdxcFlag) ? "YES" : "NO"));

    if (card->flags & SD_Support4BitWidthFlag) {
        errorstatus = SD_SetDataBusWidth(card, (SDH_Data_Bus_Width_Type)bus_wide);
    } else {
        errorstatus = SD_SetDataBusWidth(card, SDH_DATA_BUS_WIDTH_1BIT);
    }

    if (errorstatus != Status_Success) {
        return Status_SDH_SetDataBusWidthFailed;
    }

    errorstatus = SD_SendSsr(card);

    if (errorstatus != Status_Success) {
        return Status_SDH_SendSsrFailed;
    }

    SDH_MSG("\r\nSSR[0] is: 0x%x.\r\n", card->rawSsr[0]);
    SDH_MSG("\t Current is %d-line mode.\r\n\r\n", (card->rawSsr[0] & 0x80) ? 4 : 1);

    errorstatus = SD_SetBlockSize(SDH_DEFAULT_BLOCK_SIZE);

    if (errorstatus != Status_Success) {
        return Status_SDH_SetCardBlockSizeFailed;
    }

    //SD_SelectFunction(SDH_GroupTimingMode,SDH_TimingSDR25HighSpeedMode);

    return errorstatus;
}

/**
  * @brief  Initializes SD Card clock.
  * @retval SD status
  */
// status_t SDH_ClockSet(uint32_t clockInit, uint32_t clockSrc, uint32_t clockTransfer)
// {
//     sdhClockInit = clockInit;
//     sdhClockSrc = clockSrc;
//     sdhClockTransfer = clockTransfer;

//     return Status_Success;
// }

/**
  * @brief  Initializes the SD card device.
  * @retval SD status
  */
status_t SDH_Init(uint32_t bus_wide, sd_card_t *pOutCardInfo)
{
    pSDCardInfo = pOutCardInfo;

#if SDIO_SDCARD_INT_MODE
    SDH_INT_Init();
#endif

    /* reset SDH controller*/
    SDH_Reset();

    SDH_HostInit();

    if (pOutCardInfo == NULL) {
        return Status_InvalidArgument;
    } else {
        return SDH_SDCardInit(bus_wide, pOutCardInfo);
    }
}

/**
  * @brief  Allows to erase memory area specified for the given card.
  * @param  startaddr: the start address.
  * @param  endaddr: the end address.
  * @retval SD_Error: SD Card Error code.
  */
status_t SD_Erase(uint32_t startaddr, uint32_t endaddr)
{
    status_t errorstatus = Status_Success;
    uint8_t cardstate = 0;

    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    /* SDSC card uses byte unit address*/
    if (!(pSDCardInfo->flags & SD_SupportHighCapacityFlag)) {
        startaddr *= 512;
        endaddr *= 512;
    }

    /*!< Send CMD32 SD_ERASE_GRP_START with argument as addr  */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_SD_ERASE_GRP_START;
    SDH_CMD_Cfg_TypeInstance.argument = startaddr;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        goto out;
    } else if (SDH_CMD_Cfg_TypeInstance.response[0] & SD_CSR_ERRORBITS) {
        errorstatus = Status_SDH_CmdResponseError;
        goto out;
    }

    /*!< Send CMD33 SD_ERASE_GRP_END with argument as addr  */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_SD_ERASE_GRP_END;
    SDH_CMD_Cfg_TypeInstance.argument = endaddr;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        goto out;
    } else if (SDH_CMD_Cfg_TypeInstance.response[0] & SD_CSR_ERRORBITS) {
        errorstatus = Status_SDH_CmdResponseError;
        goto out;
    }

    /*!< Send CMD38 ERASE */
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_ERASE;
    SDH_CMD_Cfg_TypeInstance.argument = 0;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1B;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        goto out;
    } else if (SDH_CMD_Cfg_TypeInstance.response[0] & SD_CSR_ERRORBITS) {
        errorstatus = Status_SDH_CmdResponseError;
        goto out;
    }

    /*!< Wait till the card is in programming state */
    errorstatus = IsCardProgramming(&cardstate);

    while ((errorstatus == SD_OK) && ((SD_CARD_PROGRAMMING == cardstate) || (SD_CARD_RECEIVING == cardstate))) {
        errorstatus = IsCardProgramming(&cardstate);
    }

out:
    return errorstatus;
}

static status_t WaitInProgramming(void)
{
    uint8_t cardstate = 0;
    status_t errorstatus = Status_Success;
    //uint32_t maxdelay = 0;
    //maxdelay = 120000/(sdhClockSrc/sdhClockTransfer);

    //while(maxdelay--){}
    /*!< Wait till the card is in programming state */
    errorstatus = IsCardProgramming(&cardstate);

    while ((errorstatus == Status_Success) && ((SD_CARD_PROGRAMMING == cardstate) || (SD_CARD_RECEIVING == cardstate))) {
        errorstatus = IsCardProgramming(&cardstate);
    }

    return errorstatus;
}

/*check sd card state*/
static status_t IsCardProgramming(uint8_t *pstatus)
{
    status_t errorstatus = Status_Success;
    SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;

    /*cmd13 addressed card send its status*/
    SDH_CMD_Cfg_TypeInstance.index = SD_CMD_SEND_STATUS;
    SDH_CMD_Cfg_TypeInstance.argument = (uint32_t)(pSDCardInfo->relativeAddress) << 16;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;

    errorstatus = SDH_SendCardCommand(&SDH_CMD_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        goto out;
    } else if (SDH_CMD_Cfg_TypeInstance.response[0] & SD_CSR_ERRORBITS) {
        errorstatus = Status_SDH_CmdResponseError;
        goto out;
    }

    /*!< Find out card status */
    *pstatus = (uint8_t)((SDH_CMD_Cfg_TypeInstance.response[0] >> 9) & 0x0000000F); //status[12:9] :cardstate

out:
    return (errorstatus);
}

/* Transmit data in non-blocking mode, Only the sending status of commands is checked */
static status_t SDH_CardTransferNonBlocking(SDH_DMA_Cfg_Type *dmaCfg, SDH_Trans_Cfg_Type *transfer)
{
    status_t errorstatus = Status_Success;
    SDH_Stat_Type stat = SDH_STAT_SUCCESS;

    stat = SDH_TransferNonBlocking(dmaCfg, transfer);

    if (stat != SDH_STAT_SUCCESS) {
        return Status_SDH_TransferFailed;
    }

    /* Flush ADMA2-descriptor-table to RAM, Otherwise ADMA2 will fail */
    bflb_l1c_dcache_clean_range((void *)(dmaCfg->admaEntries), dmaCfg->maxEntries * sizeof(SDH_ADMA2_Desc_Type));

    errorstatus = SDH_SendCardCommand(transfer->cmdCfg);

    if (errorstatus != Status_Success) {
        return errorstatus;
    } else if (transfer->cmdCfg->response[0] & SD_CSR_ERRORBITS) {
        return Status_SDH_CmdResponseError;
    }

    return errorstatus;
}

status_t SDH_ReadMultiBlocks(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks)
{
    status_t errorstatus = Status_Success;
    SD_Error sd_status;
    uint32_t time_node;

    static SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;
    static SDH_Data_Cfg_Type SDH_Data_Cfg_TypeInstance;
    static SDH_Trans_Cfg_Type SDH_Trans_Cfg_TypeInstance = { &SDH_Data_Cfg_TypeInstance, &SDH_CMD_Cfg_TypeInstance };

#if defined(BL808) || defined(BL606P)
    /* BL808/BL606 supports only 8-byte aligned addresses */
    if ((uintptr_t)readbuff % 8 != 0) {
        return Status_InvalidArgument;
    }
#endif

    /* SDSC card uses byte unit address*/
    if (!(pSDCardInfo->flags & SD_SupportHighCapacityFlag)) {
        BlockSize = 512;
        ReadAddr *= 512;
    }

    SDH_MSG("\r\nRead-->IN, block num: %d, block addr: %d, read buffer addr: 0x%p.\r\n", NumberOfBlocks, ReadAddr, readbuff);

    /*set cmd parameter for READ_MULTIPLE_BLOCK*/
    if (NumberOfBlocks <= 1) {
        SDH_CMD_Cfg_TypeInstance.index = SD_CMD_READ_SINGLE_BLOCK;
    } else {
        SDH_CMD_Cfg_TypeInstance.index = SD_CMD_READ_MULT_BLOCK;
    }

    SDH_CMD_Cfg_TypeInstance.argument = (uint32_t)ReadAddr;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_DATA_PRESENT;

    /*set data parameter for READ_MULTIPLE_BLOCK*/
    if (NumberOfBlocks <= 1) {
        SDH_Data_Cfg_TypeInstance.enableAutoCommand12 = DISABLE;
        SDH_Data_Cfg_TypeInstance.enableAutoCommand23 = DISABLE;
    } else {
        if (pSDCardInfo->flags & SD_SupportSetBlockCountCmd) {
            SDH_Data_Cfg_TypeInstance.enableAutoCommand23 = ENABLE;
            SDH_Data_Cfg_TypeInstance.enableAutoCommand12 = DISABLE;
        } else {
            SDH_Data_Cfg_TypeInstance.enableAutoCommand23 = DISABLE;
            SDH_Data_Cfg_TypeInstance.enableAutoCommand12 = ENABLE;
        }
    }

    SDH_Data_Cfg_TypeInstance.enableIgnoreError = DISABLE;
    SDH_Data_Cfg_TypeInstance.dataType = SDH_TRANS_DATA_NORMAL;
    SDH_Data_Cfg_TypeInstance.blockSize = BlockSize;
    SDH_Data_Cfg_TypeInstance.blockCount = NumberOfBlocks;
    SDH_Data_Cfg_TypeInstance.rxDataLen = 0;
    SDH_Data_Cfg_TypeInstance.rxData = (uint32_t *)readbuff;
    SDH_Data_Cfg_TypeInstance.txDataLen = 0;
    SDH_Data_Cfg_TypeInstance.txData = NULL;
    SDH_Data_Cfg_TypeInstance.txDataLen = 0;
    SDH_Data_Cfg_TypeInstance.txData = NULL;

    /*set parameters for SDH_DMA_Cfg_TypeInstance*/
    SDH_DMA_Cfg_TypeInstance.dmaMode = SDH_DMA_MODE_ADMA2;
    SDH_DMA_Cfg_TypeInstance.burstSize = SDH_BURST_SIZE_128_BYTES;
    SDH_DMA_Cfg_TypeInstance.fifoThreshold = SDH_BURST_SIZE_128_BYTES;
    SDH_DMA_Cfg_TypeInstance.admaEntries = (uint32_t *)adma2Entries;
    SDH_DMA_Cfg_TypeInstance.maxEntries = sizeof(adma2Entries) / sizeof(adma2Entries[0]);

    errorstatus = SDH_CardTransferNonBlocking(&SDH_DMA_Cfg_TypeInstance, &SDH_Trans_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        SDH_MSG("SDH Transfer err:%d\r\n", errorstatus);
        goto out;
    }

    time_node = (uint32_t)bflb_mtimer_get_time_ms();

#if SDIO_SDCARD_INT_MODE

    SDH_DataWaitStatus = SD_WAITING;
    SDH_EnableIntSource(SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);

    /*wait for Xfer status. might pending here in multi-task OS*/
    while (SDH_DataWaitStatus == SD_WAITING) {
        if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("SDH read data timeout: %ld", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            SDH_DisableIntSource(SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);
            return Status_Timeout;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }
    sd_status = SDH_DataWaitStatus;
    SDH_DisableIntSource(SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);

#else

    uint32_t intFlag;
    while (1) {
        intFlag = SDH_GetIntStatus();
        if (intFlag & SDH_INT_DATA_ERRORS || intFlag & SDH_INT_DMA_ERROR || intFlag & SDH_INT_AUTO_CMD12_ERROR) {
            sd_status = SD_CMD_ERROR;
            break;

        } else if (intFlag & SDH_INT_DATA_COMPLETED) {
            sd_status = SD_OK;
            break;

        } else if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("SDH read data timeout: %ld ms\r\n", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            return Status_Timeout;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }
    SDH_ClearIntStatus(intFlag);

#endif

    if (sd_status != SD_OK) {
        errorstatus = Status_SDH_TransferFailed;
        goto out;
    }

    bflb_l1c_dcache_invalidate_range((void *)(readbuff), BlockSize * NumberOfBlocks);

    SDH_MSG("Read data used time: %ld ms\r\n", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
    SDH_MSG("Read-->OUT, block num: %d, block addr: %d, read buffer addr: 0x%p.\r\n", NumberOfBlocks, ReadAddr, readbuff);

out:
    return (errorstatus);
}

status_t SDH_WriteMultiBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks)
{
    status_t errorstatus = Status_Success;
    SD_Error sd_status;
    uint32_t time_node;

    static SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;
    static SDH_Data_Cfg_Type SDH_Data_Cfg_TypeInstance;
    static SDH_Trans_Cfg_Type SDH_Trans_Cfg_TypeInstance = { &SDH_Data_Cfg_TypeInstance, &SDH_CMD_Cfg_TypeInstance };

#if defined(BL808) || defined(BL606P)
    /* BL808/BL606 supports only 8-byte aligned addresses */
    if ((uintptr_t)writebuff % 8 != 0) {
        return Status_InvalidArgument;
    }
#endif

    if ((pSDCardInfo != NULL) && (!(pSDCardInfo->flags & SD_SupportHighCapacityFlag))) {
        /* It's SDCS card,SDSC card uses byte unit address*/
        BlockSize = 512;
        WriteAddr *= 512;
    }

    SDH_MSG("\r\nWrite-->IN, block num: %d, block addr: %d, read buffer addr: 0x%p.\r\n", NumberOfBlocks, WriteAddr, writebuff);

    /*set cmd parameter for SD_CMD_WRITE_MULT_BLOCK*/
    if (NumberOfBlocks <= 1) {
        SDH_CMD_Cfg_TypeInstance.index = SD_CMD_WRITE_SINGLE_BLOCK;
    } else {
        SDH_CMD_Cfg_TypeInstance.index = SD_CMD_WRITE_MULT_BLOCK;
    }

    SDH_CMD_Cfg_TypeInstance.argument = (uint32_t)WriteAddr;
    SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
    SDH_CMD_Cfg_TypeInstance.respType = SDH_RESP_R1;
    SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_DATA_PRESENT;

    /*set data parameter for WRITE_MULTIPLE_BLOCK*/
    if (NumberOfBlocks <= 1) {
        SDH_Data_Cfg_TypeInstance.enableAutoCommand12 = DISABLE;
        SDH_Data_Cfg_TypeInstance.enableAutoCommand23 = DISABLE;
    } else {
        if (pSDCardInfo->flags & SD_SupportSetBlockCountCmd) {
            SDH_Data_Cfg_TypeInstance.enableAutoCommand23 = ENABLE;
            SDH_Data_Cfg_TypeInstance.enableAutoCommand12 = DISABLE;
        } else {
            SDH_Data_Cfg_TypeInstance.enableAutoCommand23 = DISABLE;
            SDH_Data_Cfg_TypeInstance.enableAutoCommand12 = ENABLE;
        }
    }

    SDH_Data_Cfg_TypeInstance.enableIgnoreError = DISABLE;
    SDH_Data_Cfg_TypeInstance.dataType = SDH_TRANS_DATA_NORMAL;
    SDH_Data_Cfg_TypeInstance.blockSize = BlockSize;
    SDH_Data_Cfg_TypeInstance.blockCount = NumberOfBlocks;
    SDH_Data_Cfg_TypeInstance.rxDataLen = 0;
    SDH_Data_Cfg_TypeInstance.rxData = NULL;
    SDH_Data_Cfg_TypeInstance.txDataLen = 0;
    SDH_Data_Cfg_TypeInstance.txData = (uint32_t *)writebuff;
    /*set parameters for SDH_DMA_Cfg_TypeInstance*/
    SDH_DMA_Cfg_TypeInstance.dmaMode = SDH_DMA_MODE_ADMA2;
    SDH_DMA_Cfg_TypeInstance.burstSize = SDH_BURST_SIZE_128_BYTES;
    SDH_DMA_Cfg_TypeInstance.fifoThreshold = SDH_FIFO_THRESHOLD_256_BYTES;
    SDH_DMA_Cfg_TypeInstance.admaEntries = (uint32_t *)adma2Entries;
    SDH_DMA_Cfg_TypeInstance.maxEntries = sizeof(adma2Entries) / sizeof(adma2Entries[0]);

    bflb_l1c_dcache_clean_range((void *)(writebuff), BlockSize * NumberOfBlocks);

    errorstatus = SDH_CardTransferNonBlocking(&SDH_DMA_Cfg_TypeInstance, &SDH_Trans_Cfg_TypeInstance);

    if (errorstatus != Status_Success) {
        SDH_MSG("SDH Transfer err:%d\r\n", errorstatus);
        return errorstatus;
    }

    time_node = (uint32_t)bflb_mtimer_get_time_ms();

#if SDIO_SDCARD_INT_MODE

    SDH_DataWaitStatus = SD_WAITING;
    SDH_EnableIntSource(SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);

    /*wait for Xfer status. might pending here in multi-task OS*/
    while (SDH_DataWaitStatus == SD_WAITING) {
        if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("SDH write data timeout: %ld ms\r\n", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            SDH_DisableIntSource(SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);
            errorstatus = Status_Timeout;
            goto out;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }

    SDH_DisableIntSource(SDH_INT_DATA_COMPLETED | SDH_INT_DATA_ERRORS | SDH_INT_DMA_ERROR | SDH_INT_AUTO_CMD12_ERROR);
    sd_status = SDH_DataWaitStatus;

#else

    uint32_t intFlag;
    while (1) {
        intFlag = SDH_GetIntStatus();
        if (intFlag & SDH_INT_DATA_ERRORS || intFlag & SDH_INT_DMA_ERROR || intFlag & SDH_INT_AUTO_CMD12_ERROR) {
            sd_status = SD_DataCfg_ERROR;
            break;

        } else if (intFlag & SDH_INT_DATA_COMPLETED) {
            sd_status = SD_OK;
            break;

        } else if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS) {
            SDH_MSG("SDH write data timeout: %ld ms\r\n", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
            return Status_Timeout;
        }
        BL_DRV_DUMMY;
        BL_DRV_DUMMY;
    }
    SDH_ClearIntStatus(intFlag);

#endif

    if (sd_status != SD_OK) {
        errorstatus = Status_SDH_TransferFailed;
        goto out;
    } else {
        errorstatus = WaitInProgramming();
    }

    SDH_MSG("Write data used time: %ld ms\r\n", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
    SDH_MSG("Write-->OUT, block num: %d, block addr: %d, read buffer addr: 0x%p.\r\n", NumberOfBlocks, WriteAddr, writebuff);

out:
    return (errorstatus);
}

#endif

找到了一个关于sdcard操作的类

回复

使用道具 举报

爱笑 | 2024-1-19 14:47:53 | 显示全部楼层
我来问问小泽
用心做好保姆工作
回复 支持 反对

使用道具 举报

WT_0213 | 2024-1-19 15:01:02 | 显示全部楼层
好的,辛苦了
回复 支持 反对

使用道具 举报

Ai-Thinker小泽 | 2024-1-19 15:08:21 | 显示全部楼层
SD卡可以看D200的demo,里面有用到文件系统,SD卡读写这些。占的脚位是SDIO那几个脚位,基本就是CAM那些了。
回复 支持 反对

使用道具 举报

曹县 | 2024-1-19 15:08:35 | 显示全部楼层
回复

使用道具 举报

WT_0213 | 2024-1-19 15:19:47 | 显示全部楼层
Ai-Thinker小泽 发表于 2024-1-19 15:08
SD卡可以看D200的demo,里面有用到文件系统,SD卡读写这些。占的脚位是SDIO那几个脚位,基本就是CAM那些了 ...

大佬,R1和R2直接焊接卡槽就可以使用吗。咱们调试的时候有在 AiPi-Eyes-R1或AiPi-Eyes-R2上面用过 TF卡槽吗。 最好是有一些例子。目前找到了,sdcard 相关的h头文件和C文件。全局搜索了以下,好像没有找到引用。 懵懵的。如果不太占用咱们时间的话,辛苦咱们大概发一下 相关引用代码。比我这里梳理可能稍微快捷一些。我这里也看一下。 感谢。
回复 支持 反对

使用道具 举报

WT_0213 | 2024-1-19 15:20:53 | 显示全部楼层
回复 支持 反对

使用道具 举报

WT_0213 | 2024-1-19 15:29:00 | 显示全部楼层
Ai-Thinker小泽 发表于 2024-1-19 15:08
SD卡可以看D200的demo,里面有用到文件系统,SD卡读写这些。占的脚位是SDIO那几个脚位,基本就是CAM那些了 ...

找到了,感谢
回复 支持 反对

使用道具 举报

WT_0213 | 2024-1-20 13:32:05 | 显示全部楼层
回复

使用道具 举报

axkkj | 2024-4-24 10:24:44 来自手机 | 显示全部楼层
😀
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则