/**
* @file         sd_card.h
* @brief        spv40 sdc控制器对sd卡的驱动
* @details      包含sdsc sdhc sdxc的初始化
*               通过dma对sd的读写
*               sd卡的一些寄存器的信息读取
* @author       涂龙
* @date         2022-07-06 11:01
* @version      V0.4a
* @copyright    Copyright (c) 2017-2022  SpaceTouch Inc.
* +v0.1
*   添加错误码
*   添加等待超时
*   添加debug打印
*   修改函数名
*  +v0.1a
*   将等待超时由mtime的中断方式修改为mtime的查询方式
*  +v0.2
*   将函数需要全局变量经量修改为参数需求
*  +v0.2a
*   将mtime作为超时检测的机制改为mcycle
*  +v0.3a
*   sdc模块根据读写的长度，使用单块或多块读写命令
*   使用misra规则，修改代码风格
*  +v0.3b
*   为了适应emmc模块的添加，修改代码封装
*  +v0.4a
*   添加sdc写函数完成后，检测DO数据线GPIO上升沿中断，辅助检测写忙。将等待忙时间从写任务中释放
*/
#ifndef __SD_CARD_H__
#define __SD_CARD_H__

#include "../../../../sp2cw3/sp2cw3.h"
#include "core_v5.h"
#include "hal_memory_card.h"
//SDC 使用I/O脚
#define DEV_SDC_GPIO_CLK DEV_SDC_GPIO_CLK_
#define DEV_SDC_GPIO_CMD DEV_SDC_GPIO_CMD_
#define DEV_SDC_GPIO_D0  DEV_SDC_GPIO_D0_
#define DEV_SDC_GPIO_D1  DEV_SDC_GPIO_D1_
#define DEV_SDC_GPIO_D2  DEV_SDC_GPIO_D2_
#define DEV_SDC_GPIO_D3  DEV_SDC_GPIO_D3_


//打印提示信息宏开关
#define DEV_SDCARD_DEBUG            0

//超时检测宏开关
#define DEV_SDC_TIME_OUT_CHECK      1
//当熟读写错误的重新重复次数
#define DEV_SDC_RW_MAX_TIMES        3
//sdc超时时长设置
//500ms的原因，看手册《physical layer simplified specification v8.00》
//4.6.2 read write and erase timeout conditions
#define DEV_SDC_TIME_OUT_TIME       500UL//ms
//sdc dma超时时长设置
#define DEV_SDC_DMA_TIME_OUT_TIME   10000UL//ms
//sdc模块工作时钟
#define DEV_SDC_CLOCK_HZ 24000000UL
//sdc写数据的GPIO的忙检测使能（通过中断加邮箱的方式）
#define DEV_SDC_WDATA_BUSY_GPIOCHECK 1

#define SD_CMD(n)   (n)
#define SD_ACMD(n)  (n)

#define SD_SEND_IF_COND SD_CMD(8)


/** sdc reg bit fild define */
#define DEV_SDC_CTRL_ENABLE_OD_PULLUP               (1UL << 24)
#define DEV_SDC_CTRL_CARD_VOLTAGE_B(n)              (((n) & 0xfUL) << 20UL)
#define DEV_SDC_CTRL_CARD_VOLTAGE_B_MASK            (0xfUL << 20)
#define DEV_SDC_CTRL_CARD_VOLTAGE_A(n)              (((n) & 0xfUL) << 16UL)
#define DEV_SDC_CTRL_CARD_VOLTAGE_A_MASK            (0xfUL << 16UL)
#define DEV_SDC_CTRL_CEATA_DEV_INT_STS              (1UL << 11UL)
#define DEV_SDC_CTRL_SEND_AUTO_STOP_CCSD            (1UL << 10UL)
#define DEV_SDC_CTRL_SEND_CCSD                      (1UL << 9UL)
#define DEV_SDC_CTRL_ABORT_READ_DATA                (1UL << 8UL)
#define DEV_SDC_CTRL_SEND_IRQ_RESPONSE              (1UL << 7UL)
#define DEV_SDC_CTRL_READ_WAIT                      (1UL << 6UL)
#define DEV_SDC_CTRL_DMA_ENABLE                     (1UL << 5UL)
#define DEV_SDC_CTRL_INT_ENABLE                     (1UL << 4UL)
#define DEV_SDC_CTRL_DMA_RESET                      (1UL << 2UL)
#define DEV_SDC_CTRL_FIFO_RESET                     (1UL << 1UL)
#define DEV_SDC_CTRL_CONTROLLER_RESET               (1UL << 0UL)

#define DEV_SDC_CMD_START_CMD                       (1UL << 31UL)
#define DEV_SDC_CMD_USE_HOLD_REG                    (1UL << 29UL)
#define DEV_SDC_CMD_VOLT_SWITCH                     (1UL << 28UL)
#define DEV_SDC_CMD_BOOT_MODE                       (1UL << 27UL)
#define DEV_SDC_CMD_DISABLE_BOOT                    (1UL << 26UL)
#define DEV_SDC_CMD_EXPECT_BOOT_ACK                 (1UL << 25UL)
#define DEV_SDC_CMD_ENABLE_BOOT                     (1UL << 24UL)
#define DEV_SDC_CMD_CCS_EXPECTED                    (1UL << 23UL)
#define DEV_SDC_CMD_READ_CEATA_DEVICE               (1UL << 22UL)
#define DEV_SDC_CMD_UPDATE_CLOCK_REGISTERS_ONLY     (1UL << 21UL)
#define DEV_SDC_CMD_CARD_NUMBER(n)                  (((n) & 0x1fUL) << 16UL)
#define DEV_SDC_CMD_SEND_INITIALIZATION             (1UL << 15UL)
#define DEV_SDC_CMD_STOP_ABORT_CMD                  (1UL << 14UL)
#define DEV_SDC_CMD_WAIT_PRVDATA_COMPLETE           (1UL << 13UL)
#define DEV_SDC_CMD_SEND_AUTO_STOP                  (1UL << 12UL)
#define DEV_SDC_CMD_TRANSFER_MODE                   (1UL << 11UL)
#define DEV_SDC_CMD_READ_WRITE                      (1UL << 10UL)
#define DEV_SDC_CMD_DATA_EXPECTED                   (1UL << 9UL)
#define DEV_SDC_CMD_CHECK_RESPONSE_CRC              (1UL << 8UL)
#define DEV_SDC_CMD_RESPONSE_LENGTH                 (1UL << 7UL)
#define DEV_SDC_CMD_RESPONSE_EXPECT                 (1UL << 6UL)
#define DEV_SDC_CMD_CMD_INDEX(n)                    (((n) & 0x3fUL) << 0)

#define DEV_SDC_RINTSTS_EBE                         (1UL << 15UL)
#define DEV_SDC_RINTSTS_ACD                         (1UL << 14UL)
#define DEV_SDC_RINTSTS_SBE_BCI                     (1UL << 13UL)
#define DEV_SDC_RINTSTS_HLE                         (1UL << 12UL)
#define DEV_SDC_RINTSTS_FRUN                        (1UL << 11UL)
#define DEV_SDC_RINTSTS_HTO                         (1UL << 10UL)
#define DEV_SDC_RINTSTS_VOLV_SWITCH                 (1UL << 10UL)
#define DEV_SDC_RINTSTS_DRTO_BDS                    (1UL << 9UL)
#define DEV_SDC_RINTSTS_RTO_BAR                     (1UL << 8UL)
#define DEV_SDC_RINTSTS_DCRC                        (1UL << 7UL)
#define DEV_SDC_RINTSTS_RCRC                        (1UL << 6UL)
#define DEV_SDC_RINTSTS_RXDR                        (1UL << 5UL)
#define DEV_SDC_RINTSTS_TXDR                        (1UL << 4UL)
#define DEV_SDC_RINTSTS_DTO                         (1UL << 3UL)
#define DEV_SDC_RINTSTS_CD                          (1UL << 2UL)
#define DEV_SDC_RINTSTS_RE                          (1UL << 1UL)
#define DEV_SDC_RINTSTS_CDT                         (1UL << 0UL)

#define DEV_SDC_RINTSTS_SDIO_INTERRUPT              (0xffff0000UL)
#define DEV_SDC_RINTSTS_INT_STATUS_MASK             (0x0000ffffUL)

#define DEV_SDC_STATUS_DMA_REQ                      (1UL << 31UL)
#define DEV_SDC_STATUS_DMA_ACK                      (1UL << 30UL)
#define DEV_SDC_STATUS_FIFO_COUNT_MASK              (0x1fffUL << 17UL)
#define DEV_SDC_STATUS_RESPONSE_INDEX               (0x3fUL << 11UL)
#define DEV_SDC_STATUS_DATA_STATE_MC_BUSY           (1UL << 10UL)
#define DEV_SDC_STATUS_DATA_BUSY                    (1UL << 9UL)
#define DEV_SDC_STATUS_DATA_3_STATUS                (1UL << 8UL)
#define DEV_SDC_STATUS_COMMAND_FSM_STATES_MASK      (0xfUL << 4UL)
#define DEV_SDC_STATUS_FIFO_FULL                    (1UL << 3UL)
#define DEV_SDC_STATUS_FIFO_EMPTY                   (1UL << 2UL)
#define DEV_SDC_STATUS_FIFO_TX_WATERMARK            (1UL << 1UL)
#define DEV_SDC_STATUS_FIFO_RX_WATERMARK            (1Ul << 0)

#define DEV_SDC_CLKENA_LOWPOWER                     (1UL<<16UL)
#define DEV_SDC_CLKENA_ENABLE                       (1UL<<0)

#define DEV_SDC_UHSREG_1P8V                         (1UL<<0)
#define DEV_SDC_UHSREG_DDR                          (1UL<<16UL)

#define DEV_SDC_CMD8_HIGHT_V                        (1UL<<8UL)
#define DEV_SDC_CMD8_LOW_V                          (2UL<<8UL)

#define DEV_SDC_ACMD41_HCS                          (1UL<<30UL)
#define DEV_SDC_ACMD41_XPC                          (1UL<<28UL)
#define DEV_SDC_ACMD41_VOLTAGE_MASK                 (0xffUL<<15UL)
#define DEV_SDC_ACMD41_VOLTAGE_MASK                 (0xffUL<<15UL)
#define DEV_SDC_ACMD41_S18R                         (1UL<<24UL)
#define DEV_SDC_ACMD41_LVR                          (1UL<<7UL)

#define DEV_SDC_ACMD41_RESPONSE_BUSY                (1UL<<31UL)
#define DEV_SDC_ACMD41_RESPONSE_CCS                 (1UL<<30UL)
#define DEV_SDC_ACMD41_RESPONSE_S18A                (1UL<<24UL)

#define DEV_SDC_CMD6_MODE_CHECK                     (0UL<<31UL)
#define DEV_SDC_CMD6_MODE_SWITCH                    (1UL<<31UL)
#define DEV_SDC_CMD6_FUNC_MASK                      (0XFFFFUL)





#define   DEV_SDC_BASE              _IO_((uint32_t)0x200C0000)
#define   DEV_SDC                   ((DEV_SDC_RegDef *) DEV_SDC_BASE)


typedef enum
{

    SDC_CARD_TYPE_VER1 = 1UL,
    SDC_CARD_TYPE_VER2 = 2UL,

    SDC_CARD_TYPE_VER1_SDSC = 3UL,

    SDC_CARD_TYPE_VER2_SDSC = 4UL,
    SDC_CARD_TYPE_VER2_SDHC = 5UL,
    SDC_CARD_TYPE_VER2_SDXC = 6UL,
} SDC_CardTypeEnum;

typedef enum
{
    //ACCESS MODE
    SDC_CAED_SF_SD_DEFAULT = 0UL << 0,
    SDC_CAED_SF_SDR12 = 0UL << 0,
    SDC_CAED_SF_HS = 1UL << 0,
    SDC_CAED_SF_SDR25 = 1UL << 0,
    SDC_CAED_SF_SDR50 = 2UL << 0,
    SDC_CAED_SF_SDR104 = 3UL << 0,
    SDC_CAED_SF_DDR50 = 4UL << 0,
    SDC_CAED_SF_ACCESS = 0XFUL << 0,

    //COMMAND SYSTEM
    SDC_CAED_SF_CS_DEFAULT = 0UL << 4,
    SDC_CAED_SF_FOREC = 1UL << 4,
    SDC_CAED_SF_OTP = 3UL << 4,
    SDC_CAED_SF_ASSD = 4UL << 4,
    SDC_CAED_SF_COMMAND = 0XFUL << 4,

    //DRIVER STRENGTH
    SDC_CAED_SF_TYPEB_DEFAULT = 0UL << 8,
    SDC_CAED_SF_TYPEA = 1UL << 8,
    SDC_CAED_SF_TYPEC = 2UL << 8,
    SDC_CAED_SF_TYPED = 3UL << 8,
    SDC_CAED_SF_DRIVER = 0XFUL << 8,

    //POWER LIMIT
    SDC_CAED_SF_0P72W_DEFAULT = 0UL << 12,
    SDC_CAED_SF_1P44W = 1UL << 12,
    SDC_CAED_SF_2P16W = 2UL << 12,
    SDC_CAED_SF_2P88W = 3UL << 12,
    SDC_CAED_SF_1P80W = 4UL << 12,
    SDC_CAED_SF_POWER = 0XF << 12,

} SDC_CardSwitchFuncEnum;


/*
 * 卡是否走1.8v电压
 * 0：3.3 1：1.8
 */
typedef enum
{

    DEV_SDC_V33 = 0,
    DEV_SDC_V18 = 1,
} SDC_WorkVoltageEnum;


struct SDC_DMA_Channel
{
    uint8_t memory_card_rx_dma_channel;
    uint8_t memory_card_tx_dma_channel;
};



typedef MEMORY_CARD_Info *SDC_Info;


#define SDC_INT_MASK  (DEV_SDC_RINTSTS_RE| \
                        DEV_SDC_RINTSTS_RTO_BAR| \
                        DEV_SDC_RINTSTS_DRTO_BDS| \
                        DEV_SDC_RINTSTS_HTO| \
                        DEV_SDC_RINTSTS_FRUN| \
                        DEV_SDC_RINTSTS_HLE| \
                        DEV_SDC_RINTSTS_SBE_BCI| \
                        DEV_SDC_RINTSTS_EBE)


#define sdc_read_mcycle() read_mcycle()


void sdc_write_dma_init(uint32_t dma_ch);
void sdc_read_dma_init(uint32_t dma_ch);



uint32_t hal_sdc_set_clock(uint32_t div, uint64_t mcycle_ms_freq);
uint32_t hal_sdc_send_cmd(uint32_t cmd, uint32_t arg, uint32_t *response, uint64_t mcycle_ms_freq);
uint32_t hal_sdc_send_stop(uint64_t mcycle_ms_freq);

uint32_t hal_sdc_init(uint32_t bus_width, uint32_t clk, SDC_Info sd_info);
uint32_t sdc_read_data(uint8_t *buffer, uint32_t sd_addr, uint32_t len, uint32_t dma_ch, SDC_Info sd_info);
uint32_t sdc_write_data(uint8_t *buffer, uint32_t sd_addr, uint32_t len, uint32_t dma_ch, SDC_Info sd_info);


void hal_dev_sdc_set_bytcnt(uint32_t cnt);
void hal_dev_sdc_set_blksiz(uint32_t size);
void hal_dev_sdc_set_fifoth(uint32_t fifoth);
void hal_dev_sdc_set_dma_enable();
void hal_dev_sdc_set_rintsts(uint32_t val);
void hal_dev_sdc_set_intmask(uint32_t val);
void hal_dev_sdc_set_ctrl_or(uint32_t val);
void hal_dev_sdc_set_ctrl_and(uint32_t val);
uint32_t hal_dev_sdc_get_mintsts_state();
uint32_t hal_dev_sdc_get_rintsts_state();
uint32_t hal_dev_sdc_get_state();
uint32_t hal_dev_sdc_get_ctrl_fifo_reset_state();
Options_EnableEnum hal_dev_sdc_get_dma_cmd_state(uint32_t channelx);
void hal_dev_sdc_set_sdr_dma_config_init(uint32_t chx, uint32_t sdr, uint32_t bytcnt, uint32_t it_flag, Options_EnableEnum cmd_state);
void hal_dev_sdc_set_dst_dma_config_init(uint32_t chx, uint32_t dst, uint32_t bytcnt, uint32_t it_flag);
void hal_dev_sdc_set_sdr_dma_config_deinit(uint32_t chx, uint32_t it_flag);
void hal_dev_sdc_set_dst_dma_config_deinit(uint32_t chx, uint32_t it_flag);

#endif /* SRC_DWC_H_ */
