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

📄 onenand_base.c

📁 uboot200903最新版本的通用uboot
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  linux/drivers/mtd/onenand/onenand_base.c * *  Copyright (C) 2005-2007 Samsung Electronics *  Kyungmin Park <kyungmin.park@samsung.com> * *  Credits: *      Adrian Hunter <ext-adrian.hunter@nokia.com>: *      auto-placement support, read-while load support, various fixes *      Copyright (C) Nokia Corporation, 2007 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <common.h>#include <linux/mtd/compat.h>#include <linux/mtd/mtd.h>#include <linux/mtd/onenand.h>#include <asm/io.h>#include <asm/errno.h>#include <malloc.h>/* It should access 16-bit instead of 8-bit */static inline void *memcpy_16(void *dst, const void *src, unsigned int len){	void *ret = dst;	short *d = dst;	const short *s = src;	len >>= 1;	while (len-- > 0)		*d++ = *s++;	return ret;}/** * onenand_oob_64 - oob info for large (2KB) page */static struct nand_ecclayout onenand_oob_64 = {	.eccbytes	= 20,	.eccpos		= {		8, 9, 10, 11, 12,		24, 25, 26, 27, 28,		40, 41, 42, 43, 44,		56, 57, 58, 59, 60,		},	.oobfree	= {		{2, 3}, {14, 2}, {18, 3}, {30, 2},		{34, 3}, {46, 2}, {50, 3}, {62, 2}	}};/** * onenand_oob_32 - oob info for middle (1KB) page */static struct nand_ecclayout onenand_oob_32 = {	.eccbytes	= 10,	.eccpos		= {		8, 9, 10, 11, 12,		24, 25, 26, 27, 28,		},	.oobfree	= { {2, 3}, {14, 2}, {18, 3}, {30, 2} }};static const unsigned char ffchars[] = {	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 16 */	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 32 */	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 48 */	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* 64 */};/** * onenand_readw - [OneNAND Interface] Read OneNAND register * @param addr		address to read * * Read OneNAND register */static unsigned short onenand_readw(void __iomem * addr){	return readw(addr);}/** * onenand_writew - [OneNAND Interface] Write OneNAND register with value * @param value		value to write * @param addr		address to write * * Write OneNAND register with value */static void onenand_writew(unsigned short value, void __iomem * addr){	writew(value, addr);}/** * onenand_block_address - [DEFAULT] Get block address * @param device	the device id * @param block		the block * @return		translated block address if DDP, otherwise same * * Setup Start Address 1 Register (F100h) */static int onenand_block_address(struct onenand_chip *this, int block){	/* Device Flash Core select, NAND Flash Block Address */	if (block & this->density_mask)		return ONENAND_DDP_CHIP1 | (block ^ this->density_mask);	return block;}/** * onenand_bufferram_address - [DEFAULT] Get bufferram address * @param device	the device id * @param block		the block * @return		set DBS value if DDP, otherwise 0 * * Setup Start Address 2 Register (F101h) for DDP */static int onenand_bufferram_address(struct onenand_chip *this, int block){	/* Device BufferRAM Select */	if (block & this->density_mask)		return ONENAND_DDP_CHIP1;	return ONENAND_DDP_CHIP0;}/** * onenand_page_address - [DEFAULT] Get page address * @param page		the page address * @param sector	the sector address * @return		combined page and sector address * * Setup Start Address 8 Register (F107h) */static int onenand_page_address(int page, int sector){	/* Flash Page Address, Flash Sector Address */	int fpa, fsa;	fpa = page & ONENAND_FPA_MASK;	fsa = sector & ONENAND_FSA_MASK;	return ((fpa << ONENAND_FPA_SHIFT) | fsa);}/** * onenand_buffer_address - [DEFAULT] Get buffer address * @param dataram1	DataRAM index * @param sectors	the sector address * @param count		the number of sectors * @return		the start buffer value * * Setup Start Buffer Register (F200h) */static int onenand_buffer_address(int dataram1, int sectors, int count){	int bsa, bsc;	/* BufferRAM Sector Address */	bsa = sectors & ONENAND_BSA_MASK;	if (dataram1)		bsa |= ONENAND_BSA_DATARAM1;	/* DataRAM1 */	else		bsa |= ONENAND_BSA_DATARAM0;	/* DataRAM0 */	/* BufferRAM Sector Count */	bsc = count & ONENAND_BSC_MASK;	return ((bsa << ONENAND_BSA_SHIFT) | bsc);}/** * onenand_get_density - [DEFAULT] Get OneNAND density * @param dev_id        OneNAND device ID * * Get OneNAND density from device ID */static inline int onenand_get_density(int dev_id){	int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;	return (density & ONENAND_DEVICE_DENSITY_MASK);}/** * onenand_command - [DEFAULT] Send command to OneNAND device * @param mtd		MTD device structure * @param cmd		the command to be sent * @param addr		offset to read from or write to * @param len		number of bytes to read or write * * Send command to OneNAND device. This function is used for middle/large page * devices (1KB/2KB Bytes per page) */static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,			   size_t len){	struct onenand_chip *this = mtd->priv;	int value, readcmd = 0;	int block, page;	/* Now we use page size operation */	int sectors = 4, count = 4;	/* Address translation */	switch (cmd) {	case ONENAND_CMD_UNLOCK:	case ONENAND_CMD_LOCK:	case ONENAND_CMD_LOCK_TIGHT:	case ONENAND_CMD_UNLOCK_ALL:		block = -1;		page = -1;		break;	case ONENAND_CMD_ERASE:	case ONENAND_CMD_BUFFERRAM:		block = (int)(addr >> this->erase_shift);		page = -1;		break;	default:		block = (int)(addr >> this->erase_shift);		page = (int)(addr >> this->page_shift);		page &= this->page_mask;		break;	}	/* NOTE: The setting order of the registers is very important! */	if (cmd == ONENAND_CMD_BUFFERRAM) {		/* Select DataRAM for DDP */		value = onenand_bufferram_address(this, block);		this->write_word(value,				 this->base + ONENAND_REG_START_ADDRESS2);		/* Switch to the next data buffer */		ONENAND_SET_NEXT_BUFFERRAM(this);		return 0;	}	if (block != -1) {		/* Write 'DFS, FBA' of Flash */		value = onenand_block_address(this, block);		this->write_word(value,				 this->base + ONENAND_REG_START_ADDRESS1);		/* Write 'DFS, FBA' of Flash */		value = onenand_bufferram_address(this, block);		this->write_word(value,				 this->base + ONENAND_REG_START_ADDRESS2);	}	if (page != -1) {		int dataram;		switch (cmd) {		case ONENAND_CMD_READ:		case ONENAND_CMD_READOOB:			dataram = ONENAND_SET_NEXT_BUFFERRAM(this);			readcmd = 1;			break;		default:			dataram = ONENAND_CURRENT_BUFFERRAM(this);			break;		}		/* Write 'FPA, FSA' of Flash */		value = onenand_page_address(page, sectors);		this->write_word(value,				 this->base + ONENAND_REG_START_ADDRESS8);		/* Write 'BSA, BSC' of DataRAM */		value = onenand_buffer_address(dataram, sectors, count);		this->write_word(value, this->base + ONENAND_REG_START_BUFFER);	}	/* Interrupt clear */	this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);	/* Write command */	this->write_word(cmd, this->base + ONENAND_REG_COMMAND);	return 0;}/** * onenand_wait - [DEFAULT] wait until the command is done * @param mtd		MTD device structure * @param state		state to select the max. timeout value * * Wait for command done. This applies to all OneNAND command * Read can take up to 30us, erase up to 2ms and program up to 350us * according to general OneNAND specs */static int onenand_wait(struct mtd_info *mtd, int state){	struct onenand_chip *this = mtd->priv;	unsigned int flags = ONENAND_INT_MASTER;	unsigned int interrupt = 0;	unsigned int ctrl, ecc;	while (1) {		interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);		if (interrupt & flags)			break;	}	ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);	if (ctrl & ONENAND_CTRL_ERROR) {		printk("onenand_wait: controller error = 0x%04x\n", ctrl);		if (ctrl & ONENAND_CTRL_LOCK)			printk("onenand_wait: it's locked error = 0x%04x\n",				ctrl);		return -EIO;	}	if (interrupt & ONENAND_INT_READ) {		ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);		if (ecc & ONENAND_ECC_2BIT_ALL) {			MTDDEBUG (MTD_DEBUG_LEVEL0,				  "onenand_wait: ECC error = 0x%04x\n", ecc);			return -EBADMSG;		}	}	return 0;}/** * onenand_bufferram_offset - [DEFAULT] BufferRAM offset * @param mtd		MTD data structure * @param area		BufferRAM area * @return		offset given area * * Return BufferRAM offset given area */static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area){	struct onenand_chip *this = mtd->priv;	if (ONENAND_CURRENT_BUFFERRAM(this)) {		if (area == ONENAND_DATARAM)			return mtd->writesize;		if (area == ONENAND_SPARERAM)			return mtd->oobsize;	}	return 0;}/** * onenand_read_bufferram - [OneNAND Interface] Read the bufferram area * @param mtd		MTD data structure * @param area		BufferRAM area * @param buffer	the databuffer to put/get data * @param offset	offset to read from or write to * @param count		number of bytes to read/write * * Read the BufferRAM area */static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,				  unsigned char *buffer, int offset,				  size_t count){	struct onenand_chip *this = mtd->priv;	void __iomem *bufferram;	bufferram = this->base + area;	bufferram += onenand_bufferram_offset(mtd, area);	memcpy_16(buffer, bufferram + offset, count);	return 0;}/** * onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode * @param mtd		MTD data structure * @param area		BufferRAM area * @param buffer	the databuffer to put/get data * @param offset	offset to read from or write to * @param count		number of bytes to read/write * * Read the BufferRAM area with Sync. Burst Mode */static int onenand_sync_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,				       unsigned char *buffer, int offset,				       size_t count){	struct onenand_chip *this = mtd->priv;	void __iomem *bufferram;	bufferram = this->base + area;	bufferram += onenand_bufferram_offset(mtd, area);	this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ);	memcpy_16(buffer, bufferram + offset, count);	this->mmcontrol(mtd, 0);	return 0;}/** * onenand_write_bufferram - [OneNAND Interface] Write the bufferram area * @param mtd		MTD data structure * @param area		BufferRAM area * @param buffer	the databuffer to put/get data * @param offset	offset to read from or write to * @param count		number of bytes to read/write * * Write the BufferRAM area */static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area,				   const unsigned char *buffer, int offset,				   size_t count){	struct onenand_chip *this = mtd->priv;	void __iomem *bufferram;	bufferram = this->base + area;	bufferram += onenand_bufferram_offset(mtd, area);	memcpy_16(bufferram + offset, buffer, count);	return 0;}/** * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode * @param mtd		MTD data structure * @param addr		address to check * @return		blockpage address * * Get blockpage address at 2x program mode */static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr){	struct onenand_chip *this = mtd->priv;	int blockpage, block, page;	/* Calculate the even block number */	block = (int) (addr >> this->erase_shift) & ~1;	/* Is it the odd plane? */	if (addr & this->writesize)		block++;	page = (int) (addr >> (this->page_shift + 1)) & this->page_mask;	blockpage = (block << 7) | page;	return blockpage;}/** * onenand_check_bufferram - [GENERIC] Check BufferRAM information * @param mtd		MTD data structure * @param addr		address to check * @return		1 if there are valid data, otherwise 0 * * Check bufferram if there is data we required */static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr){	struct onenand_chip *this = mtd->priv;	int blockpage, found = 0;	unsigned int i;#ifdef CONFIG_S3C64XX	return 0;#endif	if (ONENAND_IS_2PLANE(this))		blockpage = onenand_get_2x_blockpage(mtd, addr);	else		blockpage = (int) (addr >> this->page_shift);	/* Is there valid data? */	i = ONENAND_CURRENT_BUFFERRAM(this);	if (this->bufferram[i].blockpage == blockpage)		found = 1;	else {		/* Check another BufferRAM */		i = ONENAND_NEXT_BUFFERRAM(this);		if (this->bufferram[i].blockpage == blockpage) {			ONENAND_SET_NEXT_BUFFERRAM(this);			found = 1;		}	}	if (found && ONENAND_IS_DDP(this)) {		/* Select DataRAM for DDP */		int block = (int) (addr >> this->erase_shift);		int value = onenand_bufferram_address(this, block);		this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);	}	return found;}/** * onenand_update_bufferram - [GENERIC] Update BufferRAM information * @param mtd		MTD data structure * @param addr		address to update * @param valid		valid flag * * Update BufferRAM information */static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,				    int valid){	struct onenand_chip *this = mtd->priv;	int blockpage;	unsigned int i;	if (ONENAND_IS_2PLANE(this))		blockpage = onenand_get_2x_blockpage(mtd, addr);	else		blockpage = (int)(addr >> this->page_shift);	/* Invalidate another BufferRAM */	i = ONENAND_NEXT_BUFFERRAM(this);	if (this->bufferram[i].blockpage == blockpage)		this->bufferram[i].blockpage = -1;	/* Update BufferRAM */	i = ONENAND_CURRENT_BUFFERRAM(this);	if (valid)		this->bufferram[i].blockpage = blockpage;	else		this->bufferram[i].blockpage = -1;	return 0;}/** * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information * @param mtd           MTD data structure * @param addr          start address to invalidate * @param len           length to invalidate * * Invalidate BufferRAM information

⌨️ 快捷键说明

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