⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftsdc010.c

📁 SD卡驱动程序,是基于GM8180的体系的完整代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			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 + -