/**
* @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.
*/

#include "hal_memory_card.h"
#include "hal_sd_card.h"
#include "hal_mm_card.h"
#include "hal_cmu.h"

/**
* @brief        初始化读数据dma
* @details
* @param        @arg dma_ch: dma通道数
* @return       无
* @note         无
*/
void hal_memory_card_read_dma_init(uint32_t dma_ch)
{
    DEV_CMU->CLKEN0 |= DEV_CMU_CLKEN0_DMA;
    DEV_RMU->RSTEN0 |= DEV_RMU_RSTEN0_DMA;
    dma_config_parameter_t dma_config_struct;
    dma_config_struct.src_start_addr = (uint32_t)&DEV_SDC->DATA;
    dma_config_struct.src_slot_offset = 1UL;
    dma_config_struct.src_word_offset = 1UL;
    dma_config_struct.src_width = DMA_Data_Width_32Bit;
    dma_config_struct.src_dls = DMA_Data_Location_Select_Low;
    dma_config_struct.src_ifs = DMA_Device_Sel_SDC_RX;
    dma_config_struct.src_burst_len = DMA_Burst_Length_Burst8;
    dma_config_struct.src_addr_type = DMA_Address_Type_Fix;
    dma_config_struct.src_slave = DMA_Address_Slave_Device;
    dma_config_struct.dst_start_addr = 0UL;
    dma_config_struct.dst_slot_offset = 1UL;
    dma_config_struct.dst_word_offset = 4UL;
    dma_config_struct.dst_width = DMA_Data_Width_32Bit;
    dma_config_struct.dst_dls = DMA_Data_Location_Select_Low;
    dma_config_struct.dst_ifs = DMA_Device_Sel_None;
    dma_config_struct.dst_burst_len = DMA_Burst_Length_Burst8;
    dma_config_struct.dst_addr_type = DMA_Address_Type_Inc;
    dma_config_struct.dst_slave = DMA_Address_Slave_Memory;
    dma_config_struct.slot_num = 1UL;
    dma_config_struct.byte_num = 1UL;
    //dma_config_struct.priority = dma_ch;
    dma_config_struct.priority = 7;
    dma_config_struct.reload_en = DISABLE;
    DMA_Config(dma_ch, &dma_config_struct);
    DMA_ClearITPendingBit(dma_ch, DMA_Transfer_End);
//  DMA_AccelerateCmd(dma_ch,ENABLE);
    DMA_Cmd(dma_ch, DISABLE);
}

/**
* @brief        初始化读数据dma
* @details
* @param        无
* @return       @arg dma_ch: dma通道数
* @note         无
*/
void hal_memory_card_write_dma_init(uint32_t dma_ch)
{
    DEV_CMU->CLKEN0 |= DEV_CMU_CLKEN0_DMA;
    DEV_RMU->RSTEN0 |= DEV_RMU_RSTEN0_DMA;
    dma_config_parameter_t dma_config_struct;
    dma_config_struct.src_start_addr = 0;
    dma_config_struct.src_slot_offset = 1UL;
    dma_config_struct.src_word_offset = 4UL;
    dma_config_struct.src_width = DMA_Data_Width_32Bit;
    dma_config_struct.src_dls = DMA_Data_Location_Select_Low;
    dma_config_struct.src_ifs = DMA_Device_Sel_None;
    dma_config_struct.src_burst_len = DMA_Burst_Length_Burst8;
    dma_config_struct.src_addr_type = DMA_Address_Type_Inc;
    dma_config_struct.src_slave = DMA_Address_Slave_Memory;
    dma_config_struct.dst_start_addr = (uint32_t)&DEV_SDC->DATA;
    dma_config_struct.dst_slot_offset = 1UL;
    dma_config_struct.dst_word_offset = 1UL;
    dma_config_struct.dst_width = DMA_Data_Width_32Bit;
    dma_config_struct.dst_dls = DMA_Data_Location_Select_Low;
    dma_config_struct.dst_ifs = DMA_Device_Sel_SDC_TX;
    dma_config_struct.dst_burst_len = DMA_Burst_Length_Burst8;
    dma_config_struct.dst_addr_type = DMA_Address_Type_Fix;
    dma_config_struct.dst_slave = DMA_Address_Slave_Device;
    dma_config_struct.slot_num = 1UL;
    dma_config_struct.byte_num = 1UL;
//    dma_config_struct.priority = dma_ch;
    dma_config_struct.priority = 7;
    dma_config_struct.reload_en = DISABLE;
    DMA_Config(dma_ch, &dma_config_struct);
    DMA_ClearITPendingBit(dma_ch, DMA_Transfer_End);
//  DMA_AccelerateCmd(dma_ch,ENABLE);
    DMA_Cmd(dma_ch, DISABLE);
}

/**
* @brief        设置存储卡的工作时钟
* @details
* @param        @arg div ：时钟的分频数
*               @arg mcycle_ms_freq ：mcycle每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note         无
*/
uint32_t hal_memory_card_clock(uint32_t div, uint64_t mcycle_ms_freq)
{
    uint32_t cmd_cnt = 0;
    uint32_t ret = ERR_CARD_NONE;
    //等待空闲
#if DEV_SDC_TIME_OUT_CHECK == 1UL
    uint64_t time_out_value;
    time_out_value = sdc_read_mcycle() + mcycle_ms_freq * DEV_SDC_TIME_OUT_TIME;
#endif

    while ((DEV_SDC->STATUS & (DEV_SDC_STATUS_DATA_BUSY | DEV_SDC_STATUS_DATA_STATE_MC_BUSY)) != 0)
    {
#if DEV_SDC_TIME_OUT_CHECK == 1UL

        if (sdc_read_mcycle() >= time_out_value)
        {
            return ERR_CARD_SET_CLOCK_CARD_TIMEOUT;
        }

#endif
        ;
    }

    cmd_cnt = 0;

    do
    {
        if (cmd_cnt <= 100UL)
        {
            cmd_cnt++;
        }
        else
        {
            return ERR_CARD_SET_CLOCK_CARD_TIMEOUT;
        }

        DEV_SDC->RINTSTS = DEV_SDC_RINTSTS_INT_STATUS_MASK;//写1清除所有标志
        DEV_SDC->CLKENA = 0;
        DEV_SDC->CMD = DEV_SDC_CMD_UPDATE_CLOCK_REGISTERS_ONLY//只发时钟
                       | DEV_SDC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                       ;

        while ((DEV_SDC->CMD & DEV_SDC_CMD_START_CMD) != 0) //等待上一个命令发送
        {
            ;
        }
    }
    while (DEV_SDC->RINTSTS != 0);

    DEV_SDC->RINTSTS = DEV_SDC_RINTSTS_INT_STATUS_MASK;
//    DEV_CMU->SDCCLK = DEV_CMU_SDCCLK_SEL_PLL_CORE | ((div - 1) << 4UL);
    DEV_CMU->SDCCLK = DEV_CMU_SDCCLK_SEL_PLL_CORE | (6 << 4UL);
    cmd_cnt = 0;

    do
    {
        if (cmd_cnt <= 100UL)
        {
            cmd_cnt++;
        }
        else
        {
            return ERR_CARD_SET_CLOCK_CARD_TIMEOUT;
        }

        DEV_SDC->RINTSTS = DEV_SDC_RINTSTS_INT_STATUS_MASK;//写1清除所有标志
        DEV_SDC->CLKENA = 1;
        DEV_SDC->CMD = DEV_SDC_CMD_WAIT_PRVDATA_COMPLETE//等待前面的数据转换完成在发送此命令
                       | DEV_SDC_CMD_UPDATE_CLOCK_REGISTERS_ONLY //只发时钟
                       | DEV_SDC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                       ;

        while ((DEV_SDC->CMD & DEV_SDC_CMD_START_CMD) != 0) //等待上一个命令发送
        {
            ;
        }
    }
    while (DEV_SDC->RINTSTS != 0);

    DEV_SDC->RINTSTS = DEV_SDC_RINTSTS_INT_STATUS_MASK;
    return ret;
}

/**
* @brief        向卡发送命令
* @details      向卡发送命令，并将相应返回
* @param        @arg cmd: 对应命令号
*               @arg arg: 命令对应参数
*               @arg response: 命令对应相应的存放数组，大小为4word
*               @arg mcycle_ms_freq ：mcycle每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note
*/
uint32_t hal_memory_card_send_cmd(uint32_t cmd, uint32_t arg, uint32_t *response, uint64_t mcycle_ms_freq)
{
    uint32_t ret = 0;
#if DEV_SDC_TIME_OUT_CHECK == 1
    uint64_t time_out_value;
    time_out_value = sdc_read_mcycle() + mcycle_ms_freq * DEV_SDC_TIME_OUT_TIME;
#endif

    while ((DEV_SDC->CMD & DEV_SDC_CMD_START_CMD) != 0) //等待上一个命令完成
    {
#if DEV_SDC_TIME_OUT_CHECK == 1

        if (sdc_read_mcycle() >= time_out_value)
        {
            return ERR_CARD_SEND_CMD_WAITE_LAST_TIMEOUT;
        }

#endif
        ;
    }

    DEV_SDC->RINTSTS = DEV_SDC_RINTSTS_INT_STATUS_MASK;
    DEV_SDC->CMDARG = arg;//cmd携带参数
    DEV_SDC->CMD = cmd | DEV_SDC_CMD_USE_HOLD_REG;
#if DEV_SDC_TIME_OUT_CHECK == 1
    time_out_value = sdc_read_mcycle() + mcycle_ms_freq * DEV_SDC_TIME_OUT_TIME;
#endif

    while ((DEV_SDC->RINTSTS & DEV_SDC_RINTSTS_CD) != DEV_SDC_RINTSTS_CD)
    {
#if DEV_SDC_TIME_OUT_CHECK == 1

        if (sdc_read_mcycle() >= time_out_value)
        {
            return ERR_CARD_SEND_CMD_WAITE_STATE_TIMEOUT;
        }

#endif
        ;
    }

    DEV_SDC->RINTSTS = DEV_SDC_RINTSTS_CD;

    if ((DEV_SDC->RINTSTS & (DEV_SDC_RINTSTS_RE | DEV_SDC_RINTSTS_RCRC | DEV_SDC_RINTSTS_DCRC
                             | DEV_SDC_RINTSTS_RTO_BAR | DEV_SDC_RINTSTS_DRTO_BDS | DEV_SDC_RINTSTS_FRUN
                             | DEV_SDC_RINTSTS_HLE | DEV_SDC_RINTSTS_SBE_BCI | DEV_SDC_RINTSTS_EBE)) != 0)
    {
        ret = DEV_SDC->RINTSTS;
    }

    response[0] = DEV_SDC->RESP0;
    response[1] = DEV_SDC->RESP1;
    response[2] = DEV_SDC->RESP2;
    response[3] = DEV_SDC->RESP3;
    return ret;
}

/**
* @brief        初始化卡
* @details      会探测是sd卡还是mm卡
* @param        @arg bus_width 通信的数据线
*               @arg clk 通信的时钟频率
*               @arg card_info 用于保留卡信息参数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note         可以识别sd卡和emmc卡
*               emmc卡目前只支持1线低速
*/
uint32_t hal_memory_card_init(uint32_t bus_width, uint32_t clk, MEMORY_CARD_Info *card_info)
{
    uint32_t card1_ret = 0, card2_ret = 0;
    card1_ret = hal_sdc_init(bus_width, clk, card_info);

    if (card1_ret != 0)
    {
        card2_ret = hal_mmc_init(bus_width, clk, card_info);
    }

    if (card1_ret != 0 && card2_ret != 0)
    {
        return (card1_ret >> 16) | (card2_ret & 0xffff0000UL);
    }
    else
    {
        return ERR_CARD_NONE;
    }
}


/**
* @brief        向卡发送停止命令
* @details      向卡发送停止命令，并将相应返回
* @param
*               @arg mcycle_ms_freq ：mtime每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note
*/
uint32_t hal_memory_card_send_stop(uint64_t mcycle_ms_freq)
{
    uint32_t sd_cmd, sd_arg;
    uint32_t sd_response[4];
    uint32_t ret = 0;
#if DEV_SDC_TIME_OUT_CHECK == 1
    uint64_t time_out_value;
    time_out_value = sdc_read_mcycle() + mcycle_ms_freq * DEV_SDC_TIME_OUT_TIME;
#endif

    do
    {
#if DEV_SDC_TIME_OUT_CHECK == 1

        if (sdc_read_mcycle() >= time_out_value)
        {
            return ERR_CARD_SEND_STOP_TIMEOUT;
        }

#endif
        sd_arg = 0;
        sd_cmd = SD_CMD(12)
                 | DEV_SDC_CMD_RESPONSE_EXPECT //期望响应
                 | DEV_SDC_CMD_CHECK_RESPONSE_CRC //检测响应crc
                 | DEV_SDC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
                 | DEV_SDC_CMD_STOP_ABORT_CMD
                 | DEV_SDC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                 ;
        ret = hal_sdc_send_cmd(sd_cmd, sd_arg, sd_response, mcycle_ms_freq);

        if (ret == ERR_CARD_SEND_CMD_WAITE_LAST_TIMEOUT || ret == ERR_CARD_SEND_CMD_WAITE_STATE_TIMEOUT)
        {
            return ret | ERR_CARD_SEND_STOP_TIMEOUT;
        }
    }
    while (ret);

    return ERR_CARD_NONE;
}

/**
* @brief        读取卡数据
* @details      通过dma读取固定的数据
* @param        @arg buffer: 从卡读出数据存放地址
*               @arg card_addr： 卡的地址
*               @arg len: 读取的数据长度
*               @arg dma_ch: dma通道数
*               @arg card_info ：@ MEMORY_CARD_Info 存放卡信息得结构体地址
* @return       @arg ret: 错误码 @ MEMORY_CARD_ErrorCodeEnum
* @note         不同的卡card_addr代表的地址为byte的地址或者block的地址
*/
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)
{
    return sdc_read_data(buffer, card_addr, len, dma_ch, card_info);
}

/**
* @brief        向卡写入数据
* @details      通过dma写人固定的数据
* @param        @arg buffer: 写入卡数据存放地址
*               @arg card_addr： 卡的地址
*               @arg len: 读取的数据长度
*               @arg dma_ch: dma通道数
*               @arg card_info ：@ MEMORY_CARD_Info 存放卡信息得结构体地址
* @return       @arg ret: 错误码 @ MEMORY_CARD_ErrorCodeEnum
* @note         不同的卡card_addr代表的地址为byte的地址或者block的地址
*/
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)
{
    return sdc_write_data(buffer, card_addr, len, dma_ch, card_info);
}

void hal_memory_card_get_csd(uint8_t *csd_value)
{
    for (int i = 0; i < CARD_CSD_LEN; i++)
    {
        csd_value[i] = mem_card_info.csd[i];
    }
}

void hal_memory_card_get_cid(uint8_t *cid_value)
{
    for (int i = 0; i < CARD_CID_LEN; i++)
    {
        cid_value[i] = mem_card_info.cid[i];
    }
}


uint32_t hal_memory_card_get_cpu_clock(void)
{
//  uint32_t clock_freq = 24000000UL;
//  return (clock_freq);
    return cmu_get_cpuclk();
}


uint8_t hal_memory_card_get_capacity()
{
    return mem_card_info.capacity;
}



