?? onenand_base.c
字號:
/* * 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 + -