mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-03-09 15:40:20 +00:00
Add a directory by kernel instead of a common root, add qnap-301w and rpi4 kernel 6.1 suppport
This commit is contained in:
parent
e910436a7a
commit
46837ec4c0
9459 changed files with 362648 additions and 116345 deletions
|
|
@ -0,0 +1,50 @@
|
|||
#
|
||||
# Copyright (C) 2005-2007 Samsung Electronics.
|
||||
# Kyungmin Park <kyungmin.park@samsung.com>
|
||||
#
|
||||
# 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 $(TOPDIR)/config.mk
|
||||
|
||||
LIB := $(obj)libonenand.o
|
||||
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
COBJS-$(CONFIG_CMD_ONENAND) := onenand_uboot.o onenand_base.o onenand_bbt.o
|
||||
COBJS-$(CONFIG_SAMSUNG_ONENAND) += samsung.o
|
||||
else
|
||||
COBJS-y := onenand_spl.o
|
||||
endif
|
||||
|
||||
COBJS := $(COBJS-y)
|
||||
SRCS := $(COBJS:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(COBJS))
|
||||
|
||||
all: $(LIB)
|
||||
|
||||
$(LIB): $(obj).depend $(OBJS)
|
||||
$(call cmd_link_o_target, $(OBJS))
|
||||
|
||||
#########################################################################
|
||||
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* linux/drivers/mtd/onenand/onenand_bbt.c
|
||||
*
|
||||
* Bad Block Table support for the OneNAND driver
|
||||
*
|
||||
* Copyright(c) 2005-2008 Samsung Electronics
|
||||
* Kyungmin Park <kyungmin.park@samsung.com>
|
||||
*
|
||||
* TODO:
|
||||
* Split BBT core and chip specific BBT.
|
||||
*
|
||||
* 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/compat.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/onenand.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <asm/errno.h>
|
||||
|
||||
/**
|
||||
* check_short_pattern - [GENERIC] check if a pattern is in the buffer
|
||||
* @param buf the buffer to search
|
||||
* @param len the length of buffer to search
|
||||
* @param paglen the pagelength
|
||||
* @param td search pattern descriptor
|
||||
*
|
||||
* Check for a pattern at the given place. Used to search bad block
|
||||
* tables and good / bad block identifiers. Same as check_pattern, but
|
||||
* no optional empty check and the pattern is expected to start
|
||||
* at offset 0.
|
||||
*/
|
||||
static int check_short_pattern(uint8_t * buf, int len, int paglen,
|
||||
struct nand_bbt_descr *td)
|
||||
{
|
||||
int i;
|
||||
uint8_t *p = buf;
|
||||
|
||||
/* Compare the pattern */
|
||||
for (i = 0; i < td->len; i++) {
|
||||
if (p[i] != td->pattern[i])
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* create_bbt - [GENERIC] Create a bad block table by scanning the device
|
||||
* @param mtd MTD device structure
|
||||
* @param buf temporary buffer
|
||||
* @param bd descriptor for the good/bad block search pattern
|
||||
* @param chip create the table for a specific chip, -1 read all chips.
|
||||
* Applies only if NAND_BBT_PERCHIP option is set
|
||||
*
|
||||
* Create a bad block table by scanning the device
|
||||
* for the given good/bad block identify pattern
|
||||
*/
|
||||
static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
|
||||
struct nand_bbt_descr *bd, int chip)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
struct bbm_info *bbm = this->bbm;
|
||||
int i, j, numblocks, len, scanlen;
|
||||
int startblock;
|
||||
loff_t from;
|
||||
size_t readlen, ooblen;
|
||||
struct mtd_oob_ops ops;
|
||||
int rgn;
|
||||
|
||||
printk(KERN_INFO "Scanning device for bad blocks\n");
|
||||
|
||||
len = 1;
|
||||
|
||||
/* We need only read few bytes from the OOB area */
|
||||
scanlen = ooblen = 0;
|
||||
readlen = bd->len;
|
||||
|
||||
/* chip == -1 case only */
|
||||
/* Note that numblocks is 2 * (real numblocks) here;
|
||||
* see i += 2 below as it makses shifting and masking less painful
|
||||
*/
|
||||
numblocks = this->chipsize >> (bbm->bbt_erase_shift - 1);
|
||||
startblock = 0;
|
||||
from = 0;
|
||||
|
||||
ops.mode = MTD_OOB_PLACE;
|
||||
ops.ooblen = readlen;
|
||||
ops.oobbuf = buf;
|
||||
ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
|
||||
|
||||
for (i = startblock; i < numblocks;) {
|
||||
int ret;
|
||||
|
||||
for (j = 0; j < len; j++) {
|
||||
/* No need to read pages fully,
|
||||
* just read required OOB bytes */
|
||||
ret = onenand_bbt_read_oob(mtd,
|
||||
from + j * mtd->writesize +
|
||||
bd->offs, &ops);
|
||||
|
||||
/* If it is a initial bad block, just ignore it */
|
||||
if (ret == ONENAND_BBT_READ_FATAL_ERROR)
|
||||
return -EIO;
|
||||
|
||||
if (ret || check_short_pattern
|
||||
(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
|
||||
bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
|
||||
printk(KERN_WARNING
|
||||
"Bad eraseblock %d at 0x%08x\n", i >> 1,
|
||||
(unsigned int)from);
|
||||
break;
|
||||
}
|
||||
}
|
||||
i += 2;
|
||||
|
||||
if (FLEXONENAND(this)) {
|
||||
rgn = flexonenand_region(mtd, from);
|
||||
from += mtd->eraseregions[rgn].erasesize;
|
||||
} else
|
||||
from += (1 << bbm->bbt_erase_shift);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* onenand_memory_bbt - [GENERIC] create a memory based bad block table
|
||||
* @param mtd MTD device structure
|
||||
* @param bd descriptor for the good/bad block search pattern
|
||||
*
|
||||
* The function creates a memory based bbt by scanning the device
|
||||
* for manufacturer / software marked good / bad blocks
|
||||
*/
|
||||
static inline int onenand_memory_bbt(struct mtd_info *mtd,
|
||||
struct nand_bbt_descr *bd)
|
||||
{
|
||||
unsigned char data_buf[MAX_ONENAND_PAGESIZE];
|
||||
|
||||
bd->options &= ~NAND_BBT_SCANEMPTY;
|
||||
return create_bbt(mtd, data_buf, bd, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* onenand_isbad_bbt - [OneNAND Interface] Check if a block is bad
|
||||
* @param mtd MTD device structure
|
||||
* @param offs offset in the device
|
||||
* @param allowbbt allow access to bad block table region
|
||||
*/
|
||||
static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
struct bbm_info *bbm = this->bbm;
|
||||
int block;
|
||||
uint8_t res;
|
||||
|
||||
/* Get block number * 2 */
|
||||
block = (int) (onenand_block(this, offs) << 1);
|
||||
res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03;
|
||||
|
||||
MTDDEBUG (MTD_DEBUG_LEVEL2,
|
||||
"onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n",
|
||||
(unsigned int)offs, block >> 1, res);
|
||||
|
||||
switch ((int)res) {
|
||||
case 0x00:
|
||||
return 0;
|
||||
case 0x01:
|
||||
return 1;
|
||||
case 0x02:
|
||||
return allowbbt ? 0 : 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* onenand_scan_bbt - [OneNAND Interface] scan, find, read and maybe create bad block table(s)
|
||||
* @param mtd MTD device structure
|
||||
* @param bd descriptor for the good/bad block search pattern
|
||||
*
|
||||
* The function checks, if a bad block table(s) is/are already
|
||||
* available. If not it scans the device for manufacturer
|
||||
* marked good / bad blocks and writes the bad block table(s) to
|
||||
* the selected place.
|
||||
*
|
||||
* The bad block table memory is allocated here. It must be freed
|
||||
* by calling the onenand_free_bbt function.
|
||||
*
|
||||
*/
|
||||
int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
struct bbm_info *bbm = this->bbm;
|
||||
int len, ret = 0;
|
||||
|
||||
len = this->chipsize >> (this->erase_shift + 2);
|
||||
/* Allocate memory (2bit per block) */
|
||||
bbm->bbt = malloc(len);
|
||||
if (!bbm->bbt) {
|
||||
printk(KERN_ERR "onenand_scan_bbt: Out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* Clear the memory bad block table */
|
||||
memset(bbm->bbt, 0x00, len);
|
||||
|
||||
/* Set the bad block position */
|
||||
bbm->badblockpos = ONENAND_BADBLOCK_POS;
|
||||
|
||||
/* Set erase shift */
|
||||
bbm->bbt_erase_shift = this->erase_shift;
|
||||
|
||||
if (!bbm->isbad_bbt)
|
||||
bbm->isbad_bbt = onenand_isbad_bbt;
|
||||
|
||||
/* Scan the device to build a memory based bad block table */
|
||||
if ((ret = onenand_memory_bbt(mtd, bd))) {
|
||||
printk(KERN_ERR
|
||||
"onenand_scan_bbt: Can't scan flash and build the RAM-based BBT\n");
|
||||
free(bbm->bbt);
|
||||
bbm->bbt = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Define some generic bad / good block scan pattern which are used
|
||||
* while scanning a device for factory marked good / bad blocks.
|
||||
*/
|
||||
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
|
||||
|
||||
static struct nand_bbt_descr largepage_memorybased = {
|
||||
.options = 0,
|
||||
.offs = 0,
|
||||
.len = 2,
|
||||
.pattern = scan_ff_pattern,
|
||||
};
|
||||
|
||||
/**
|
||||
* onenand_default_bbt - [OneNAND Interface] Select a default bad block table for the device
|
||||
* @param mtd MTD device structure
|
||||
*
|
||||
* This function selects the default bad block table
|
||||
* support for the device and calls the onenand_scan_bbt function
|
||||
*/
|
||||
int onenand_default_bbt(struct mtd_info *mtd)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
struct bbm_info *bbm;
|
||||
|
||||
this->bbm = malloc(sizeof(struct bbm_info));
|
||||
if (!this->bbm)
|
||||
return -ENOMEM;
|
||||
|
||||
bbm = this->bbm;
|
||||
|
||||
memset(bbm, 0, sizeof(struct bbm_info));
|
||||
|
||||
/* 1KB page has same configuration as 2KB page */
|
||||
if (!bbm->badblock_pattern)
|
||||
bbm->badblock_pattern = &largepage_memorybased;
|
||||
|
||||
return onenand_scan_bbt(mtd, bbm->badblock_pattern);
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
*
|
||||
* Based on code:
|
||||
* Copyright (C) 2005-2009 Samsung Electronics
|
||||
* Kyungmin Park <kyungmin.park@samsung.com>
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/mtd/onenand_regs.h>
|
||||
#include <onenand_uboot.h>
|
||||
|
||||
/*
|
||||
* Device geometry:
|
||||
* - 2048b page, 128k erase block.
|
||||
* - 4096b page, 256k erase block.
|
||||
*/
|
||||
enum onenand_spl_pagesize {
|
||||
PAGE_2K = 2048,
|
||||
PAGE_4K = 4096,
|
||||
};
|
||||
|
||||
#define ONENAND_PAGES_PER_BLOCK 64
|
||||
#define onenand_block_address(block) (block)
|
||||
#define onenand_sector_address(page) (page << 2)
|
||||
#define onenand_buffer_address() ((1 << 3) << 8)
|
||||
#define onenand_bufferram_address(block) (0)
|
||||
|
||||
static inline uint16_t onenand_readw(uint32_t addr)
|
||||
{
|
||||
return readw(CONFIG_SYS_ONENAND_BASE + addr);
|
||||
}
|
||||
|
||||
static inline void onenand_writew(uint16_t value, uint32_t addr)
|
||||
{
|
||||
writew(value, CONFIG_SYS_ONENAND_BASE + addr);
|
||||
}
|
||||
|
||||
static enum onenand_spl_pagesize onenand_spl_get_geometry(void)
|
||||
{
|
||||
uint32_t dev_id, density;
|
||||
|
||||
if (!onenand_readw(ONENAND_REG_TECHNOLOGY)) {
|
||||
dev_id = onenand_readw(ONENAND_REG_DEVICE_ID);
|
||||
density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
|
||||
density &= ONENAND_DEVICE_DENSITY_MASK;
|
||||
|
||||
if (density < ONENAND_DEVICE_DENSITY_4Gb)
|
||||
return PAGE_2K;
|
||||
|
||||
if (dev_id & ONENAND_DEVICE_IS_DDP)
|
||||
return PAGE_2K;
|
||||
}
|
||||
|
||||
return PAGE_4K;
|
||||
}
|
||||
|
||||
static int onenand_spl_read_page(uint32_t block, uint32_t page, uint32_t *buf,
|
||||
enum onenand_spl_pagesize pagesize)
|
||||
{
|
||||
const uint32_t addr = CONFIG_SYS_ONENAND_BASE + ONENAND_DATARAM;
|
||||
uint32_t offset;
|
||||
|
||||
onenand_writew(onenand_block_address(block),
|
||||
ONENAND_REG_START_ADDRESS1);
|
||||
|
||||
onenand_writew(onenand_bufferram_address(block),
|
||||
ONENAND_REG_START_ADDRESS2);
|
||||
|
||||
onenand_writew(onenand_sector_address(page),
|
||||
ONENAND_REG_START_ADDRESS8);
|
||||
|
||||
onenand_writew(onenand_buffer_address(),
|
||||
ONENAND_REG_START_BUFFER);
|
||||
|
||||
onenand_writew(ONENAND_INT_CLEAR, ONENAND_REG_INTERRUPT);
|
||||
|
||||
onenand_writew(ONENAND_CMD_READ, ONENAND_REG_COMMAND);
|
||||
|
||||
while (!(onenand_readw(ONENAND_REG_INTERRUPT) & ONENAND_INT_READ))
|
||||
continue;
|
||||
|
||||
/* Check for invalid block mark */
|
||||
if (page < 2 && (onenand_readw(ONENAND_SPARERAM) != 0xffff))
|
||||
return 1;
|
||||
|
||||
for (offset = 0; offset < pagesize; offset += 4)
|
||||
buf[offset / 4] = readl(addr + offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void onenand_spl_load_image(uint32_t offs, uint32_t size, void *dst)
|
||||
{
|
||||
uint32_t *addr = (uint32_t *)dst;
|
||||
uint32_t total_pages;
|
||||
uint32_t block;
|
||||
uint32_t page, rpage;
|
||||
enum onenand_spl_pagesize pagesize;
|
||||
int ret;
|
||||
|
||||
pagesize = onenand_spl_get_geometry();
|
||||
|
||||
/*
|
||||
* The page can be either 2k or 4k, avoid using DIV_ROUND_UP to avoid
|
||||
* pulling further unwanted functions into the SPL.
|
||||
*/
|
||||
if (pagesize == 2048) {
|
||||
total_pages = DIV_ROUND_UP(size, 2048);
|
||||
page = offs / 2048;
|
||||
} else {
|
||||
total_pages = DIV_ROUND_UP(size, 4096);
|
||||
page = offs / 4096;
|
||||
}
|
||||
|
||||
for (; page <= total_pages; page++) {
|
||||
block = page / ONENAND_PAGES_PER_BLOCK;
|
||||
rpage = page & (ONENAND_PAGES_PER_BLOCK - 1);
|
||||
ret = onenand_spl_read_page(block, rpage, addr, pagesize);
|
||||
if (ret) {
|
||||
total_pages += ONENAND_PAGES_PER_BLOCK;
|
||||
page += ONENAND_PAGES_PER_BLOCK - 1;
|
||||
} else {
|
||||
addr += pagesize / 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* drivers/mtd/onenand/onenand_uboot.c
|
||||
*
|
||||
* Copyright (C) 2005-2008 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OneNAND initialization at U-Boot
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/onenand.h>
|
||||
|
||||
struct mtd_info onenand_mtd;
|
||||
struct onenand_chip onenand_chip;
|
||||
static __attribute__((unused)) char dev_name[] = "onenand0";
|
||||
|
||||
void onenand_init(void)
|
||||
{
|
||||
memset(&onenand_mtd, 0, sizeof(struct mtd_info));
|
||||
memset(&onenand_chip, 0, sizeof(struct onenand_chip));
|
||||
|
||||
onenand_mtd.priv = &onenand_chip;
|
||||
|
||||
#ifdef CONFIG_USE_ONENAND_BOARD_INIT
|
||||
/*
|
||||
* It's used for some board init required
|
||||
*/
|
||||
onenand_board_init(&onenand_mtd);
|
||||
#else
|
||||
onenand_chip.base = (void *) CONFIG_SYS_ONENAND_BASE;
|
||||
#endif
|
||||
|
||||
onenand_scan(&onenand_mtd, 1);
|
||||
|
||||
if (onenand_chip.device_id & DEVICE_IS_FLEXONENAND)
|
||||
puts("Flex-");
|
||||
puts("OneNAND: ");
|
||||
print_size(onenand_chip.chipsize, "\n");
|
||||
|
||||
#ifdef CONFIG_MTD_DEVICE
|
||||
/*
|
||||
* Add MTD device so that we can reference it later
|
||||
* via the mtdcore infrastructure (e.g. ubi).
|
||||
*/
|
||||
onenand_mtd.name = dev_name;
|
||||
add_mtd_device(&onenand_mtd);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,645 @@
|
|||
/*
|
||||
* S3C64XX/S5PC100 OneNAND driver at U-Boot
|
||||
*
|
||||
* Copyright (C) 2008-2009 Samsung Electronics
|
||||
* Kyungmin Park <kyungmin.park@samsung.com>
|
||||
*
|
||||
* Implementation:
|
||||
* Emulate the pseudo BufferRAM
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/onenand.h>
|
||||
#include <linux/mtd/samsung_onenand.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
#ifdef ONENAND_DEBUG
|
||||
#define DPRINTK(format, args...) \
|
||||
do { \
|
||||
printf("%s[%d]: " format "\n", __func__, __LINE__, ##args); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DPRINTK(...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define ONENAND_ERASE_STATUS 0x00
|
||||
#define ONENAND_MULTI_ERASE_SET 0x01
|
||||
#define ONENAND_ERASE_START 0x03
|
||||
#define ONENAND_UNLOCK_START 0x08
|
||||
#define ONENAND_UNLOCK_END 0x09
|
||||
#define ONENAND_LOCK_START 0x0A
|
||||
#define ONENAND_LOCK_END 0x0B
|
||||
#define ONENAND_LOCK_TIGHT_START 0x0C
|
||||
#define ONENAND_LOCK_TIGHT_END 0x0D
|
||||
#define ONENAND_UNLOCK_ALL 0x0E
|
||||
#define ONENAND_OTP_ACCESS 0x12
|
||||
#define ONENAND_SPARE_ACCESS_ONLY 0x13
|
||||
#define ONENAND_MAIN_ACCESS_ONLY 0x14
|
||||
#define ONENAND_ERASE_VERIFY 0x15
|
||||
#define ONENAND_MAIN_SPARE_ACCESS 0x16
|
||||
#define ONENAND_PIPELINE_READ 0x4000
|
||||
|
||||
#if defined(CONFIG_S3C64XX)
|
||||
#define MAP_00 (0x0 << 24)
|
||||
#define MAP_01 (0x1 << 24)
|
||||
#define MAP_10 (0x2 << 24)
|
||||
#define MAP_11 (0x3 << 24)
|
||||
#elif defined(CONFIG_S5P)
|
||||
#define MAP_00 (0x0 << 26)
|
||||
#define MAP_01 (0x1 << 26)
|
||||
#define MAP_10 (0x2 << 26)
|
||||
#define MAP_11 (0x3 << 26)
|
||||
#endif
|
||||
|
||||
/* read/write of XIP buffer */
|
||||
#define CMD_MAP_00(mem_addr) (MAP_00 | ((mem_addr) << 1))
|
||||
/* read/write to the memory device */
|
||||
#define CMD_MAP_01(mem_addr) (MAP_01 | (mem_addr))
|
||||
/* control special functions of the memory device */
|
||||
#define CMD_MAP_10(mem_addr) (MAP_10 | (mem_addr))
|
||||
/* direct interface(direct access) with the memory device */
|
||||
#define CMD_MAP_11(mem_addr) (MAP_11 | ((mem_addr) << 2))
|
||||
|
||||
struct s3c_onenand {
|
||||
struct mtd_info *mtd;
|
||||
void __iomem *base;
|
||||
void __iomem *ahb_addr;
|
||||
int bootram_command;
|
||||
void __iomem *page_buf;
|
||||
void __iomem *oob_buf;
|
||||
unsigned int (*mem_addr)(int fba, int fpa, int fsa);
|
||||
struct samsung_onenand *reg;
|
||||
};
|
||||
|
||||
static struct s3c_onenand *onenand;
|
||||
|
||||
static int s3c_read_cmd(unsigned int cmd)
|
||||
{
|
||||
return readl(onenand->ahb_addr + cmd);
|
||||
}
|
||||
|
||||
static void s3c_write_cmd(int value, unsigned int cmd)
|
||||
{
|
||||
writel(value, onenand->ahb_addr + cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
* MEM_ADDR
|
||||
*
|
||||
* fba: flash block address
|
||||
* fpa: flash page address
|
||||
* fsa: flash sector address
|
||||
*
|
||||
* return the buffer address on the memory device
|
||||
* It will be combined with CMD_MAP_XX
|
||||
*/
|
||||
#if defined(CONFIG_S3C64XX)
|
||||
static unsigned int s3c_mem_addr(int fba, int fpa, int fsa)
|
||||
{
|
||||
return (fba << 12) | (fpa << 6) | (fsa << 4);
|
||||
}
|
||||
#elif defined(CONFIG_S5P)
|
||||
static unsigned int s3c_mem_addr(int fba, int fpa, int fsa)
|
||||
{
|
||||
return (fba << 13) | (fpa << 7) | (fsa << 5);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void s3c_onenand_reset(void)
|
||||
{
|
||||
unsigned long timeout = 0x10000;
|
||||
int stat;
|
||||
|
||||
writel(ONENAND_MEM_RESET_COLD, &onenand->reg->mem_reset);
|
||||
while (timeout--) {
|
||||
stat = readl(&onenand->reg->int_err_stat);
|
||||
if (stat & RST_CMP)
|
||||
break;
|
||||
}
|
||||
stat = readl(&onenand->reg->int_err_stat);
|
||||
writel(stat, &onenand->reg->int_err_ack);
|
||||
|
||||
/* Clear interrupt */
|
||||
writel(0x0, &onenand->reg->int_err_ack);
|
||||
/* Clear the ECC status */
|
||||
writel(0x0, &onenand->reg->ecc_err_stat);
|
||||
}
|
||||
|
||||
static unsigned short s3c_onenand_readw(void __iomem *addr)
|
||||
{
|
||||
struct onenand_chip *this = onenand->mtd->priv;
|
||||
int reg = addr - this->base;
|
||||
int word_addr = reg >> 1;
|
||||
int value;
|
||||
|
||||
/* It's used for probing time */
|
||||
switch (reg) {
|
||||
case ONENAND_REG_MANUFACTURER_ID:
|
||||
return readl(&onenand->reg->manufact_id);
|
||||
case ONENAND_REG_DEVICE_ID:
|
||||
return readl(&onenand->reg->device_id);
|
||||
case ONENAND_REG_VERSION_ID:
|
||||
return readl(&onenand->reg->flash_ver_id);
|
||||
case ONENAND_REG_DATA_BUFFER_SIZE:
|
||||
return readl(&onenand->reg->data_buf_size);
|
||||
case ONENAND_REG_TECHNOLOGY:
|
||||
return readl(&onenand->reg->tech);
|
||||
case ONENAND_REG_SYS_CFG1:
|
||||
return readl(&onenand->reg->mem_cfg);
|
||||
|
||||
/* Used at unlock all status */
|
||||
case ONENAND_REG_CTRL_STATUS:
|
||||
return 0;
|
||||
|
||||
case ONENAND_REG_WP_STATUS:
|
||||
return ONENAND_WP_US;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* BootRAM access control */
|
||||
if (reg < ONENAND_DATARAM && onenand->bootram_command) {
|
||||
if (word_addr == 0)
|
||||
return readl(&onenand->reg->manufact_id);
|
||||
if (word_addr == 1)
|
||||
return readl(&onenand->reg->device_id);
|
||||
if (word_addr == 2)
|
||||
return readl(&onenand->reg->flash_ver_id);
|
||||
}
|
||||
|
||||
value = s3c_read_cmd(CMD_MAP_11(word_addr)) & 0xffff;
|
||||
printk(KERN_INFO "s3c_onenand_readw: Illegal access"
|
||||
" at reg 0x%x, value 0x%x\n", word_addr, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void s3c_onenand_writew(unsigned short value, void __iomem *addr)
|
||||
{
|
||||
struct onenand_chip *this = onenand->mtd->priv;
|
||||
int reg = addr - this->base;
|
||||
int word_addr = reg >> 1;
|
||||
|
||||
/* It's used for probing time */
|
||||
switch (reg) {
|
||||
case ONENAND_REG_SYS_CFG1:
|
||||
writel(value, &onenand->reg->mem_cfg);
|
||||
return;
|
||||
|
||||
case ONENAND_REG_START_ADDRESS1:
|
||||
case ONENAND_REG_START_ADDRESS2:
|
||||
return;
|
||||
|
||||
/* Lock/lock-tight/unlock/unlock_all */
|
||||
case ONENAND_REG_START_BLOCK_ADDRESS:
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* BootRAM access control */
|
||||
if (reg < ONENAND_DATARAM) {
|
||||
if (value == ONENAND_CMD_READID) {
|
||||
onenand->bootram_command = 1;
|
||||
return;
|
||||
}
|
||||
if (value == ONENAND_CMD_RESET) {
|
||||
writel(ONENAND_MEM_RESET_COLD,
|
||||
&onenand->reg->mem_reset);
|
||||
onenand->bootram_command = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_INFO "s3c_onenand_writew: Illegal access"
|
||||
" at reg 0x%x, value 0x%x\n", word_addr, value);
|
||||
|
||||
s3c_write_cmd(value, CMD_MAP_11(word_addr));
|
||||
}
|
||||
|
||||
static int s3c_onenand_wait(struct mtd_info *mtd, int state)
|
||||
{
|
||||
unsigned int flags = INT_ACT;
|
||||
unsigned int stat, ecc;
|
||||
unsigned long timeout = 0x100000;
|
||||
|
||||
switch (state) {
|
||||
case FL_READING:
|
||||
flags |= BLK_RW_CMP | LOAD_CMP;
|
||||
break;
|
||||
case FL_WRITING:
|
||||
flags |= BLK_RW_CMP | PGM_CMP;
|
||||
break;
|
||||
case FL_ERASING:
|
||||
flags |= BLK_RW_CMP | ERS_CMP;
|
||||
break;
|
||||
case FL_LOCKING:
|
||||
flags |= BLK_RW_CMP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
while (timeout--) {
|
||||
stat = readl(&onenand->reg->int_err_stat);
|
||||
if (stat & flags)
|
||||
break;
|
||||
}
|
||||
|
||||
/* To get correct interrupt status in timeout case */
|
||||
stat = readl(&onenand->reg->int_err_stat);
|
||||
writel(stat, &onenand->reg->int_err_ack);
|
||||
|
||||
/*
|
||||
* In the Spec. it checks the controller status first
|
||||
* However if you get the correct information in case of
|
||||
* power off recovery (POR) test, it should read ECC status first
|
||||
*/
|
||||
if (stat & LOAD_CMP) {
|
||||
ecc = readl(&onenand->reg->ecc_err_stat);
|
||||
if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
|
||||
printk(KERN_INFO "%s: ECC error = 0x%04x\n",
|
||||
__func__, ecc);
|
||||
mtd->ecc_stats.failed++;
|
||||
return -EBADMSG;
|
||||
}
|
||||
}
|
||||
|
||||
if (stat & (LOCKED_BLK | ERS_FAIL | PGM_FAIL | LD_FAIL_ECC_ERR)) {
|
||||
printk(KERN_INFO "%s: controller error = 0x%04x\n",
|
||||
__func__, stat);
|
||||
if (stat & LOCKED_BLK)
|
||||
printk(KERN_INFO "%s: it's locked error = 0x%04x\n",
|
||||
__func__, stat);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c_onenand_command(struct mtd_info *mtd, int cmd,
|
||||
loff_t addr, size_t len)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
unsigned int *m, *s;
|
||||
int fba, fpa, fsa = 0;
|
||||
unsigned int mem_addr;
|
||||
int i, mcount, scount;
|
||||
int index;
|
||||
|
||||
fba = (int) (addr >> this->erase_shift);
|
||||
fpa = (int) (addr >> this->page_shift);
|
||||
fpa &= this->page_mask;
|
||||
|
||||
mem_addr = onenand->mem_addr(fba, fpa, fsa);
|
||||
|
||||
switch (cmd) {
|
||||
case ONENAND_CMD_READ:
|
||||
case ONENAND_CMD_READOOB:
|
||||
case ONENAND_CMD_BUFFERRAM:
|
||||
ONENAND_SET_NEXT_BUFFERRAM(this);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
index = ONENAND_CURRENT_BUFFERRAM(this);
|
||||
|
||||
/*
|
||||
* Emulate Two BufferRAMs and access with 4 bytes pointer
|
||||
*/
|
||||
m = (unsigned int *) onenand->page_buf;
|
||||
s = (unsigned int *) onenand->oob_buf;
|
||||
|
||||
if (index) {
|
||||
m += (this->writesize >> 2);
|
||||
s += (mtd->oobsize >> 2);
|
||||
}
|
||||
|
||||
mcount = mtd->writesize >> 2;
|
||||
scount = mtd->oobsize >> 2;
|
||||
|
||||
switch (cmd) {
|
||||
case ONENAND_CMD_READ:
|
||||
/* Main */
|
||||
for (i = 0; i < mcount; i++)
|
||||
*m++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
|
||||
return 0;
|
||||
|
||||
case ONENAND_CMD_READOOB:
|
||||
writel(TSRF, &onenand->reg->trans_spare);
|
||||
/* Main */
|
||||
for (i = 0; i < mcount; i++)
|
||||
*m++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
|
||||
|
||||
/* Spare */
|
||||
for (i = 0; i < scount; i++)
|
||||
*s++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
|
||||
|
||||
writel(0, &onenand->reg->trans_spare);
|
||||
return 0;
|
||||
|
||||
case ONENAND_CMD_PROG:
|
||||
/* Main */
|
||||
for (i = 0; i < mcount; i++)
|
||||
s3c_write_cmd(*m++, CMD_MAP_01(mem_addr));
|
||||
return 0;
|
||||
|
||||
case ONENAND_CMD_PROGOOB:
|
||||
writel(TSRF, &onenand->reg->trans_spare);
|
||||
|
||||
/* Main - dummy write */
|
||||
for (i = 0; i < mcount; i++)
|
||||
s3c_write_cmd(0xffffffff, CMD_MAP_01(mem_addr));
|
||||
|
||||
/* Spare */
|
||||
for (i = 0; i < scount; i++)
|
||||
s3c_write_cmd(*s++, CMD_MAP_01(mem_addr));
|
||||
|
||||
writel(0, &onenand->reg->trans_spare);
|
||||
return 0;
|
||||
|
||||
case ONENAND_CMD_UNLOCK_ALL:
|
||||
s3c_write_cmd(ONENAND_UNLOCK_ALL, CMD_MAP_10(mem_addr));
|
||||
return 0;
|
||||
|
||||
case ONENAND_CMD_ERASE:
|
||||
s3c_write_cmd(ONENAND_ERASE_START, CMD_MAP_10(mem_addr));
|
||||
return 0;
|
||||
|
||||
case ONENAND_CMD_MULTIBLOCK_ERASE:
|
||||
s3c_write_cmd(ONENAND_MULTI_ERASE_SET, CMD_MAP_10(mem_addr));
|
||||
return 0;
|
||||
|
||||
case ONENAND_CMD_ERASE_VERIFY:
|
||||
s3c_write_cmd(ONENAND_ERASE_VERIFY, CMD_MAP_10(mem_addr));
|
||||
return 0;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *s3c_get_bufferram(struct mtd_info *mtd, int area)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
int index = ONENAND_CURRENT_BUFFERRAM(this);
|
||||
unsigned char *p;
|
||||
|
||||
if (area == ONENAND_DATARAM) {
|
||||
p = (unsigned char *) onenand->page_buf;
|
||||
if (index == 1)
|
||||
p += this->writesize;
|
||||
} else {
|
||||
p = (unsigned char *) onenand->oob_buf;
|
||||
if (index == 1)
|
||||
p += mtd->oobsize;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,
|
||||
unsigned char *buffer, int offset,
|
||||
size_t count)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
p = s3c_get_bufferram(mtd, area);
|
||||
memcpy(buffer, p + offset, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area,
|
||||
const unsigned char *buffer, int offset,
|
||||
size_t count)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
p = s3c_get_bufferram(mtd, area);
|
||||
memcpy(p + offset, buffer, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c_onenand_bbt_wait(struct mtd_info *mtd, int state)
|
||||
{
|
||||
struct samsung_onenand *reg = (struct samsung_onenand *)onenand->base;
|
||||
unsigned int flags = INT_ACT | LOAD_CMP;
|
||||
unsigned int stat;
|
||||
unsigned long timeout = 0x10000;
|
||||
|
||||
while (timeout--) {
|
||||
stat = readl(®->int_err_stat);
|
||||
if (stat & flags)
|
||||
break;
|
||||
}
|
||||
/* To get correct interrupt status in timeout case */
|
||||
stat = readl(&onenand->reg->int_err_stat);
|
||||
writel(stat, &onenand->reg->int_err_ack);
|
||||
|
||||
if (stat & LD_FAIL_ECC_ERR) {
|
||||
s3c_onenand_reset();
|
||||
return ONENAND_BBT_READ_ERROR;
|
||||
}
|
||||
|
||||
if (stat & LOAD_CMP) {
|
||||
int ecc = readl(&onenand->reg->ecc_err_stat);
|
||||
if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
|
||||
s3c_onenand_reset();
|
||||
return ONENAND_BBT_READ_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s3c_onenand_check_lock_status(struct mtd_info *mtd)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
unsigned int block, end;
|
||||
|
||||
end = this->chipsize >> this->erase_shift;
|
||||
|
||||
for (block = 0; block < end; block++) {
|
||||
s3c_read_cmd(CMD_MAP_01(onenand->mem_addr(block, 0, 0)));
|
||||
|
||||
if (readl(&onenand->reg->int_err_stat) & LOCKED_BLK) {
|
||||
printf("block %d is write-protected!\n", block);
|
||||
writel(LOCKED_BLK, &onenand->reg->int_err_ack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void s3c_onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs,
|
||||
size_t len, int cmd)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
int start, end, start_mem_addr, end_mem_addr;
|
||||
|
||||
start = ofs >> this->erase_shift;
|
||||
start_mem_addr = onenand->mem_addr(start, 0, 0);
|
||||
end = start + (len >> this->erase_shift) - 1;
|
||||
end_mem_addr = onenand->mem_addr(end, 0, 0);
|
||||
|
||||
if (cmd == ONENAND_CMD_LOCK) {
|
||||
s3c_write_cmd(ONENAND_LOCK_START, CMD_MAP_10(start_mem_addr));
|
||||
s3c_write_cmd(ONENAND_LOCK_END, CMD_MAP_10(end_mem_addr));
|
||||
} else {
|
||||
s3c_write_cmd(ONENAND_UNLOCK_START, CMD_MAP_10(start_mem_addr));
|
||||
s3c_write_cmd(ONENAND_UNLOCK_END, CMD_MAP_10(end_mem_addr));
|
||||
}
|
||||
|
||||
this->wait(mtd, FL_LOCKING);
|
||||
}
|
||||
|
||||
static void s3c_onenand_unlock_all(struct mtd_info *mtd)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
loff_t ofs = 0;
|
||||
size_t len = this->chipsize;
|
||||
|
||||
/* FIXME workaround */
|
||||
this->subpagesize = mtd->writesize;
|
||||
mtd->subpage_sft = 0;
|
||||
|
||||
if (this->options & ONENAND_HAS_UNLOCK_ALL) {
|
||||
/* Write unlock command */
|
||||
this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
|
||||
|
||||
/* No need to check return value */
|
||||
this->wait(mtd, FL_LOCKING);
|
||||
|
||||
/* Workaround for all block unlock in DDP */
|
||||
if (!ONENAND_IS_DDP(this)) {
|
||||
s3c_onenand_check_lock_status(mtd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* All blocks on another chip */
|
||||
ofs = this->chipsize >> 1;
|
||||
len = this->chipsize >> 1;
|
||||
}
|
||||
|
||||
s3c_onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
|
||||
s3c_onenand_check_lock_status(mtd);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_S3C64XX
|
||||
static void s3c_set_width_regs(struct onenand_chip *this)
|
||||
{
|
||||
int dev_id, density;
|
||||
int fba, fpa, fsa;
|
||||
int dbs_dfs;
|
||||
|
||||
dev_id = DEVICE_ID0_REG;
|
||||
|
||||
density = (dev_id >> ONENAND_DEVICE_DENSITY_SHIFT) & 0xf;
|
||||
dbs_dfs = !!(dev_id & ONENAND_DEVICE_IS_DDP);
|
||||
|
||||
fba = density + 7;
|
||||
if (dbs_dfs)
|
||||
fba--; /* Decrease the fba */
|
||||
fpa = 6;
|
||||
if (density >= ONENAND_DEVICE_DENSITY_512Mb)
|
||||
fsa = 2;
|
||||
else
|
||||
fsa = 1;
|
||||
|
||||
DPRINTK("FBA %lu, FPA %lu, FSA %lu, DDP %lu",
|
||||
FBA_WIDTH0_REG, FPA_WIDTH0_REG, FSA_WIDTH0_REG,
|
||||
DDP_DEVICE_REG);
|
||||
|
||||
DPRINTK("mem_cfg0 0x%lx, sync mode %lu, "
|
||||
"dev_page_size %lu, BURST LEN %lu",
|
||||
MEM_CFG0_REG, SYNC_MODE_REG,
|
||||
DEV_PAGE_SIZE_REG, BURST_LEN0_REG);
|
||||
|
||||
DEV_PAGE_SIZE_REG = 0x1;
|
||||
|
||||
FBA_WIDTH0_REG = fba;
|
||||
FPA_WIDTH0_REG = fpa;
|
||||
FSA_WIDTH0_REG = fsa;
|
||||
DBS_DFS_WIDTH0_REG = dbs_dfs;
|
||||
}
|
||||
#endif
|
||||
|
||||
int s5pc110_chip_probe(struct mtd_info *mtd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int s5pc210_chip_probe(struct mtd_info *mtd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void s3c_onenand_init(struct mtd_info *mtd)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
u32 size = (4 << 10); /* 4 KiB */
|
||||
|
||||
onenand = malloc(sizeof(struct s3c_onenand));
|
||||
if (!onenand)
|
||||
return;
|
||||
|
||||
onenand->page_buf = malloc(size * sizeof(char));
|
||||
if (!onenand->page_buf)
|
||||
return;
|
||||
memset(onenand->page_buf, 0xff, size);
|
||||
|
||||
onenand->oob_buf = malloc(128 * sizeof(char));
|
||||
if (!onenand->oob_buf)
|
||||
return;
|
||||
memset(onenand->oob_buf, 0xff, 128);
|
||||
|
||||
onenand->mtd = mtd;
|
||||
|
||||
#if defined(CONFIG_S3C64XX)
|
||||
onenand->base = (void *)0x70100000;
|
||||
onenand->ahb_addr = (void *)0x20000000;
|
||||
#elif defined(CONFIG_S5P)
|
||||
onenand->base = (void *)0xE7100000;
|
||||
onenand->ahb_addr = (void *)0xB0000000;
|
||||
#endif
|
||||
onenand->mem_addr = s3c_mem_addr;
|
||||
onenand->reg = (struct samsung_onenand *)onenand->base;
|
||||
|
||||
this->read_word = s3c_onenand_readw;
|
||||
this->write_word = s3c_onenand_writew;
|
||||
|
||||
this->wait = s3c_onenand_wait;
|
||||
this->bbt_wait = s3c_onenand_bbt_wait;
|
||||
this->unlock_all = s3c_onenand_unlock_all;
|
||||
this->command = s3c_onenand_command;
|
||||
|
||||
this->read_bufferram = onenand_read_bufferram;
|
||||
this->write_bufferram = onenand_write_bufferram;
|
||||
|
||||
this->options |= ONENAND_RUNTIME_BADBLOCK_CHECK;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue