pure sdk for main

This commit is contained in:
divadiow
2025-08-27 09:51:58 +01:00
parent f0d033f1c9
commit 0571416e7c
3283 changed files with 1577720 additions and 1 deletions
+947
View File
@@ -0,0 +1,947 @@
#include "sys_config.h"
#include "typesdef.h"
#include "devid.h"
#include "list.h"
#include "dev.h"
#include "osal/task.h"
#include "osal/semaphore.h"
#include "osal/mutex.h"
#include "lib/sdhost/sdhost.h"
#include "hal/gpio.h"
#include "osal/irq.h"
#include "osal/string.h"
#include "osal/mutex.h"
#include "osal/irq.h"
#include "osal/task.h"
#include "osal/sleep.h"
#include "osal/timer.h"
struct hgsdh_hw
{
__IO uint32 CFG;
__IO uint32 BAUD;
__IO uint32 CPTR;
__IO uint32 DPTR;
__IO uint32 DCNT;
#if TXW81X
__IO uint32 STA;
__IO uint32 CFG1;
__IO uint32 ISMP;
#endif
};
static uint8 sdhc_cmd_rsp_buf[32]__attribute__ ((aligned(4)));
#if TXW81X
static uint8 sdhc_dat_ping_buf0[512];
static uint8 sdhc_dat_ping_buf1[512];
#endif
void delay_us(uint32 n);
struct sdh_device *sdh_irq;
static void ll_sdhc_set_bus_clk(struct hgsdh_hw *p_sdhc, uint32 sys_clk, uint32 bus_clk)
{
p_sdhc->BAUD = ((sys_clk + bus_clk - 1)/ bus_clk) - 1;
}
static void ll_sdhc_set_ioe(struct hgsdh_hw *p_sdhc, TYPE_LL_SDHC_IOE ioe)
{
if (ioe == LL_SDHC_IROF) {
p_sdhc->CFG &= ~LL_SDHC_ODAT_RISING_EDGE;
} else {
p_sdhc->CFG |= LL_SDHC_ODAT_RISING_EDGE;
}
}
static void ll_sdhc_set_dat_width(struct hgsdh_hw *p_sdhc, TYPE_LL_SDHC_DAT_WIDTH width)
{
if (width == LL_SDHC_DAT_4BIT) {
p_sdhc->CFG |= LL_SDHC_DAT_WIDTH_4BIT;
} else {
p_sdhc->CFG &= ~LL_SDHC_DAT_WIDTH_4BIT;
}
}
static void ll_sdhc_clk_suspend_ctrl(struct hgsdh_hw *p_sdhc, uint8 suspend_enable)
{
if (suspend_enable) {
p_sdhc->CFG &= ~LL_SDHC_CLK_OUT_EN;
} else {
p_sdhc->CFG |= LL_SDHC_CLK_OUT_EN;
}
}
static void ll_sdhc_post_8clk_ctrl(struct hgsdh_hw *p_sdhc, uint8 enable)
{
if (enable) {
p_sdhc->CFG |= LL_SDHC_8CLK_AFTER_EN;
//p_sdhc->CFG |= LL_SDHC_8CLK_BEFORE_EN;
} else {
p_sdhc->CFG &= ~LL_SDHC_8CLK_AFTER_EN;
//p_sdhc->CFG &= ~LL_SDHC_8CLK_BEFORE_EN;
}
}
static void ll_sdhc_before_8clk_ctrl(struct hgsdh_hw *p_sdhc, uint8 enable)
{
if (enable) {
p_sdhc->CFG |= LL_SDHC_8CLK_BEFORE_EN;
} else {
p_sdhc->CFG &= ~LL_SDHC_8CLK_BEFORE_EN;
}
}
static void ll_sdhc_8clk_ctrl(struct hgsdh_hw *p_sdhc, uint8 enable)
{
ll_sdhc_before_8clk_ctrl(p_sdhc, enable);
}
static void ll_sdhc_cmd_intr_enable(struct hgsdh_hw *p_sdhc, uint8 enable)
{
if (enable) {
p_sdhc->CFG |= LL_SDHC_CMD_INTR_EN;
} else {
p_sdhc->CFG &= ~LL_SDHC_CMD_INTR_EN;
}
}
/**
* @brief ll_sdhc_set_dat_width
* @param p_sdhc : sdhc register structure pointer
* @retval none
*/
static void ll_sdhc_dat_intr_enable(struct hgsdh_hw *p_sdhc, uint8 enable)
{
if (enable) {
p_sdhc->CFG |= LL_SDHC_DAT_INTR_EN;
} else {
p_sdhc->CFG &= ~LL_SDHC_DAT_INTR_EN;
}
}
static void ll_sdhc_clr_cmd_done_pending(struct hgsdh_hw *p_sdhc)
{
p_sdhc->CFG |= LL_SDHC_CMD_DONE_CLR;
}
#ifdef TXW81X
static void ll_sdhc_cmd_sample_enable(struct hgsdh_hw *p_sdhc, uint8 enable)
{
if (enable)
{
p_sdhc->CFG1 |= LL_SDHC_CMD_SMP_EN;
}else{
p_sdhc->CFG1 &= ~LL_SDHC_CMD_SMP_EN;
}
}
static void ll_sdhc_dat_sample_enable(struct hgsdh_hw *p_sdhc, uint8 enable)
{
if (enable)
{
p_sdhc->CFG1 |= LL_SDHC_DAT_SMP_EN;
}else{
p_sdhc->CFG1 &= ~LL_SDHC_DAT_SMP_EN;
}
}
static void ll_sdhc_delay_clock(struct hgsdh_hw *p_sdhc, TYPE_LL_SDHC_DELAY_SYSCLK type , uint8_t delay)
{
if (type == LL_SDHC_DLY_HALF_SYSCLK)
{
p_sdhc->CFG1 &= ~0xff;
p_sdhc->CFG1 |= LL_SDHC_DELAY_HALF_SYSCLK;
}else if(type == LL_SDHC_DLY_ONE_SYSCLK){
p_sdhc->CFG1 &= ~0xff;
p_sdhc->CFG1 |= LL_SDHC_DELAY_WHOLE_SYSCLK;
}else if(type == LL_SDHC_DLY_CHAIN){
p_sdhc->CFG1 &= ~0xff;
p_sdhc->CFG1 |= LL_SDHC_DELAY_CHAIN_EN;
p_sdhc->CFG1 |= delay;
}else{
p_sdhc->CFG1 &= ~0xff;
}
}
static void ll_sdhc_dat_overflow_stop_enable(struct hgsdh_hw *p_sdhc, uint8_t enable)
{
if (enable)
{
p_sdhc->CFG1 |= LL_SDHC_DAT_OVERFLOW_STOP_EN;
}else{
p_sdhc->CFG1 &= ~LL_SDHC_DAT_OVERFLOW_STOP_EN;
}
}
#endif
static bool ll_sdhc_get_cmd_done_pending(struct hgsdh_hw *p_sdhc)
{
return ((p_sdhc->CFG & LL_SDHC_CMD_DONE)) ? TRUE : FALSE;
}
static bool ll_sdhc_get_cmd_rsp_timeout_pending(struct hgsdh_hw *p_sdhc)
{
return (p_sdhc->CFG & LL_SDHC_RSP_TIMEOUT) ? TRUE : FALSE;
}
static bool ll_sdhc_get_cmd_rsp_err_pending(struct hgsdh_hw *p_sdhc)
{
return (p_sdhc->CFG & LL_SDHC_RSP_CRC_ERR) ? TRUE : FALSE;
}
static void ll_sdhc_clr_dat_done_pending(struct hgsdh_hw *p_sdhc)
{
p_sdhc->CFG |= LL_SDHC_DAT_DONE_CLR;
}
static bool ll_sdhc_get_dat_done_pending(struct hgsdh_hw *p_sdhc)
{
return ((p_sdhc->CFG & LL_SDHC_DAT_DONE)) ? TRUE : FALSE;
}
static bool ll_sdhc_get_rd_dat_err_pending(struct hgsdh_hw *p_sdhc)
{
return (p_sdhc->CFG & LL_SDHC_DAT_CRC_ERR) ? TRUE : FALSE;
}
static bool ll_sdhc_get_wr_dat_err_pending(struct hgsdh_hw *p_sdhc)
{
return ((p_sdhc->CFG & LL_SDHC_CRC_STA) != (2<<16)) ? TRUE : FALSE;
}
static void ll_sdhc_read_data_kick(struct hgsdh_hw *p_sdhc, uint32 addr, uint32 len)
{
p_sdhc->CFG &= ~LL_SDHC_DAT_RW_MSK;
p_sdhc->CFG &= ~LL_SDHC_CLK_OUT_EN;
ll_sdhc_clr_dat_done_pending(p_sdhc);
//os_printf("\r\nDPTR:%x\r\n",addr);
p_sdhc->DPTR = addr;
p_sdhc->DCNT = len & (~ 0x3UL);
p_sdhc->CFG |= LL_SDHC_DAT_RCV;
}
static void ll_sdhc_write_data_kick(struct hgsdh_hw *p_sdhc, uint32 addr, uint32 len)
{
p_sdhc->CFG &= ~LL_SDHC_DAT_RW_MSK;
ll_sdhc_clr_dat_done_pending(p_sdhc);
p_sdhc->DPTR = addr;
p_sdhc->DCNT = len & (~ 0x3UL);
p_sdhc->CFG |= LL_SDHC_DAT_SEND_WAIT_BUSY;
}
static bool ll_sdhc_read_data_wait(struct hgsdh_hw *p_sdhc, uint32 time_ms)
{
do {
} while (!ll_sdhc_get_dat_done_pending(p_sdhc));
if (ll_sdhc_get_rd_dat_err_pending(p_sdhc)) {
os_printf("dat err\r\n");
return FALSE;
}
return TRUE;
}
static bool ll_sdhc_write_data_wait(struct hgsdh_hw *p_sdhc, uint32 time_ms)
{
uint64 time = os_jiffies();
do {
if ((os_jiffies() - time) > time_ms) {
return FALSE;
}
} while (!ll_sdhc_get_dat_done_pending(p_sdhc));
if (ll_sdhc_get_wr_dat_err_pending(p_sdhc)) {
return FALSE;
}
return TRUE;
}
void hgic_sdc_irq_update(struct sdh_device *host, int32_t enable)
{
struct hgsdh *sdh_hw = (struct hgsdh*)host;
struct hgsdh_hw *hw = (struct hgsdh_hw *)sdh_hw->hw;
if (enable) {
os_printf("enable sdio irq");
} else {
os_printf("disable sdio irq");
}
#if CMD_ISR_EN
ll_sdhc_cmd_intr_enable(hw, enable);
#endif
#if DAT_ISR_EN
ll_sdhc_dat_intr_enable(hw, enable);
#endif
// ll_sdhc_dat1_intr_enable(host->p_sdhc, enable);
}
//volatile uint8 sd_8clk_open = 0;
void ll_sdhc_config(struct sdh_device *sdhost,struct hgsdh_hw * p_sdhc, TYPE_LL_SDHC_CFG *p_cfg)
{
ll_sdhc_set_bus_clk(p_sdhc, peripheral_clock_get(HG_AHB_PT_SDMMC), p_cfg->bus_clk);
ll_sdhc_set_ioe(p_sdhc, p_cfg->ioe);
ll_sdhc_set_dat_width(p_sdhc, p_cfg->width);
ll_sdhc_clk_suspend_ctrl(p_sdhc, 0);
ll_sdhc_8clk_ctrl(p_sdhc, sdhost->sd_8clk_open);
p_sdhc->CFG |= LL_SDHC_EN;
#ifdef TXW81X
p_sdhc->CFG1 |= (LL_SDHC_DAT_OVERFLOW_STOP_EN);
#endif
}
void ll_sdhc_close(struct hgsdh_hw * p_sdhc)
{
p_sdhc->CFG &= ~LL_SDHC_EN;
}
#ifdef TXW81X
void ll_sdhc_set_sample(struct hgsdh_hw *p_sdhc, uint8_t cmd_sample, uint8_t dat_sample)
{
p_sdhc->ISMP = (dat_sample << 16) | cmd_sample;
}
#endif
volatile uint8 sd_cmd_isr_get = 0;
volatile uint8 sd_dat_isr_get = 0;
int32 sdh_cmd(struct sdh_device *sdhost,struct rt_mmcsd_cmd* cmd)
{
uint32 rsp_type;
uint32 cmd_tick;
//uint32 cur_tick;
struct hgsdh *sdh_hw = (struct hgsdh*)sdhost;
struct hgsdh_hw *p_sdhc = (struct hgsdh_hw *)sdh_hw->hw;
sdhc_cmd_rsp_buf[0] = cmd->cmd_code | 0x40;
//put_unaligned_be32(cmd->arg, &sdhc_cmd_rsp_buf[1]);
sdhc_cmd_rsp_buf[1] = (cmd->arg >> 24) & 0xFF;
sdhc_cmd_rsp_buf[2] = (cmd->arg >> 16) & 0xFF;
sdhc_cmd_rsp_buf[3] = (cmd->arg >> 8) & 0xFF;
sdhc_cmd_rsp_buf[4] = (cmd->arg >> 0) & 0xFF;
p_sdhc->CPTR = (uint32)sdhc_cmd_rsp_buf;
rsp_type = ((cmd->flags & MMC_RSP_PRESENT) ? BIT(5) : 0) |
((cmd->flags & MMC_RSP_136) ? BIT(6) : 0) |
((cmd->flags & MMC_RSP_BUSY) ? BIT(7) : 0);
if (0 == rsp_type) {
rsp_type = (0x2 << 5);
}
//ll_sdhc_post_8clk_ctrl(p_sdhc, sd_8clk_open);
ll_sdhc_clr_cmd_done_pending(p_sdhc);
// os_printf("cmd:%d %x\r\n",cmd->cmd_code,(p_sdhc->CFG & ~LL_SDHC_CMD_RESP_MSK) | rsp_type);
p_sdhc->CFG = (p_sdhc->CFG & ~LL_SDHC_CMD_RESP_MSK) | rsp_type;
if(cmd->cmd_code == STOP_TRANSMISSION)
{
cmd_tick = ~0;
}
else
{
cmd_tick = 0x1fffff;
}
//ll_gpio_bit_reset(GPIOB,BIT(5));
while (!ll_sdhc_get_cmd_done_pending(p_sdhc)&&!sd_cmd_isr_get)
{
if (--cmd_tick == 0) {
//ll_gpio_bit_reset(GPIOB,BIT(5));
//sdreg(base,SDxCON1) = BIT(BIT_CPCLR);
//sdreg(base,SDxCON0) &= ~BIT(BIT_8CKE);
ll_sdhc_clr_cmd_done_pending(p_sdhc);
// ll_sdhc_post_8clk_ctrl(p_sdhc,0);
// p_sdhc->CFG &= ~(BIT(5)|BIT(6)|BIT(7));
p_sdhc->CFG &= ~BIT(0);
// os_printf ("CMD%d pending time out!resp:%x\r\n", cmd->cmd_code,rsp_type);
//ll_gpio_bit_set(GPIOB,BIT(5));
p_sdhc->CFG |= BIT(0);
//ll_sdhc_post_8clk_ctrl(p_sdhc, 0);
return -1;
}
}
sd_cmd_isr_get = 0;
//ll_gpio_bit_set(GPIOB,BIT(5));
if ((rsp_type != (0x2 << 5)) && (ll_sdhc_get_cmd_rsp_timeout_pending(p_sdhc) || ((cmd->flags & MMC_RSP_CRC) && ll_sdhc_get_cmd_rsp_err_pending(p_sdhc))))
{
os_printf("read timeout pending set or rsp err:%d %d\r\n",ll_sdhc_get_cmd_rsp_timeout_pending(p_sdhc),ll_sdhc_get_cmd_rsp_err_pending(p_sdhc));
return -1;
}
cmd->resp[0] = (sdhc_cmd_rsp_buf[9] << 24) |
(sdhc_cmd_rsp_buf[10] << 16) |
(sdhc_cmd_rsp_buf[11] << 8) |
(sdhc_cmd_rsp_buf[12] << 0);
cmd->resp[1] = (sdhc_cmd_rsp_buf[13] << 24) |
(sdhc_cmd_rsp_buf[14] << 16) |
(sdhc_cmd_rsp_buf[15] << 8) |
(sdhc_cmd_rsp_buf[16] << 0);
cmd->resp[2] = (sdhc_cmd_rsp_buf[17] << 24) |
(sdhc_cmd_rsp_buf[18] << 16) |
(sdhc_cmd_rsp_buf[19] << 8) |
(sdhc_cmd_rsp_buf[20] << 0);
cmd->resp[3] = (sdhc_cmd_rsp_buf[21] << 24) |
(sdhc_cmd_rsp_buf[22] << 16) |
(sdhc_cmd_rsp_buf[23] << 8) |
(sdhc_cmd_rsp_buf[24] << 0);
#if 0
os_printf("\r\n");
for(cmd_tick = 0;cmd_tick < 32;cmd_tick++){
os_printf("%02x",sdhc_cmd_rsp_buf[cmd_tick]);
}
os_printf("\r\n");
#endif
// os_printf("cmd->resp:%x\r\n",cmd->resp[0]);
// ll_sdhc_post_8clk_ctrl(p_sdhc, 0);
return 0;
}
void sdhc_interrupt_handle(struct sdh_device *sdhost)
{
struct hgsdh *sdh_hw = (struct hgsdh*)sdhost;
struct hgsdh_hw *hw = (struct hgsdh_hw *)sdh_hw->hw;
if (ll_sdhc_get_dat_done_pending(hw)){
ll_sdhc_clr_dat_done_pending(hw);
if(sdhost->sd_opt == SD_M_R){
if(ll_sdhc_get_rd_dat_err_pending(hw))
{
if(sdhost->io_cfg.self_adaption_flag != MMCSD_SMP_EN) os_printf("read dat err pending\r\n");
sdhost->data.err = DATA_DIR_READ;
os_sema_up(&sdhost->dat_sema);
return;
}
if(sdhost->data.blks - 1)
{
sdhost->data.blks = sdhost->data.blks -1;
sdhost->data.buf = sdhost->data.buf + sdhost->data.blksize;
if(sdhost->data.psram_flag)
{
ll_sdhc_read_data_kick(hw, (uint32_t)sdhost->data.ping_buff[(sdhost->data.ping_sel+1)%2], sdhost->data.blksize);
hw_memcpy((void *)(sdhost->data.buf - sdhost->data.blksize), (void *)sdhost->data.ping_buff[sdhost->data.ping_sel++], sdhost->data.blksize);
} else {
ll_sdhc_read_data_kick(hw, (uint32_t)sdhost->data.buf, sdhost->data.blksize);
}
}else
{
os_sema_up(&sdhost->dat_sema);
}
}
else if(sdhost->sd_opt == SD_M_W)
{
if (ll_sdhc_get_wr_dat_err_pending(hw))
{
os_printf("write dat err pending\r\n");
sdhost->data.err = DATA_DIR_READ;
os_sema_up(&sdhost->dat_sema);
return;
}
if(sdhost->data.blks - 1)
{
sdhost->data.blks = sdhost->data.blks -1;
sdhost->data.buf = sdhost->data.buf + sdhost->data.blksize;
ll_sdhc_write_data_kick(hw, (uint32_t)sdhost->data.buf, sdhost->data.blksize);
}else
{
os_sema_up(&sdhost->dat_sema);
}
}
else
{
os_sema_up(&sdhost->dat_sema); //single read/write
}
}
}
void SDHOST_IRQHandler_action(void *sdhost)
{
sdhc_interrupt_handle(sdhost);
}
int32 sdh_write(struct sdh_device *sdhost,uint8_t * buf)
{
struct hgsdh *sdh_hw = (struct hgsdh*)sdhost;
struct hgsdh_hw *hw = (struct hgsdh_hw *)sdh_hw->hw;
uint32_t xfer_len = sdhost->data.blksize;
#if DAT_ISR_EN
#if TXW81X
sdhost->data.psram_flag = 0;
sys_dcache_clean_range_unaligned((uint32 *)buf, (uint32_t)(sdhost->data.blks * sdhost->data.blksize));
#endif
sdhost->data.buf = buf;
ll_sdhc_write_data_kick(hw, (uint32_t)buf, xfer_len);
#else
#if TXW81X
sdhost->data.psram_flag = 0;
sys_dcache_clean_range_unaligned((uint32 *)buf, (uint32_t)(sdhost->data.blks * sdhost->data.blksize));
#endif
uint32_t blocks = sdhost->data.blks;
uint32_t size = sdhost->data.blks * sdhost->data.blksize;
do {
ll_sdhc_write_data_kick(hw, (uint32_t)buf, xfer_len);
buf += xfer_len;
if (blocks) {
blocks--;
}
if (!ll_sdhc_write_data_wait(hw, sdhost->data.timeout_ns/1000000))
{
os_printf("write timeout:%d\r\n",sdhost->data.timeout_ns);
sdhost->data.err = DATA_DIR_WRITE;
break;
}
if (ll_sdhc_get_wr_dat_err_pending(hw)) {
os_printf("write dat err pending\r\n");
sdhost->data.err = DATA_DIR_WRITE;
}
sd_dat_isr_get = 0;
} while (blocks);
#endif
return 0;
}
int32 sdh_read(struct sdh_device *sdhost,uint8* buf)
{
struct hgsdh *sdh_hw = (struct hgsdh*)sdhost;
struct hgsdh_hw *hw = (struct hgsdh_hw *)sdh_hw->hw;
uint32_t xfer_len = sdhost->data.blksize;
sdhost->sd_8clk_open = 0;
ll_sdhc_8clk_ctrl(hw, sdhost->sd_8clk_open);
#if DAT_ISR_EN
sdhost->data.buf = buf;
#if TXW81X
sdhost->data.psram_flag = ((((uint32_t)buf) >> 24) == 0x38 || (((uint32_t)buf) >> 24) == 0x08);
if(sdhost->data.psram_flag) buf = (uint8 *)sdhost->data.ping_buff[sdhost->data.ping_sel];
#endif
ll_sdhc_read_data_kick(hw, (uint32_t)buf, xfer_len);
#else
uint32_t blocks = sdhost->data.blks;
uint32_t size = sdhost->data.blks * sdhost->data.blksize;
do {
ll_sdhc_read_data_kick(hw, (uint32_t)buf, xfer_len);
buf += xfer_len;
if (blocks) {
blocks--;
}
if (!ll_sdhc_read_data_wait(hw, sdhost->data.timeout_ns/1000000))
{
os_printf("read dat timeout\r\n");
//while(1);
sdhost->data.err = DATA_DIR_READ;
}
if (ll_sdhc_get_rd_dat_err_pending(hw)) {
os_printf("read dat err pending\r\n");
sdhost->data.err = DATA_DIR_READ;
}
sd_dat_isr_get = 0;
} while (blocks);
#endif
ll_sdhc_8clk_ctrl(hw,sdhost->sd_8clk_open);
return 0;
}
int32 sdh_complete(struct sdh_device *sdhost)
{
#if DAT_ISR_EN
int res;
int ret = 0;
res = os_sema_down(&sdhost->dat_sema, 2000);
struct hgsdh *sdh_hw = (struct hgsdh*)sdhost;
struct hgsdh_hw *hw = (struct hgsdh_hw *)sdh_hw->hw;
if(sdhost->data.err != 0 || res == 0){
if(res == 0)
{
sdhost->sd_opt = SD_OFF;
}
ret = -1;
}
if(sdhost->sd_8clk_default) sdhost->sd_8clk_open = 1;
ll_sdhc_8clk_ctrl(hw,sdhost->sd_8clk_open);
#if TXW81X
if(sdhost->data.psram_flag && (sdhost->sd_opt == SD_M_R)&& !ret) hw_memcpy((void *)(sdhost->data.buf), (void *)sdhost->data.ping_buff[sdhost->data.ping_sel++], sdhost->data.blksize);
#endif
return ret;
#endif
}
//set the sdh config
int32 sdh_open(struct sdh_device *sdhost,uint8 bus_w)
{
struct hgsdh *sdh_hw = (struct hgsdh*)sdhost;
struct hgsdh_hw *hw = (struct hgsdh_hw *)sdh_hw->hw;
if (sdhost == 0) {
os_printf("mmcsd alloc host fail");
return 0;
}
sdh_hw->opened = 0;
SYSCTRL->SYS_CON1 &= ~(BIT(20));
delay_us(10);
SYSCTRL->SYS_CON1 |= (BIT(20));
sysctrl_sdhc_clk_open();
sdh_irq = sdhost;
/* set host default attributes */
sdhost->sd_8clk_default = 1;
sdhost->sd_8clk_open = sdhost->sd_8clk_default;
sdhost->freq_min = 400 * 1000;
#ifdef TXW81X
sdhost->freq_max = 50000000;
#else
sdhost->freq_max = 24000000;
#endif
sdhost->valid_ocr = 0x00FFFF80;/* The voltage range supported is 1.65v-3.6v */
#ifdef TXW81X
if(bus_w == 4)
sdhost->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ | MMCSD_SUP_HIGHSPEED;
else
sdhost->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ | MMCSD_SUP_HIGHSPEED;
#else
if(bus_w == 4)
sdhost->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
else
sdhost->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
#endif
sdhost->max_seg_size = 4096;
sdhost->max_dma_segs = 1;
sdhost->max_blk_size = 512;
sdhost->max_blk_count = 512;
sdhost->sd_stop = 0;
sdhost->sd_opt = SD_IDLE;
sdhost->new_lba = 0;
if(sdhost->dat_sema.hdl)
{
os_sema_del(&sdhost->dat_sema);
}
os_sema_init(&sdhost->dat_sema, 0);
/* link up host and sdio */
sdhost->private_data = 0;
sdhost->data.timeout_ns = 100000000; /* 100ms */
TYPE_LL_SDHC_CFG cfg;
cfg.bus_clk = sdhost->freq_min;
cfg.ioe = LL_SDHC_IROF;//LL_SDHC_IROF;
if(bus_w == 4)
cfg.width = LL_SDHC_DAT_4BIT;
else
cfg.width = LL_SDHC_DAT_1BIT;
ll_sdhc_config(sdhost,hw, &cfg);
#ifdef TXW81X
sdhost->data.ping_buff[0] = (uint32_t)sdhc_dat_ping_buf0;
sdhost->data.ping_buff[1] = (uint32_t)sdhc_dat_ping_buf1;
sdhost->data.ping_sel = 0;
sdhost->io_cfg.dat_overflow_stop_flag = 1;
sdhost->io_cfg.self_adaption_flag = 0;
#endif
hgic_sdc_irq_update(sdhost, 1);
NVIC_EnableIRQ(SDHOST_IRQn);
request_irq(SDHOST_IRQn, SDHOST_IRQHandler_action, (void*)sdhost);
return 0;
}
static void hgsdh_set_clock(struct sdh_device *sdhost, uint32_t clk)
{
struct hgsdh *sdh_hw = (struct hgsdh*)sdhost;
struct hgsdh_hw *hw = (struct hgsdh_hw *)sdh_hw->hw;
if (clk < sdhost->freq_min) {
clk = sdhost->freq_min;
}
if (clk > sdhost->freq_max) {
clk = sdhost->freq_max;
}
if (clk > 25000000) {
ll_sdhc_set_ioe(hw, LL_SDHC_IROR);
} else {
ll_sdhc_set_ioe(hw, LL_SDHC_IROF);
}
if (clk) {
ll_sdhc_set_bus_clk(hw, sys_get_apbclk(), clk);
}
}
static void hgsdh_set_bus_width(struct hgsdh_hw *p_sdhc, uint32 bus_width)
{
switch (bus_width)
{
case MMCSD_BUS_WIDTH_1:
ll_sdhc_set_dat_width(p_sdhc, LL_SDHC_DAT_1BIT);
break;
case MMCSD_BUS_WIDTH_4:
ll_sdhc_set_dat_width(p_sdhc, LL_SDHC_DAT_4BIT);
break;
case MMCSD_BUS_WIDTH_8:
os_printf("bus errr\r\n");
break;
default:
os_printf("no support bus width :%d\r\n", bus_width);
break;
}
}
static void hgsdh_set_sample(struct hgsdh_hw *p_sdhc, TYPE_LL_SDHC_SMP_CFG type, uint32_t cmd_smp, uint32_t dat_smp)
{
switch (type)
{
case LL_SDHC_ALL_SMP_CFG_DIS:
ll_sdhc_cmd_sample_enable(p_sdhc, 0);
ll_sdhc_dat_sample_enable(p_sdhc, 0);
ll_sdhc_set_sample(p_sdhc, 0, 0);
break;
case LL_SDHC_CMD_SMP_CFG_EN:
ll_sdhc_cmd_sample_enable(p_sdhc, 1);
ll_sdhc_set_sample(p_sdhc, cmd_smp, dat_smp);
break;
case LL_SDHC_DAT_SMP_CFG_EN:
ll_sdhc_dat_sample_enable(p_sdhc, 1);
ll_sdhc_set_sample(p_sdhc, cmd_smp, dat_smp);
break;
case LL_SDHC_ALL_SMP_CFG_EN:
ll_sdhc_cmd_sample_enable(p_sdhc, 1);
ll_sdhc_dat_sample_enable(p_sdhc, 1);
ll_sdhc_set_sample(p_sdhc, cmd_smp, dat_smp);
break;
default:
os_printf("sample type : %d err!\r\n", type);
break;
}
}
static void hgsdh_set_power_mode(uint8_t mode)
{
switch (mode)
{
case MMCSD_POWER_OFF:
break;
case MMCSD_POWER_UP:
break;
case MMCSD_POWER_ON:
break;
default:
os_printf("unknown power_mode %d", mode);
break;
}
}
int32 sdh_cfg(struct sdh_device *sdhost, struct rt_mmcsd_io_cfg *io_cfg)
{
struct hgsdh *sdh_hw = (struct hgsdh*)sdhost;
struct hgsdh_hw *hw = (struct hgsdh_hw *)sdh_hw->hw;
switch (io_cfg->ioctl_type)
{
case LL_SDHC_IOCTRL_SET_CLOCK:
hgsdh_set_clock(sdhost, io_cfg->clock);
io_cfg->crc_sample_max = sys_get_apbclk() / io_cfg->clock;
break;
case LL_SDHC_IOCTRL_SET_BUS_WIDTH:
hgsdh_set_bus_width(hw, io_cfg->bus_width);
break;
#ifdef TXW81X
case LL_SDHC_IOCTRL_SET_SMP:
hgsdh_set_sample(hw, io_cfg->smp_type, io_cfg->cmd_crc_sample, io_cfg->dat_crc_sample);
break;
case LL_SDHC_IOCTRL_SET_DELAY_TYPE:
(io_cfg->delay_flag) ? (ll_sdhc_delay_clock(hw, io_cfg->delay_type, io_cfg->delay_chain_cnt)) :
(ll_sdhc_delay_clock(hw, LL_SDHC_DLY_NONE, 0));
break;
case LL_SDHC_IOCTRL_SET_DAT_OF_STOP_CLK:
ll_sdhc_dat_overflow_stop_enable(hw, io_cfg->dat_overflow_stop_flag);
break;
#endif
case LL_SDHC_IOCTRL_SET_POWER_MODE:
hgsdh_set_power_mode(io_cfg->power_mode);
break;
default:
os_printf("err ioctrl_cmd : %d\r\n", io_cfg->ioctl_type);
break;
}
if(io_cfg->ioctl_type < LL_SDHC_IOCTRL_SET_SMP)
{
os_printf("clk:%d width:%s%s%s power:%s%s%s\r\n",
io_cfg->clock,
io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : ""
);
}
return 0;
}
int32 sdh_close(struct sdh_device *sdhost)
{
struct hgsdh *sdh_hw = (struct hgsdh*)sdhost;
struct hgsdh_hw *hw = (struct hgsdh_hw *)sdh_hw->hw;
ll_sdhc_close(hw);
sdh_hw->opened = 0;
sdh_hw->dsleep = 0;
sysctrl_sdhc_clk_close();
os_sema_del(&sdhost->dat_sema);
NVIC_DisableIRQ(SDHOST_IRQn);
pin_func(sdhost->dev.dev_id,0);
return 0;
}
#ifdef CONFIG_SLEEP
int32 sdh_suspend(struct sdh_device *sdhost)
{
struct hgsdh *sdh_hw = (struct hgsdh*)sdhost;
struct hgsdh_hw *hw = (struct hgsdh_hw *)sdh_hw->hw;
struct hgsdh_hw *hw_cfg;
if (!sdh_hw->opened || sdh_hw->dsleep)
{
return RET_OK;
}
if (os_mutex_lock(&sdhost->lock, osWaitForever))
{
return RET_ERR;
}
if (0 > os_mutex_lock(&sdhost->bp_suspend_lock, 10000))
{
return RET_ERR;
}
sysctrl_sdhc_clk_close();
sdhost->cfg_backup = (uint32 *)os_malloc(sizeof(struct hgsdh_hw));
//memcpy((uint8 *)sdhost->cfg_backup,(uint8 *)hw,sizeof(struct hgsdh_hw));
hw_cfg = (struct hgsdh_hw*)sdhost->cfg_backup;
hw_cfg->BAUD = hw->BAUD;
hw_cfg->CFG = hw->CFG;
hw_cfg->CPTR = hw->CPTR;
hw_cfg->DPTR = hw->DPTR;
hw_cfg->DCNT = hw->DCNT;
#ifdef TXW81X
hw_cfg->CFG1 = hw->CFG1;
hw_cfg->ISMP = hw->ISMP;
#endif
irq_disable(sdh_hw->irq_num);
sdh_hw->dsleep = 1;
os_mutex_unlock(&sdhost->bp_suspend_lock);
return 0;
}
int32 sdh_resume(struct sdh_device *sdhost)
{
struct hgsdh *sdh_hw = (struct hgsdh*)sdhost;
struct hgsdh_hw *hw = (struct hgsdh_hw *)sdh_hw->hw;
struct hgsdh_hw *hw_cfg;
if ((!sdh_hw->opened) || (!sdh_hw->dsleep)) {
return RET_OK;
}
if (0 > os_mutex_lock(&sdhost->bp_resume_lock, 10000))
{
return RET_ERR;
}
sysctrl_sdhc_clk_open();
hw_cfg = (struct hgsdh_hw*)sdhost->cfg_backup;
//memcpy((uint8 *)hw,(uint8 *)sdhost->cfg_backup,sizeof(struct hgsdh_hw));
hw->BAUD = hw_cfg->BAUD;
hw->CPTR = hw_cfg->CPTR;
hw->DPTR = hw_cfg->DPTR;
hw->DCNT = hw_cfg->DCNT;
hw->CFG = hw_cfg->CFG;
#ifdef TXW81X
hw->CFG1 = hw_cfg->CFG1;
hw->ISMP = hw_cfg->ISMP;
#endif
irq_enable(sdh_hw->irq_num);
os_free(sdhost->cfg_backup);
sdh_hw->dsleep = 0;
os_mutex_unlock(&sdhost->bp_resume_lock);
os_mutex_unlock(&sdhost->lock);
return 0;
}
#endif
void hgsdh_attach(uint32 dev_id, struct hgsdh *sdhost)
{
sdhost->dev.open = sdh_open;
sdhost->dev.close = sdh_close;
sdhost->dev.iocfg = sdh_cfg;
sdhost->dev.cmd = sdh_cmd;
sdhost->dev.write = sdh_write;
sdhost->dev.read = sdh_read;
sdhost->dev.complete = sdh_complete;
memset(&sdhost->dev.dat_sema,0,sizeof(sdhost->dev.dat_sema));
#ifdef CONFIG_SLEEP
sdhost->dev.suspend = sdh_suspend;
sdhost->dev.resume = sdh_resume;
os_mutex_init(&sdhost->dev.bp_suspend_lock);
os_mutex_init(&sdhost->dev.bp_resume_lock);
#endif
os_mutex_init(&sdhost->dev.lock);
irq_disable(sdhost->irq_num);
dev_register(dev_id, (struct dev_obj *)sdhost);
}