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

📄 onenand_base.c

📁 u-boot 源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/drivers/mtd/onenand/onenand_base.c * *  Copyright (C) 2005-2007 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 <common.h>#ifdef CONFIG_CMD_ONENAND#include <linux/mtd/compat.h>#include <linux/mtd/mtd.h>#include <linux/mtd/onenand.h>#include <asm/io.h>#include <asm/errno.h>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 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) {		DEBUG(MTD_DEBUG_LEVEL0,		      "onenand_wait: controller error = 0x%04x\n", ctrl);		return -EAGAIN;	}	if (ctrl & ONENAND_CTRL_LOCK) {		DEBUG(MTD_DEBUG_LEVEL0,		      "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) {			DEBUG(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->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_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, 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(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, 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;

⌨️ 快捷键说明

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