/**
* @file         memory_card.c
* @brief        对sd卡或emm卡驱动
* @details      对sd卡或emm卡驱动
* @author       涂龙
* @date         2022-01-27 09:04
* @version      V0.0
* @copyright    Copyright (c) 2017-2022  SpaceTouch Inc.
*/
#ifndef __MEMORY_CARD_H__
#define __MEMORY_CARD_H__

#include "platform.h"



/*
 * 错误码组成：0-15bit为sdc本身状态寄存器的比特信息，16-23bit为事件信息，24-31bit为命令事件信息
 * */
typedef enum
{
    ERR_CARD_NONE                            = 0,
    //具体行为
    ERR_CARD_SET_CLOCK_FAIL                  = 0x1UL << 16, ///<时钟配置失败
    ERR_CARD_HARDWARE_ERROR                  = 0x2UL << 16, ///<硬件错误
    ERR_CARD_NOT_CARD                        = 0x3UL << 16, ///<没有卡
    ERR_CARD_INVALID_CARD                    = 0x4UL << 16, ///<无效卡
    ERR_CARD_READ_CID_FAIL                   = 0x5UL << 16, ///<读卡cid寄存器失败（cmd2）
    ERR_CARD_ASK_RELATIVE_ADDR_FAIL          = 0x6UL << 16, ///<读卡地址失败（cmd3）
    ERR_CARD_READ_CSD_FAIL                   = 0x7UL << 16, ///<读卡csd寄存器失败（cmd9）
    ERR_CARD_TOGGLES_CARD_STATES_FAIL        = 0x8UL << 16, ///<翻转卡状态失败（cmd7）
    ERR_CARD_SET_BUS_WIDTH_FAIL              = 0x9UL << 16, ///<设置卡bus宽度失败（cmd55 或acmd6）
    ERR_CARD_READ_RCA_FAIL                   = 0xaUL << 16, ///<读卡RCA寄存器失败（cmd13）
    ERR_CARD_READ_DATA_FAIL                  = 0xbUL << 16, ///<读卡数据失败（cmd18）
    ERR_CARD_WRITE_DATA_FAIL                 = 0xcUL << 16, ///<写卡数据失败（cmd25）
    ERR_CARD_ERASE_DATA_FAIL                 = 0xdUL << 16, ///<擦卡区域失败（cmd32,cmd33,cmd38）
    ERR_CARD_SET_BLOCKLEN_FAIL               = 0xeUL << 16, ///<设置卡block长度失败（cmd16）
    ERR_CARD_READ_EXTCSD_FAIL                = 0xfUL << 16, ///<读取卡ext_csd寄存器失败（cmd8）

    ERR_CARD_READ_CARD_READY_TIMEOUT         = 0x10UL << 16, ///<发送ACMD41等待卡准备超时
    ERR_CARD_SET_CLOCK_CARD_TIMEOUT          = 0x11UL << 16, ///<设置时钟前等待SDC空闲超时
    ERR_CARD_READ_CARD_DATA_TIMEOUT          = 0x12UL << 16, ///<读数前等待SDC空闲超时
    ERR_CARD_READ_DMA_IDLE_TIMEOUT           = 0x13UL << 16, ///<读数DMA使用前等待空闲超时
    ERR_CARD_READ_ACD_TIMEOUT                = 0x14UL << 16, ///<读数等待自动命令完成超时(cmd12)
    ERR_CARD_WRITE_CARD_DATA_TIMEOUT         = 0x15UL << 16, ///<写数前等待SDC空闲超时
    ERR_CARD_WRITE_OVER_CARD_DATA_TIMEOUT    = 0x16UL << 16, ///<写数后等待SDC空闲超时
    ERR_CARD_WRITE_DMA_IDLE_TIMEOUT          = 0x17UL << 16, ///<写数DMA使用前等待空闲超时
    ERR_CARD_WRITE_ACD_TIMEOUT               = 0x18UL << 16, ///<写数等待自动命令完成超时(硬件自动cmd12)
    ERR_CARD_WRITE_DMA_OVER_TIMEOUT          = 0x1aUL << 16, ///<写数DMA使用超时（它的超时时长与其他不一致）
    ERR_CARD_ERASE_CARD_DATA_TIMEOUT         = 0x1bUL << 16, ///<擦除区域数据前等待SDC空闲超时
    ERR_CARD_ERASE_OVER_CARD_DATA_TIMEOUT    = 0x1cUL << 16, ///<擦除区域数据完成等待SDC空闲超时
    ERR_CARD_FIFO_REST_TIMEOUT               = 0x1dUL << 16, ///<复位SDC fifo等待超时
    ERR_CARD_RFAIL_INIT_FAIL                 = 0x1eUL << 16, ///<读失败后再初始化操作卡失败
    ERR_CARD_WFAIL_INIT_FAIL                 = 0x1fUL << 16, ///<写失败后再初始化操作卡失败


    ERR_CARD_SEND_STOP_TIMEOUT               = 0x3fUL << 16, ///<发送stop（cmd12）超时
    ERR_CARD_READ_DMA_OVER_TIMEOUT           = 0x40UL << 16, ///<读数DMA使用超时（它的超时时长与其他不一样）

    ERR_CARD_UHS1_SUPPORTS_ONLY_4BIT         = 0x41UL << 16, ///<配置sd卡进入uhs-1,却用了非四线
    ERR_CARD_SDSC_NOT_SUPPORTS_UHS1          = 0x42UL << 16, ///<SDSC卡没有uhs1 bus 模式
    ERR_CARD_SET_1P8V_CMD_WAITE_TIMEOUT      = 0x43UL << 16, ///<切换1.8V前，等待上一命令完成超时
    ERR_CARD_SET_1P8V_CMD_SEND_TIMEOUT       = 0x44UL << 16, ///<切换1.8V时，发送命令超时
    ERR_CARD_SET_1P8V_IO_CHANGE_FAIL         = 0x45UL << 16, ///<切换1.8V后，io状态变化不对


    //命令信息
    ERR_CARD_SEND_CMD_WAITE_LAST_TIMEOUT     = 0x1UL << 24, ///<SDC发送命令前等待上一命令完成超时
    ERR_CARD_SEND_CMD_WAITE_STATE_TIMEOUT    = 0x2UL << 24, ///<SDC发送命令后等待命令完成状态超时

    //状态寄存器信息
    ERR_CARD_RESPONSE_ERROR                  = 1UL << 1UL,
    ERR_CARD_RESPONSE_CRC_ERROR              = 1UL << 6UL,
    ERR_CARD_DATA_CRC_ERROR                  = 1UL << 7UL,
    ERR_CARD_RESPONSE_TIMEOUT                = 1UL << 8UL,
    ERR_CARD_DATA_READ_TIMEOUT               = 1UL << 9UL,
    ERR_CARD_FIFO_ERROR                      = 1UL << 11UL,
    ERR_CARD_HARDWARE_LOCKED_WTRITE_ERROR    = 1UL << 12UL,
    ERR_CARD_START_BIT_ERROR                 = 1UL << 13UL,
    ERR_CARD_END_BIT_ERROR                   = 1UL << 15UL,

} MEMORY_CARD_ErrorCodeEnum;



typedef struct
{
    __IO    uint32_t    CTRL;           //offset:0x00
    __IO    uint32_t    PWREN;          //offset:0x04
    __IO    uint32_t    CLKDIV;         //offset:0x08
    __IO    uint32_t    CLKSRC;         //offset:0x0C
    __IO    uint32_t    CLKENA;         //offset:0x10
    __IO    uint32_t    TMOUT;          //offset:0x14
    __IO    uint32_t    CTYPE;          //offset:0x18
    __IO    uint32_t    BLKSIZ;         //offset:0x1C
    __IO    uint32_t    BYTCNT;         //offset:0x20
    __IO    uint32_t    INTMASK;        //offset:0x24
    __IO    uint32_t    CMDARG;         //offset:0x28
    __IO    uint32_t    CMD;            //offset:0x2C
    __IO    uint32_t    RESP0;          //offset:0x30
    __IO    uint32_t    RESP1;          //offset:0x34
    __IO    uint32_t    RESP2;          //offset:0x38
    __IO    uint32_t    RESP3;          //offset:0x3C
    __IO    uint32_t    MINTSTS;        //offset:0x40
    __IO    uint32_t    RINTSTS;        //offset:0x44
    __IO    uint32_t    STATUS;         //offset:0x48
    __IO    uint32_t    FIFOTH;         //offset:0x4C
    __IO    uint32_t    CDETECT;        //offset:0x50
    __IO    uint32_t    WRTPRT;         //offset:0x54
    __IO    uint32_t    GPIO;           //offset:0x58
    __IO    uint32_t    TCBCNT;         //offset:0x5C
    __IO    uint32_t    TBBCNT;         //offset:0x60
    __IO    uint32_t    DEBNCE;         //offset:0x64
    __IO    uint32_t    USRID;          //offset:0x68
    __IO    uint32_t    VERID;          //offset:0x6C
    __IO    uint32_t    HCON;           //offset:0x70
    __IO    uint32_t    UHSREG;         //offset:0x74
    __IO    uint32_t    RSTN;           //offset:0x78
    __IO    uint32_t    RESERVED0;      //offset:0x7C
    __IO    uint32_t    BMOD;           //offset:0x80
    __IO    uint32_t    PLDMND;         //offset:0x84
    __IO    uint32_t    DBADDR;         //offset:0x88
    __IO    uint32_t    IDSTS;          //offset:0x8C
    __IO    uint32_t    IDINTEN;        //offset:0x90
    __IO    uint32_t    DSCADDR;        //offset:0x94
    __IO    uint32_t    BUFADDR;        //offset:0x98
    __IO    uint32_t    RESERVED1[25];  //offset:0x9C~0xFF
    __IO    uint32_t    CARDTHRCTL;     //offset:0x100
    __IO    uint32_t    BACKENDPOWER;   //offset:0x104
    __IO    uint32_t    UHSREGEXT;      //offset:0x108
    __IO    uint32_t    EMMCDDRREG;     //offset:0x10C
    __IO    uint32_t    ENABLESHIFT;    //offset:0x110
    __IO    uint32_t    RESERVED2[59];  //offset:0x114~0x1FF
    __IO    uint32_t    DATA;           //offset:0x200

} DEV_SDC_RegDef;


#define CARD_CSD_LEN 16
#define CARD_CID_LEN 16
#define CARD_MMC_EXTCSD_LEN 512UL

typedef struct
{
    /*
     * ！！！注意！！！标注“需要初始值”的成员需要在sd卡初始化之前完成初值赋值
     * */
    /*使用io*/
    uint8_t clk_gpio;//需要初始值
    uint8_t cmd_gpio;//需要初始值
    uint8_t d0_gpio;//需要初始值
    uint8_t d1_gpio;//需要初始值
    uint8_t d2_gpio;//需要初始值
    uint8_t d3_gpio;//需要初始值
    uint64_t mcycle_ms_freq;////需要初始值  mcycle每毫秒的计数值 =cpu的时钟的千分频


    uint32_t relative_addr;//卡地址
    uint8_t capacity;//卡容量标志
    uint8_t csd[CARD_CSD_LEN];//csd寄存器内容
    uint8_t cid[CARD_CID_LEN];//cid寄存器内容

    uint8_t s18r;///< 需要初始值  卡是否走1.8v电压 0：3.3 1：1.8

    //mmc 特有
    uint8_t ext_csd[CARD_MMC_EXTCSD_LEN];//ext_csd寄存器内容

    //sd卡特有
    /* brom 不支持功能选择
     若不想改变原始值，swicth_function成员应填入下面四值
    SDC_CARD_SF_ACCESS,
    SDC_CARD_SF_COMMAND,
    SDC_CARD_SF_DRIVER,
    SDC_CARD_SF_POWER,
    */
    uint32_t swicth_function[4];///<需要初始值 SDC_CardSwitchFuncEnum 选择功能
    uint16_t support_function[4];///<通过查询支持的功能 第几bit置位表示第几功能支持

    uint8_t card_type;//卡类型


} MEMORY_CARD_Info;

extern MEMORY_CARD_Info mem_card_info;

//使用同一个通道需要每次读写前都重新配置dma
//#define MEMORY_CARD_RX_DMA_CHANNEL 5//7
//#define MEMORY_CARD_TX_DMA_CHANNEL 6


void hal_memory_card_read_dma_init(uint32_t dma_ch);
void hal_memory_card_write_dma_init(uint32_t dma_ch);

uint32_t hal_memory_card_clock(uint32_t div, uint64_t mcycle_ms_freq);
uint32_t hal_memory_card_send_cmd(uint32_t cmd, uint32_t arg, uint32_t *response, uint64_t mcycle_ms_freq);
uint32_t hal_memory_card_init(uint32_t bus_width, uint32_t clk, MEMORY_CARD_Info *card_info);
uint32_t hal_memory_card_send_stop(uint64_t mcycle_ms_freq);
uint32_t hal_memory_card_read(uint8_t *buffer, uint32_t card_addr, uint32_t len, uint32_t dma_ch, MEMORY_CARD_Info *card_info);
uint32_t hal_memory_card_write(uint8_t *buffer, uint32_t card_addr, uint32_t len, uint32_t dma_ch, MEMORY_CARD_Info *card_info);

void hal_memory_card_get_csd(uint8_t *csd_value);
void  hal_memory_card_get_cid(uint8_t *cid_value);
uint32_t hal_memory_card_get_cpu_clock(void);
uint8_t hal_memory_card_get_capacity();


#endif /* SRC_MEMORY_CARD_H_ */
