mmc.c

来自「最新版的u-boot,2008-10-18发布」· C语言 代码 · 共 663 行 · 第 1/2 页

C
663
字号
/* * (C) Copyright 2003 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */#include <config.h>#include <common.h>#include <mmc.h>#include <asm/errno.h>#include <asm/arch/hardware.h>#include <part.h>#ifdef CONFIG_MMCextern int fat_register_device(block_dev_desc_t * dev_desc, int part_no);static block_dev_desc_t mmc_dev;block_dev_desc_t *mmc_get_dev(int dev){	return ((block_dev_desc_t *) & mmc_dev);}/* * FIXME needs to read cid and csd info to determine block size * and other parameters */static uchar mmc_buf[MMC_BLOCK_SIZE];static uchar spec_ver;static int mmc_ready = 0;static int wide = 0;static uint32_t */****************************************************/mmc_cmd(ushort cmd, ushort argh, ushort argl, ushort cmdat)/****************************************************/{	static uint32_t resp[4], a, b, c;	ulong status;	int i;	debug("mmc_cmd %u 0x%04x 0x%04x 0x%04x\n", cmd, argh, argl,	      cmdat | wide);	MMC_STRPCL = MMC_STRPCL_STOP_CLK;	MMC_I_MASK = ~MMC_I_MASK_CLK_IS_OFF;	while (!(MMC_I_REG & MMC_I_REG_CLK_IS_OFF)) ;	MMC_CMD = cmd;	MMC_ARGH = argh;	MMC_ARGL = argl;	MMC_CMDAT = cmdat | wide;	MMC_I_MASK = ~MMC_I_MASK_END_CMD_RES;	MMC_STRPCL = MMC_STRPCL_START_CLK;	while (!(MMC_I_REG & MMC_I_REG_END_CMD_RES)) ;	status = MMC_STAT;	debug("MMC status 0x%08x\n", status);	if (status & MMC_STAT_TIME_OUT_RESPONSE) {		return 0;	}	/* Linux says:	 * Did I mention this is Sick.  We always need to	 * discard the upper 8 bits of the first 16-bit word.	 */	a = (MMC_RES & 0xffff);	for (i = 0; i < 4; i++) {		b = (MMC_RES & 0xffff);		c = (MMC_RES & 0xffff);		resp[i] = (a << 24) | (b << 8) | (c >> 8);		a = c;		debug("MMC resp[%d] = %#08x\n", i, resp[i]);	}	return resp;}int/****************************************************/mmc_block_read(uchar * dst, ulong src, ulong len)/****************************************************/{	ushort argh, argl;	ulong status;	if (len == 0) {		return 0;	}	debug("mmc_block_rd dst %lx src %lx len %d\n", (ulong) dst, src, len);	argh = len >> 16;	argl = len & 0xffff;	/* set block len */	mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1);	/* send read command */	argh = src >> 16;	argl = src & 0xffff;	MMC_STRPCL = MMC_STRPCL_STOP_CLK;	MMC_RDTO = 0xffff;	MMC_NOB = 1;	MMC_BLKLEN = len;	mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, argh, argl,		MMC_CMDAT_R1 | MMC_CMDAT_READ | MMC_CMDAT_BLOCK |		MMC_CMDAT_DATA_EN);	MMC_I_MASK = ~MMC_I_MASK_RXFIFO_RD_REQ;	while (len) {		if (MMC_I_REG & MMC_I_REG_RXFIFO_RD_REQ) {#ifdef CONFIG_PXA27X			int i;			for (i = min(len, 32); i; i--) {				*dst++ = *((volatile uchar *)&MMC_RXFIFO);				len--;			}#else			*dst++ = MMC_RXFIFO;			len--;#endif		}		status = MMC_STAT;		if (status & MMC_STAT_ERRORS) {			printf("MMC_STAT error %lx\n", status);			return -1;		}	}	MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE;	while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE)) ;	status = MMC_STAT;	if (status & MMC_STAT_ERRORS) {		printf("MMC_STAT error %lx\n", status);		return -1;	}	return 0;}int/****************************************************/mmc_block_write(ulong dst, uchar * src, int len)/****************************************************/{	ushort argh, argl;	ulong status;	if (len == 0) {		return 0;	}	debug("mmc_block_wr dst %lx src %lx len %d\n", dst, (ulong) src, len);	argh = len >> 16;	argl = len & 0xffff;	/* set block len */	mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1);	/* send write command */	argh = dst >> 16;	argl = dst & 0xffff;	MMC_STRPCL = MMC_STRPCL_STOP_CLK;	MMC_NOB = 1;	MMC_BLKLEN = len;	mmc_cmd(MMC_CMD_WRITE_BLOCK, argh, argl,		MMC_CMDAT_R1 | MMC_CMDAT_WRITE | MMC_CMDAT_BLOCK |		MMC_CMDAT_DATA_EN);	MMC_I_MASK = ~MMC_I_MASK_TXFIFO_WR_REQ;	while (len) {		if (MMC_I_REG & MMC_I_REG_TXFIFO_WR_REQ) {			int i, bytes = min(32, len);			for (i = 0; i < bytes; i++) {				MMC_TXFIFO = *src++;			}			if (bytes < 32) {				MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL;			}			len -= bytes;		}		status = MMC_STAT;		if (status & MMC_STAT_ERRORS) {			printf("MMC_STAT error %lx\n", status);			return -1;		}	}	MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE;	while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE)) ;	MMC_I_MASK = ~MMC_I_MASK_PRG_DONE;	while (!(MMC_I_REG & MMC_I_REG_PRG_DONE)) ;	status = MMC_STAT;	if (status & MMC_STAT_ERRORS) {		printf("MMC_STAT error %lx\n", status);		return -1;	}	return 0;}int/****************************************************/mmc_read(ulong src, uchar * dst, int size)/****************************************************/{	ulong end, part_start, part_end, part_len, aligned_start, aligned_end;	ulong mmc_block_size, mmc_block_address;	if (size == 0) {		return 0;	}	if (!mmc_ready) {		printf("Please initial the MMC first\n");		return -1;	}	mmc_block_size = MMC_BLOCK_SIZE;	mmc_block_address = ~(mmc_block_size - 1);	src -= CFG_MMC_BASE;	end = src + size;	part_start = ~mmc_block_address & src;	part_end = ~mmc_block_address & end;	aligned_start = mmc_block_address & src;	aligned_end = mmc_block_address & end;	/* all block aligned accesses */	debug	    ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",	     src, (ulong) dst, end, part_start, part_end, aligned_start,	     aligned_end);	if (part_start) {		part_len = mmc_block_size - part_start;		debug		    ("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",		     src, (ulong) dst, end, part_start, part_end, aligned_start,		     aligned_end);		if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) <		    0) {			return -1;		}		memcpy(dst, mmc_buf + part_start, part_len);		dst += part_len;		src += part_len;	}	debug	    ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",	     src, (ulong) dst, end, part_start, part_end, aligned_start,	     aligned_end);	for (; src < aligned_end; src += mmc_block_size, dst += mmc_block_size) {		debug		    ("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",		     src, (ulong) dst, end, part_start, part_end, aligned_start,		     aligned_end);		if ((mmc_block_read((uchar *) (dst), src, mmc_block_size)) < 0) {			return -1;		}	}	debug	    ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",	     src, (ulong) dst, end, part_start, part_end, aligned_start,	     aligned_end);	if (part_end && src < end) {		debug		    ("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",		     src, (ulong) dst, end, part_start, part_end, aligned_start,		     aligned_end);		if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) {			return -1;		}		memcpy(dst, mmc_buf, part_end);	}	return 0;}int/****************************************************/mmc_write(uchar * src, ulong dst, int size)/****************************************************/{	ulong end, part_start, part_end, part_len, aligned_start, aligned_end;	ulong mmc_block_size, mmc_block_address;	if (size == 0) {		return 0;	}	if (!mmc_ready) {		printf("Please initial the MMC first\n");		return -1;	}	mmc_block_size = MMC_BLOCK_SIZE;	mmc_block_address = ~(mmc_block_size - 1);	dst -= CFG_MMC_BASE;	end = dst + size;	part_start = ~mmc_block_address & dst;	part_end = ~mmc_block_address & end;	aligned_start = mmc_block_address & dst;	aligned_end = mmc_block_address & end;	/* all block aligned accesses */	debug	    ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",	     src, (ulong) dst, end, part_start, part_end, aligned_start,	     aligned_end);	if (part_start) {		part_len = mmc_block_size - part_start;		debug		    ("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",		     (ulong) src, dst, end, part_start, part_end, aligned_start,		     aligned_end);		if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) <		    0) {

⌨️ 快捷键说明

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