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

📄 mmc_asic3.c

📁 三星公司ARM芯片S3C2410 SD/MMC LINUX 驱动程序源码。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Low-level MMC/SD functions for the ASIC3 MMC/SD Controller * * Use consistent with the GNU GPL is permitted, * provided that this copyright notice is * preserved in its entirety in all copies and derived works. * * Some parts of code based on iPAQ 3800 MMC driver code * * Author: Pawel Kolodziejski (aquadran) * * comments: * - initilise card procedure fail sometimes for my MMC card, * - add code for handle interrupt card detection (removal, insertion). * - add code for support PM. * - multi block mode not tested (MMC core driver doesn't support it) * - 3900 must disable bus host clock, and use asic2 MMC clock */#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/proc_fs.h>#include <linux/delay.h>#include <asm/unaligned.h>#include <asm/arch/hardware.h>#include <asm/arch/h3900_asic.h>#include <linux/mmc/mmc_ll.h>struct response_info {	int length;	u16 cdc_flags;};static struct response_info rinfo[] = {        { 0,  SD_CTRL_COMMAND_RESPONSE_TYPE_NORMAL  }, // R0        { 5,  SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1  }, // R1        { 5,  SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1B }, // R1b        { 16, SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R2  }, // R2        { 16, SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R2  }, // R2        { 5,  SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R3  }, // R3        { 5,  SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R3  }, // R4        { 5,  SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R3  }, // R5        { 5,  SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R3  }, // R6};struct mmc_data {	struct mmc_request *request;	int                flag;};static struct mmc_data g_data;#ifdef CONFIG_MMC_DEBUGstruct cmd_to_name {	int   id;	char *name;};static struct cmd_to_name cmd_names[] = {	{ MMC_CIM_RESET, "CIM_RESET" },	{ MMC_GO_IDLE_STATE, "GO_IDLE_STATE" },	{ MMC_SEND_OP_COND, "SEND_OP_COND" },	{ MMC_ALL_SEND_CID, "ALL_SEND_CID" },	{ MMC_SET_RELATIVE_ADDR, "SET_RELATIVE_ADDR" },	{ MMC_SET_DSR, "SET_DSR" },	{ MMC_SELECT_CARD, "SELECT_CARD" },	{ MMC_SEND_CSD, "SEND_CSD" },	{ MMC_SEND_CID, "SEND_CID" },	{ MMC_READ_DAT_UNTIL_STOP, "READ_DAT_UNTIL_STOP" },	{ MMC_STOP_TRANSMISSION, "STOP_TRANSMISSION" },	{ MMC_SEND_STATUS	, "SEND_STATUS	" },	{ MMC_GO_INACTIVE_STATE, "GO_INACTIVE_STATE" },	{ MMC_SET_BLOCKLEN, "SET_BLOCKLEN" },	{ MMC_READ_SINGLE_BLOCK, "READ_SINGLE_BLOCK" },	{ MMC_READ_MULTIPLE_BLOCK, "READ_MULTIPLE_BLOCK" },	{ MMC_WRITE_DAT_UNTIL_STOP, "WRITE_DAT_UNTIL_STOP" },	{ MMC_SET_BLOCK_COUNT, "SET_BLOCK_COUNT" },	{ MMC_WRITE_BLOCK, "WRITE_BLOCK" },	{ MMC_WRITE_MULTIPLE_BLOCK, "WRITE_MULTIPLE_BLOCK" },	{ MMC_PROGRAM_CID, "PROGRAM_CID" },	{ MMC_PROGRAM_CSD, "PROGRAM_CSD" },	{ MMC_SET_WRITE_PROT, "SET_WRITE_PROT" },	{ MMC_CLR_WRITE_PROT, "CLR_WRITE_PROT" },	{ MMC_SEND_WRITE_PROT, "SEND_WRITE_PROT" },	{ MMC_ERASE_GROUP_START, "ERASE_GROUP_START" },	{ MMC_ERASE_GROUP_END, "ERASE_GROUP_END" },	{ MMC_ERASE, "ERASE" },	{ MMC_FAST_IO, "FAST_IO" },	{ MMC_GO_IRQ_STATE, "GO_IRQ_STATE" },	{ MMC_LOCK_UNLOCK, "LOCK_UNLOCK" },	{ MMC_APP_CMD, "APP_CMD" },	{ MMC_GEN_CMD, "GEN_CMD" },	{ SD_APP_OP_COND, "SD_APP_OP_COND" },	{ SD_APP_SET_BUS_WIDTH, "SD_APP_SET_BUS_WIDTH" },};static char *get_cmd_name(int cmd){	int i;	int len = sizeof(cmd_names) / sizeof(struct cmd_to_name);	for (i = 0 ; i < len ; i++)		if ( cmd == cmd_names[i].id)			return cmd_names[i].name;	return "UNKNOWN";}#endif /* CONFIG_MMC_DEBUG */static void mmc_asic3_stop_clock(void){	H3900_ASIC3_SD_CTRL_CardClockCtrl = 0; // disable clock}static void mmc_asic3_start_clock(void){	H3900_ASIC3_SD_CONFIG_ClockMode = CLOCK_MODE_DIV_CLOCK_DISABLE; // disable div rate clock	H3900_ASIC3_SD_CTRL_CardClockCtrl = SD_CTRL_CARDCLOCKCONTROL_ENABLE_CLOCK;	if (g_data.flag == 1)	    	H3900_ASIC3_SD_CTRL_CardClockCtrl |= SD_CTRL_CARDCLOCKCONTROL_FOR_SD_CARD;	mdelay(1);}static int mmc_asic3_set_clock(u32 rate){	H3900_ASIC3_SD_CONFIG_ClockMode = CLOCK_MODE_DIV_CLOCK_DISABLE; // disable div rate clock	H3900_ASIC3_SD_CTRL_CardClockCtrl = SD_CTRL_CARDCLOCKCONTROL_ENABLE_CLOCK;	if (g_data.flag == 1)    		H3900_ASIC3_SD_CTRL_CardClockCtrl |= SD_CTRL_CARDCLOCKCONTROL_FOR_SD_CARD;	mdelay(1);	return MMC_NO_ERROR;}static int mmc_asic3_reset_asic(void){	if (machine_is_h3900()) {		H3800_ASIC2_CLOCK_Enable |= ASIC2_CLOCK_SD_2;  // 24.576 Mhz		H3900_ASIC3_CLOCK_CDEX |= CLOCK_CDEX_EX0;		mdelay(1);		/* Enable the host clock */		H3900_ASIC3_CLOCK_SEL    |= CLOCK_SEL_SD_HCLK_SEL;		H3900_ASIC3_CLOCK_SEL    &= ~CLOCK_SEL_SD_BCLK_SEL;		H3900_ASIC3_CLOCK_CDEX   |= CLOCK_CDEX_SD_HOST;		H3900_ASIC3_CLOCK_CDEX   &= ~CLOCK_CDEX_SD_BUS;		mdelay(1);	}        H3900_ASIC3_CLOCK_CDEX |= CLOCK_CDEX_EX1;	mdelay(1);	H3900_ASIC3_EXTCF_Select |= ASIC3_EXTCF_SD_MEM_ENABLE; // enable possibility SD/MMC card in CF slot ?	H3900_ASIC3_SDHWCTRL_SDConf &= ~(ASIC3_SDHWCTRL_SUSPEND | ASIC3_SDHWCTRL_PCLR); // wake up	mdelay(10);	H3900_ASIC3_SD_CONFIG_Addr0 = 0x0800; // offset to host controller	H3900_ASIC3_SD_CONFIG_Addr1 = 0x0000;	H3900_ASIC3_SD_CONFIG_ClkStop = SD_CONFIG_CLKSTOP_ENABLE_ALL; // setup stop clock (i think)	H3900_ASIC3_SD_CONFIG_SDHC_CardDetect = 2; // two cycles (possible 512ms)	H3900_ASIC3_SD_CONFIG_Command = SD_CONFIG_COMMAND_MAE; // access to control registers enabled	H3900_ASIC3_SD_CTRL_SoftwareReset = 0;	mdelay(2);	H3900_ASIC3_SD_CTRL_SoftwareReset = 1;	mdelay(2);	H3900_ASIC3_SDIO_CTRL_SoftwareReset = 0;	mdelay(2);	H3900_ASIC3_SDIO_CTRL_SoftwareReset = 1;	mdelay(2);	H3900_ASIC3_SD_CTRL_IntMaskCard = 0x0; // mask all interrupts, they are not used	H3900_ASIC3_SD_CTRL_IntMaskBuffer = 0x0; //       --- // ---	H3900_ASIC3_SDHWCTRL_SDConf &= ~ASIC3_SDHWCTRL_PCLR; // clear all SDIO registers	H3900_ASIC3_SD_CTRL_MemCardOptionSetup = MEM_CARD_OPTION_REQUIRED |						MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(14) |						MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT |						MEM_CARD_OPTION_DATA_XFR_WIDTH_1;	H3900_ASIC3_SD_CTRL_ErrorStatus0 = 0; // clear detail error status register	H3900_ASIC3_SD_CTRL_ErrorStatus1 = 0; //       --- // ---	H3900_ASIC3_SD_CTRL_CardStatus = 0; // clear card status	H3900_ASIC3_SD_CTRL_BufferCtrl = 0; // clear buffer controller status	H3900_ASIC3_SD_CTRL_StopInternal = 0; // clear stop transfer register	H3900_ASIC3_SDIO_CTRL_ClocknWaitCtrl = 0x0100; // setup clock for SDIO	H3900_ASIC3_SDHWCTRL_SDConf |= ASIC3_SDHWCTRL_SDPWR; // turn on power at controller(?)	mdelay(10);	H3900_ASIC3_SD_CONFIG_SDHC_Power3 = 0; // turn off auto power down after card remove	H3900_ASIC3_SD_CONFIG_SDHC_Power1 = SD_CONFIG_POWER1_PC_33V; 	// turn on power to card,									// turn off auto power up after card inserted	mdelay(10);	H3900_ASIC3_SD_CONFIG_ClockMode = CLOCK_MODE_DIV_CLOCK_ENABLE; // enable div clock for change rate	H3900_ASIC3_SD_CTRL_CardClockCtrl = 0; // reset card clock ?	H3900_ASIC3_SD_CTRL_CardClockCtrl = SD_CTRL_CARDCLOCKCONTROL_ENABLE_CLOCK | SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_64;	mdelay(1);	MMC_DEBUG(0, "Card status 0x%04x\n", H3900_ASIC3_SD_CTRL_CardStatus);	MMC_DEBUG(0, "Buffer status 0x%04x\n", H3900_ASIC3_SD_CTRL_BufferCtrl);	g_data.flag = 0;	return MMC_NO_ERROR;}static void mmc_asic3_set_command(u16 cmd, u32 arg){	MMC_DEBUG(1, "cmd=%d arg=0x%08x", cmd, arg);	H3900_ASIC3_SD_CTRL_Arg1 = arg >> 16;	H3900_ASIC3_SD_CTRL_Arg0 = arg & 0xffff;	H3900_ASIC3_SD_CTRL_Cmd = cmd;}static void mmc_asic3_set_transfer(u16 block_len, u16 nob){	MMC_DEBUG(1, "block_len=%d nob=%d", block_len, nob);	H3900_ASIC3_SD_CTRL_MemCardXferDataLen = block_len;	// size of block (default 512 bytes)	H3900_ASIC3_SD_CTRL_TransferSectorCount = nob;		// number blocks to transfer}static void mmc_asic3_transmit_data(struct mmc_request *request){	u8 *buf = request->buffer;	u16 data;	int i;	MMC_DEBUG(1, "nob=%d block_len=%d", request->nob, request->block_len);	if (request->nob <= 0) {		MMC_DEBUG(1, "*** nob already at 0 ***");		return;	}	for (i = 0; i < request->block_len; i += 2, buf += 2) {		data = ((u16) *buf) | (*(buf + 1) << 8);		H3900_ASIC3_SD_CTRL_DataPort = data; // write two bytes to SD/MMC controller buffer	}	START_MMC_DEBUG(3) {		u8 *b = request->buffer;		for (i = 0 ; i < request->block_len ; i++) {			printk(" %02x", *b++);			if (((i + 1) % 16) == 0)				printk("\n");		}	} END_MMC_DEBUG;	// Updated the request buffer to reflect the current state	request->buffer = (u8 *)buf;	request->nob--;}static void mmc_asic3_receive_data(struct mmc_request *request){	u8 *buf = request->buffer;	u16 data;	int i;	MMC_DEBUG(1, "nob=%d block_len=%d buf=%p", request->nob, request->block_len, buf);	if (request->nob <= 0) {		MMC_DEBUG(1, "*** nob already at 0 ***");		return;	}	for (i = 0; i < request->block_len; i += 2) {		data = H3900_ASIC3_SD_CTRL_DataPort; // read two bytes from SD/MMC controller buffer		*buf++ = data & 0xff;		*buf++ = data >> 8;	}	START_MMC_DEBUG(3) {		u8 *b = request->buffer;		for (i = 0; i < request->block_len ; i++) {			printk(" %02x", *b++);			if ( ((i + 1) % 16) == 0 )				printk("\n");		}	} END_MMC_DEBUG;	// Updated the request buffer to reflect the current state 	request->buffer = (u8 *)buf;	request->nob--;}static void mmc_asic3_get_response(struct mmc_request *request){	int i, len = rinfo[request->rtype].length;	u8 *buf = request->response;	u16 data;	request->result = MMC_NO_ERROR;    // Mark this as having a request result of some kind	if (len <= 0) {		MMC_DEBUG(1, "no response");		return;	}	if (len > 5) { // R2 handle		data = H3900_ASIC3_SD_CTRL_Response7;		buf[0] = 0x3f;		buf[1] = data & 0xff;		data = H3900_ASIC3_SD_CTRL_Response6;		buf[2] = data >> 8;		buf[3] = data & 0xff;		data = H3900_ASIC3_SD_CTRL_Response5;		buf[4] = data >> 8;		buf[5] = data & 0xff;		data = H3900_ASIC3_SD_CTRL_Response4;		buf[6] = data >> 8;		buf[7] = data & 0xff;		data = H3900_ASIC3_SD_CTRL_Response3;		buf[8] = data >> 8;		buf[9] = data & 0xff;		data = H3900_ASIC3_SD_CTRL_Response2;		buf[10] = data >> 8;		buf[11] = data & 0xff;		data = H3900_ASIC3_SD_CTRL_Response1;		buf[12] = data >> 8;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -