📄 ftsdc010.c
字号:
sd_err_code = ERR_DATA_TIMEOUT_ERROR; printk("%s() ERR_DATA_TIMEOUT_ERROR\n", __func__); return FALSE; } } #else unsigned long timeout = jiffies + SDC_GET_STATUS_RETRY_TIMEOUT_COUNT; while (time_before(jiffies, timeout)) { status = SDC_R_REG(SDC_STATUS_REG); if (status & SDC_STATUS_REG_DATA_CRC_OK) { P_DEBUGG("%s : receive data ok, status=0x%x\n", __func__, status); /* clear data CRC OK bit */ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_CRC_OK); return TRUE; } else if (status & SDC_STATUS_REG_DATA_CRC_FAIL) { /* clear data CRC fail bit */ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_CRC_FAIL); sd_err_code = ERR_DATA_CRC_ERROR; printk("%s() ERR_DATA_CRC_ERROR\n", __func__); return FALSE; } else if (status & SDC_STATUS_REG_DATA_TIMEOUT) { /* clear data timeout bit */ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT); sd_err_code = ERR_DATA_TIMEOUT_ERROR; printk("%s() ERR_DATA_TIMEOUT_ERROR\n", __func__); return FALSE; } } #endif P_DEBUG("%s() ERR_WAIT_DATA_CRC_TIMEOUT, status=0x%x\n", __func__, status); sd_err_code = ERR_WAIT_DATA_CRC_TIMEOUT; return FALSE;}static inline int sdc_check_data_end(void){ uint status; #ifndef CONFIG_FTSDC010_USE_TIMER_DELAY int count = 0; while (count++ < SDC_GET_STATUS_RETRY_COUNT) { status = SDC_R_REG(SDC_STATUS_REG); if (status & SDC_STATUS_REG_DATA_END) { SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_END); return TRUE; } else if (status & SDC_STATUS_REG_DATA_TIMEOUT) { /* clear data timeout bit */ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT); sd_err_code = ERR_DATA_TIMEOUT_ERROR; printk("%s() ERR_DATA_TIMEOUT_ERROR\n", __func__); return FALSE; } } #else unsigned long timeout = jiffies + SDC_GET_STATUS_RETRY_TIMEOUT_COUNT; while (time_before(jiffies, timeout)) { status = SDC_R_REG(SDC_STATUS_REG); if (status & SDC_STATUS_REG_DATA_END) { SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_END); return TRUE; } else if (status & SDC_STATUS_REG_DATA_TIMEOUT) { /* clear data timeout bit */ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT); sd_err_code = ERR_DATA_TIMEOUT_ERROR; printk("%s() ERR_DATA_TIMEOUT_ERROR\n", __func__); return FALSE; } } #endif sd_err_code = ERR_WAIT_TRANSFER_END_TIMEOUT; P_DEBUG("%s() ERR_WAIT_TRANSFER_END_TIMEOUT\n", __func__); return FALSE;}int sdc_set_bus_width_cmd(sd_card_t *info, uint width){ uint status; /* send CMD55 to indicate to the card that the next command is an application specific command */ if (!sdc_send_cmd(SD_APP_CMD | SDC_CMD_REG_NEED_RSP, (((uint)info->RCA) << 16), &status)) return FALSE; if (!sd_check_err(status)) return FALSE; /* send ACMD6 to set bus width */ if (!sdc_send_cmd(SD_SET_BUS_WIDTH_CMD | SDC_CMD_REG_APP_CMD | SDC_CMD_REG_NEED_RSP, width, &status)) return FALSE; if (!sd_check_err(status)) return FALSE; return TRUE;}int sdc_set_bus_width(sd_card_t *info){ uint width; /* if it is not SD card, it does not support wide bus */ if (info->CardType != MEMORY_CARD_TYPE_SD) return TRUE; /* get SCR register */ if (!sd_get_scr(info, (uint *) &info->SCR)) return FALSE; /* if host controller does not support wide bus, return */ if ((SDC_R_REG(SDC_BUS_WIDTH_REG) & SDC_WIDE_BUS_SUPPORT) != SDC_WIDE_BUS_SUPPORT) return TRUE; if (!sd_set_transfer_state(info)) return FALSE; if (info->SCR.SD_BUS_WIDTH & SD_SCR_4_BIT_BIT) width = SD_BUS_WIDTH_4_BIT; else width = SD_BUS_WIDTH_1_BIT; if (!sdc_set_bus_width_cmd(info, width)) return FALSE; if (width == SD_BUS_WIDTH_1_BIT) SDC_W_REG(SDC_BUS_WIDTH_REG, SDC_BUS_WIDTH_REG_SINGLE_BUS); else SDC_W_REG(SDC_BUS_WIDTH_REG, SDC_BUS_WIDTH_REG_WIDE_BUS); return TRUE;}static inline int sdc_pre_erase_cmd(uint nr_blocks){ uint status; sd_card_t *info=&sd_card_info; /* send CMD55 to indicate to the card that the next command is an application specific command */ if (!sdc_send_cmd(SD_APP_CMD | SDC_CMD_REG_NEED_RSP, (((uint)info->RCA) << 16), &status)) return FALSE; if (!sd_check_err(status)) return FALSE; /* send ACMD6 to set bus width */ if (!sdc_send_cmd(23 | SDC_CMD_REG_APP_CMD | SDC_CMD_REG_NEED_RSP, nr_blocks, &status)) return FALSE; if (!sd_check_err(status)) return FALSE; return TRUE;}uint sdc_set_bus_clock(sd_card_t *info, uint clock){ uint div = 0, reg; while (clock < (info->SysFrequency / (2 * (div + 1)))) div++; /* write clock divided */ reg = SDC_R_REG(SDC_CLOCK_CTRL_REG); reg &= (~SDC_CLOCK_REG_CLK_DIV | 0x80); //ijsung: preserv SD or MMC reg += div & SDC_CLOCK_REG_CLK_DIV; SDC_W_REG(SDC_CLOCK_CTRL_REG, reg); P_DEBUG("%s: SD clock=%d, info->SysFrequency=%d, div=%d\n",__func__,clock, info->SysFrequency, div); return info->SysFrequency / (2 * (div + 1));}static inline int sdc_set_block_size(uint size){ uint status; static uint last_size=0; if (size == last_size) return TRUE; else last_size=size; if (!sdc_send_cmd(SD_SET_BLOCKLEN_CMD | SDC_CMD_REG_NEED_RSP, size, &status)) return FALSE; if (!sd_check_err(status)) return FALSE; return TRUE;}void sdc_set_card_type(int type){ uint reg; reg = SDC_R_REG(SDC_CLOCK_CTRL_REG); reg &= ~SDC_CLOCK_REG_CARD_TYPE; if (type == MEMORY_CARD_TYPE_SD) { reg |= SDC_CARD_TYPE_SD; } else { reg |= SDC_CARD_TYPE_MMC; } SDC_W_REG(SDC_CLOCK_CTRL_REG, reg);}#ifdef CONFIG_FTSDC010_USE_AHBDMAstatic void sdc_ahbdma_timeout_handler(unsigned long data) { u32 int_status = fa_ahb_dma_get_status(SD_DMA_CHANNEL); if ( (int_status&INT_DMA_ERROR) || (int_status&INT_DMA_ABORT) ) { printk(KERN_ERR "AHB DMA response Error/Abort. SD has something wrong\n"); sd_err_code = ERR_APBDMA_RSP_ERROR; wake_up_interruptible(&sd_dma_queue); return; } else if (!int_status) { printk(KERN_ERR "AHB DMA Time out\n"); sd_err_code = ERR_DATA_TIMEOUT_ERROR; wake_up_interruptible(&sd_dma_queue); return; } printk(KERN_WARNING "Time out but DMA finish\n"); wake_up_interruptible(&sd_dma_queue);}#endif#ifdef CONFIG_FTSDC010_USE_APBDMA#ifndef CONFIG_FTSDC010_USE_APBDMA_POLLstatic void sdc_apbdma_timeout_handler(unsigned long data) { u32 int_status = fa_apb_dma_get_status(SD_DMA_CHANNEL); if (int_status&INT_DMA_ERROR) { printk(KERN_ERR "APB DMA response Error. SD has something wrong\n"); sd_err_code = ERR_APBDMA_RSP_ERROR; } else if (!int_status) { printk(KERN_ERR "APB DMA Time out, status=0x%x\n",int_status); sd_err_code = ERR_DATA_TIMEOUT_ERROR; } if(sync_mode) wake_up_interruptible(&sd_dma_queue);}#endif#endifint sdc_read_block(sd_card_t *info, uint size, uint *buf){ /* * Please refer SanDisk SD Manual v1.9 Section 5.1.9.2 (page 5-76) to set the timeout setting */ #ifdef CONFIG_FTSDC010_USE_AHBDMA unsigned long timeout = jiffies + SDC_TIMEOUT_BASE*((size+511)>>9); struct timer_list to_timer; #endif #ifdef CONFIG_FTSDC010_USE_APBDMA unsigned long timeout = jiffies + SDC_TIMEOUT_BASE*((size+511)>>9); #ifdef CONFIG_FTSDC010_USE_APBDMA_POLL int sd_time_out=0; #else struct timer_list to_timer; #endif #endif uint count, i; //unsigned char *tmp;#ifdef CONFIG_FTSDC010_USE_APBDMA#if 0 tmp = buf; for(i=0;i< size;i++,tmp++) *tmp=0x5a; consistent_sync(buf, size, DMA_TO_DEVICE);#endif if ((info->DMAEnable) && (size >= (SDC_READ_FIFO_LEN * 4))) { P_DEBUG("%s:size=%d, buf=%p) - DMA Read\n", __func__, size,buf ); P_DEBUG("dma_buf = %d\n", dma_buf); //prepare parameter for add dma entry parm.src = FTSDC_PA_BASE + SDC_DATA_WINDOW_REG; // given source phy addr if (dma_buf) parm.dest = dma_buf; // given dest phy addr else parm.dest = __pa(buf); parm.width = APBDMA_WIDTH_32BIT; // data width of transfer parm.s_req_num = SDC_APBDMA_CHAL; // source hardware request number parm.d_req_num = 0; // destination hardware request number parm.sctl = APBDMA_CTL_FIX; // source address increment parm.dctl = APBDMA_CTL_INC16; // destination address increment parm.stype = APBDMA_TYPE_APB; // indicate source device, AHB or APB parm.dtype = APBDMA_TYPE_AHB; // indicate destinate device, AHB of APB parm.size = size >> 4; // transfer count (DMA transfer count) // total transer size is parm.size*parm.width*parm.burst(0/1=>1/4) // here each DMA transfer tx/rx 16 bytes data. parm.burst = TRUE; // yes/no burst parm.irq = APBDMA_TRIGGER_IRQ_WITH_ERROR; // trigger irq enable/disable fa_set_apb_dma_params(SD_DMA_CHANNEL, &parm); // call add function if (dma_buf) consistent_sync(__va(dma_buf), size, DMA_FROM_DEVICE); else consistent_sync(buf, size, DMA_FROM_DEVICE); #ifndef CONFIG_FTSDC010_USE_APBDMA_POLL /* Set up time out timer */ init_timer(&to_timer); to_timer.expires = timeout; to_timer.function = sdc_apbdma_timeout_handler; to_timer.data = (unsigned long) info; add_timer(&to_timer); /* Start DMA */ fa_apb_dma_start(SD_DMA_CHANNEL); interruptible_sleep_on(&sd_dma_queue); //printk("c=%x:g=%x\n",fa_apb_dma_get_cycle(SD_DMA_CHANNEL),fa_apb_dma_get_status(SD_DMA_CHANNEL)); //wait_event_interruptible_timeout(sd_dma_queue, !fa_apb_dma_get_cycle(SD_DMA_CHANNEL), SDC_TIMEOUT_BASE*((size+511)>>9)); //wait_event_interruptible_timeout(sd_dma_queue,fa_apb_dma_get_status(SD_DMA_CHANNEL) != INT_DMA_TRIGGER, SDC_TIMEOUT_BASE*((size+511)>>9)); /* clean up the timeout timer */ del_timer_sync(&to_timer); #else /* Start DMA */ fa_apb_dma_start(SD_DMA_CHANNEL); while( (i=fa_apb_dma_get_status(SD_DMA_CHANNEL)) == 0 ) { if ( time_after(jiffies, timeout) ) { sd_time_out=1; break; } } if ( sd_time_out == 1 ) { sd_err_code = ERR_DATA_TIMEOUT_ERROR; P_DEBUG("SD_Rx: APB DMA Rx Time-out\n"); } else if ( i&INT_DMA_ERROR ) { sd_err_code = ERR_APBDMA_RSP_ERROR; P_DEBUG(KERN_ERR "SD_Rx: APB DMA Error\n"); } else if ( i&INT_DMA_TRIGGER ) { P_DEBUG("SD_Rx: APB DMA Finish\n"); } #endif if ( sd_err_code == ERR_DATA_TIMEOUT_ERROR ) { printk("SD_Rx: APB DMA Rx Time-out\n"); //printk("dest=%x,size=%x\n",buf,size); } /* Stop DMA */ fa_apb_dma_stop(SD_DMA_CHANNEL); fa_apb_dma_reset(SD_DMA_CHANNEL); P_DEBUG("DMA Read interruptible_sleep_on()\n"); } else#endif#ifdef CONFIG_FTSDC010_USE_AHBDMA if ((info->DMAEnable) && (size >= (SDC_READ_FIFO_LEN * 4))) { P_DEBUG("%s:size=%d, buf=%p) - DMA Read\n", __func__, size,buf ); if (dma_buf) parm.dest = dma_buf; else parm.dest = __pa(buf); fa_set_ahb_dma_src_params(SD_DMA_CHANNEL, FTSDC_PA_BASE + SDC_DATA_WINDOW_REG , AHBDMA_MASTER_0, 2, 2); fa_set_ahb_dma_dst_params(SD_DMA_CHANNEL, parm.dest, AHBDMA_MASTER_0, 2, 0); fa_set_ahb_dma_transfer_bs(SD_DMA_CHANNEL, 1); //set burst fa_set_ahb_dma_transfer_params2(SD_DMA_CHANNEL, AHBDMA_MASTER_0, size, 1); fa_ahb_dma_init(SD_DMA_CHANNEL, 7); fa_ahb_dma_add_auto(SD_DMA_CHANNEL, size); if (dma_buf) consistent_sync(__va(dma_buf), size, DMA_FROM_DEVICE); else consistent_sync(buf, size, DMA_FROM_DEVICE); /* Set up time out timer */ init_timer(&to_timer); to_timer.expires = timeout; to_timer.function = sdc_ahbdma_timeout_handler; to_timer.data = (unsigned long) info; add_timer(&to_timer); /* Start DMA */ fa_ahb_dma_start(SD_DMA_CHANNEL); //interruptible_sleep_on(&sd_dma_queue); wait_event_interruptible_timeout(sd_dma_queue, fa_ahb_dma_all_done(SD_DMA_CHANNEL), SDC_TIMEOUT_BASE*((size+511)>>9)); P_DEBUG("DMA Read sleep_on()\n"); /* clean up the timeout timer */ del_timer_sync(&to_timer); /* Stop DMA */ fa_ahb_dma_stop(SD_DMA_CHANNEL); fa_ahb_dma_reset(SD_DMA_CHANNEL); } else#endif { while (size > 0) { if (!sdc_check_rx_ready()) { printk("error...........\n"); return FALSE; } /* read data from FIFO */ if (size >= (SDC_READ_FIFO_LEN << 2)) count = SDC_READ_FIFO_LEN; else count = size >> 2; /* read data from FIFO */ P_DEBUG("\n"); for (i = 1; i <= count; i++, buf++) { *buf = SDC_R_REG(SDC_DATA_WINDOW_REG); P_DEBUG("%.8x ",*buf); } size -= (count << 2); } } return sdc_check_data_crc();}int sdc_write_block(sd_card_t *info, uint size, uint *buf){ #ifdef CONFIG_FTSDC010_USE_AHBDMA unsigned long timeout = jiffies + SDC_TIMEOUT_BASE*3*((size+511)>>9); struct timer_list to_timer; #endif #ifdef CONFIG_FTSDC010_USE_APBDMA unsigned long timeout = jiffies + SDC_TIMEOUT_BASE*3*((size+511)>>9); #ifdef CONFIG_FTSDC010_USE_APBDMA_POLL int sd_time_out=0; #else struct timer_list to_timer; #endif #endif uint count, i;#ifdef CONFIG_FTSDC010_USE_APBDMA //CONFIG_FTSDC010_USE_APBDMA if (info->DMAEnable) { P_DEBUG("%s:size=%d, buf=%p) - DMA Write\n", __func__, size,buf ); if (dma_buf) parm.src = dma_buf; else parm.src = __pa(buf); parm.dest = FTSDC_PA_BASE + SDC_DATA_WINDOW_REG; parm.width = APBDMA_WIDTH_32BIT; parm.d_req_num = 0; parm.s_req_num = SDC_APBDMA_CHAL; parm.sctl = APBDMA_CTL_INC16; parm.dctl = APBDMA_CTL_FIX; parm.stype = APBDMA_TYPE_AHB; parm.dtype = APBDMA_TYPE_APB;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -