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

📄 onenand_base.c

📁 老版本的mtd-snap
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/drivers/mtd/onenand/onenand_base.c * *  Copyright (C) 2005 Samsung Electronics *  Kyungmin Park <kyungmin.park@samsung.com> * * 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 <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/mtd/mtd.h>#include <linux/mtd/onenand.h>#include <linux/mtd/partitions.h>#include <asm/io.h>/** * onenand_oob_64 - oob info for large (2KB) page */static struct nand_oobinfo onenand_oob_64 = {	.useecc		= MTD_NANDECC_AUTOPLACE,	.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},		{24, 3}, {46, 2}, {40, 3}, {62, 2} }};/** * onenand_oob_32 - oob info for middle (1KB) page */static struct nand_oobinfo onenand_oob_32 = {	.useecc		= MTD_NANDECC_AUTOPLACE,	.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(int device, int block){	if (device & ONENAND_DEVICE_IS_DDP) {		/* Device Flash Core select, NAND Flash Block Address */		int dfs = 0, density, mask;		density = device >> ONENAND_DEVICE_DENSITY_SHIFT;		mask = (1 << (density + 6));		if (block & mask)			dfs = 1;		return (dfs << ONENAND_DDP_SHIFT) | (block & (mask - 1));	}	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(int device, int block){	if (device & ONENAND_DEVICE_IS_DDP) {		/* Device BufferRAM Select */		int dbs = 0, density, mask;		density = device >> ONENAND_DEVICE_DENSITY_SHIFT;		mask = (1 << (density + 6));		if (block & mask)			dbs = 1;		return (dbs << ONENAND_DDP_SHIFT);	}	return 0;}/** * 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_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:		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->device_id, 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->device_id, block);		this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);	}	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);					if (readcmd) {			/* Select DataRAM for DDP */			value = onenand_bufferram_address(this->device_id, block);			this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);		}	}	/* 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 long timeout;	unsigned int flags = ONENAND_INT_MASTER;	unsigned int interrupt = 0;	unsigned int ctrl, ecc;	/* The 20 msec is enough */	timeout = jiffies + msecs_to_jiffies(20);	while (time_before(jiffies, timeout)) {		interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);		if (interrupt & flags)			break;		if (state != FL_READING)			cond_resched();	}	/* To get correct interrupt status in timeout case */	interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);	ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);	if (ctrl & ONENAND_CTRL_ERROR) {		DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x", ctrl);		return -EIO;	}	if (ctrl & ONENAND_CTRL_LOCK) {		DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error = 0x%04x", ctrl);		return -EIO;	}	if (interrupt & ONENAND_INT_READ) {		ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);		if (ecc & ONENAND_ECC_2BIT_ALL) {			DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x", 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->oobblock;		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, 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(buffer, bufferram + offset, count);	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, 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(bufferram + offset, buffer, count);	return 0;}/** * 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 block, page;	int i;		block = (int) (addr >> this->erase_shift);	page = (int) (addr >> this->page_shift);	page &= this->page_mask;	i = ONENAND_CURRENT_BUFFERRAM(this);	/* Is there valid data? */	if (this->bufferram[i].block == block &&	    this->bufferram[i].page == page &&	    this->bufferram[i].valid)		return 1;	return 0;}/** * 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 block, page;	int i;		block = (int) (addr >> this->erase_shift);	page = (int) (addr >> this->page_shift);	page &= this->page_mask;	/* Invalidate BufferRAM */	for (i = 0; i < MAX_BUFFERRAM; i++) {		if (this->bufferram[i].block == block &&		    this->bufferram[i].page == page)			this->bufferram[i].valid = 0;	}	/* Update BufferRAM */	i = ONENAND_CURRENT_BUFFERRAM(this);	this->bufferram[i].block = block;	this->bufferram[i].page = page;	this->bufferram[i].valid = valid;	return 0;}/** * onenand_get_device - [GENERIC] Get chip for selected access * @param mtd		MTD device structure * @param new_state	the state which is requested * * Get the device and lock it for exclusive access */static void onenand_get_device(struct mtd_info *mtd, int new_state){	struct onenand_chip *this = mtd->priv;	DECLARE_WAITQUEUE(wait, current);	/*	 * Grab the lock and see if the device is available	 */	while (1) {		spin_lock(&this->chip_lock);		if (this->state == FL_READY) {			this->state = new_state;

⌨️ 快捷键说明

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