Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 37923
b: refs/heads/master
c: 28b79ff
h: refs/heads/master
i:
  37921: ac102d0
  37919: 6fdbf11
v: v3
  • Loading branch information
Kyungmin Park authored and David Woodhouse committed Sep 26, 2006
1 parent 03602ff commit 6957259
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 23 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 98638ee2edf86b80cf89486c4aabcd9ce471a54a
refs/heads/master: 28b79ff9661b22e4c41c0d00d4ab8503e810f13d
137 changes: 118 additions & 19 deletions trunk/drivers/mtd/onenand/onenand_base.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* linux/drivers/mtd/onenand/onenand_base.c
*
* Copyright (C) 2005 Samsung Electronics
* Copyright (C) 2005-2006 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -199,6 +199,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
case ONENAND_CMD_UNLOCK:
case ONENAND_CMD_LOCK:
case ONENAND_CMD_LOCK_TIGHT:
case ONENAND_CMD_UNLOCK_ALL:
block = -1;
page = -1;
break;
Expand Down Expand Up @@ -1211,11 +1212,11 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
end = len >> this->erase_shift;

/* Continuous lock scheme */
if (this->options & ONENAND_CONT_LOCK) {
if (this->options & ONENAND_HAS_CONT_LOCK) {
/* Set start block address */
this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
/* Set end block address */
this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
this->write_word(start + end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
/* Write unlock command */
this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);

Expand All @@ -1236,7 +1237,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
}

/* Block lock scheme */
for (block = start; block < end; block++) {
for (block = start; block < start + end; block++) {
/* Set block address */
value = onenand_block_address(this, block);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
Expand Down Expand Up @@ -1265,6 +1266,79 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
return 0;
}

/**
* onenand_check_lock_status - [OneNAND Interface] Check lock status
* @param this onenand chip data structure
*
* Check lock status
*/
static void onenand_check_lock_status(struct onenand_chip *this)
{
unsigned int value, block, status;
unsigned int end;

end = this->chipsize >> this->erase_shift;
for (block = 0; block < end; block++) {
/* Set block address */
value = onenand_block_address(this, block);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
/* Select DataRAM for DDP */
value = onenand_bufferram_address(this, block);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
/* Set start block address */
this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);

/* Check lock status */
status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
if (!(status & ONENAND_WP_US))
printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
}
}

/**
* onenand_unlock_all - [OneNAND Interface] unlock all blocks
* @param mtd MTD device structure
*
* Unlock all blocks
*/
static int onenand_unlock_all(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;

if (this->options & ONENAND_HAS_UNLOCK_ALL) {
/* Write unlock command */
this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);

/* There's no return value */
this->wait(mtd, FL_UNLOCKING);

/* Sanity check */
while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
& ONENAND_CTRL_ONGO)
continue;

/* Workaround for all block unlock in DDP */
if (this->device_id & ONENAND_DEVICE_IS_DDP) {
loff_t ofs;
size_t len;

/* 1st block on another chip */
ofs = this->chipsize >> 1;
len = 1 << this->erase_shift;

onenand_unlock(mtd, ofs, len);
}

onenand_check_lock_status(this);

return 0;
}

mtd->unlock(mtd, 0x0, this->chipsize);

return 0;
}

#ifdef CONFIG_MTD_ONENAND_OTP

/* Interal OTP operation */
Expand Down Expand Up @@ -1563,13 +1637,44 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
}
#endif /* CONFIG_MTD_ONENAND_OTP */

/**
* onenand_lock_scheme - Check and set OneNAND lock scheme
* @param mtd MTD data structure
*
* Check and set OneNAND lock scheme
*/
static void onenand_lock_scheme(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;
unsigned int density, process;

/* Lock scheme depends on density and process */
density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;

/* Lock scheme */
if (density >= ONENAND_DEVICE_DENSITY_1Gb) {
/* A-Die has all block unlock */
if (process) {
printk(KERN_DEBUG "Chip support all block unlock\n");
this->options |= ONENAND_HAS_UNLOCK_ALL;
}
} else {
/* Some OneNAND has continues lock scheme */
if (!process) {
printk(KERN_DEBUG "Lock scheme is Continues Lock\n");
this->options |= ONENAND_HAS_CONT_LOCK;
}
}
}

/**
* onenand_print_device_info - Print device ID
* @param device device ID
*
* Print device ID
*/
static void onenand_print_device_info(int device)
static void onenand_print_device_info(int device, int version)
{
int vcc, demuxed, ddp, density;

Expand All @@ -1583,6 +1688,7 @@ static void onenand_print_device_info(int device)
(16 << density),
vcc ? "2.65/3.3" : "1.8",
device);
printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version);
}

static const struct onenand_manufacturers onenand_manuf_ids[] = {
Expand Down Expand Up @@ -1625,8 +1731,7 @@ static int onenand_check_maf(int manuf)
static int onenand_probe(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;
int bram_maf_id, bram_dev_id, maf_id, dev_id;
int version_id;
int bram_maf_id, bram_dev_id, maf_id, dev_id, ver_id;
int density;
int syscfg;

Expand Down Expand Up @@ -1657,14 +1762,16 @@ static int onenand_probe(struct mtd_info *mtd)
/* Read manufacturer and device IDs from Register */
maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
ver_id= this->read_word(this->base + ONENAND_REG_VERSION_ID);

/* Check OneNAND device */
if (maf_id != bram_maf_id || dev_id != bram_dev_id)
return -ENXIO;

/* Flash device information */
onenand_print_device_info(dev_id);
onenand_print_device_info(dev_id, ver_id);
this->device_id = dev_id;
this->version_id = ver_id;

density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
this->chipsize = (16 << density) << 20;
Expand All @@ -1687,16 +1794,8 @@ static int onenand_probe(struct mtd_info *mtd)

mtd->size = this->chipsize;

/* Version ID */
version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id);

/* Lock scheme */
if (density <= ONENAND_DEVICE_DENSITY_512Mb &&
!(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) {
printk(KERN_INFO "Lock scheme is Continues Lock\n");
this->options |= ONENAND_CONT_LOCK;
}
/* Check OneNAND lock scheme */
onenand_lock_scheme(mtd);

return 0;
}
Expand Down Expand Up @@ -1832,7 +1931,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd->owner = THIS_MODULE;

/* Unlock whole block */
mtd->unlock(mtd, 0x0, this->chipsize);
onenand_unlock_all(mtd);

return this->scan_bbt(mtd);
}
Expand Down
6 changes: 4 additions & 2 deletions trunk/include/linux/mtd/onenand.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* linux/include/linux/mtd/onenand.h
*
* Copyright (C) 2005 Samsung Electronics
* Copyright (C) 2005-2006 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -96,6 +96,7 @@ struct onenand_chip {
void __iomem *base;
unsigned int chipsize;
unsigned int device_id;
unsigned int version_id;
unsigned int density_mask;
unsigned int options;

Expand Down Expand Up @@ -149,7 +150,8 @@ struct onenand_chip {
/*
* Options bits
*/
#define ONENAND_CONT_LOCK (0x0001)
#define ONENAND_HAS_CONT_LOCK (0x0001)
#define ONENAND_HAS_UNLOCK_ALL (0x0002)
#define ONENAND_PAGEBUF_ALLOC (0x1000)

/*
Expand Down
4 changes: 3 additions & 1 deletion trunk/include/linux/mtd/onenand_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* OneNAND Register header file
*
* Copyright (C) 2005 Samsung Electronics
* Copyright (C) 2005-2006 Samsung Electronics
*
* 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
Expand Down Expand Up @@ -72,6 +72,7 @@
#define ONENAND_DEVICE_VCC_MASK (0x3)

#define ONENAND_DEVICE_DENSITY_512Mb (0x002)
#define ONENAND_DEVICE_DENSITY_1Gb (0x003)

/*
* Version ID Register F002h (R)
Expand Down Expand Up @@ -110,6 +111,7 @@
#define ONENAND_CMD_UNLOCK (0x23)
#define ONENAND_CMD_LOCK (0x2A)
#define ONENAND_CMD_LOCK_TIGHT (0x2C)
#define ONENAND_CMD_UNLOCK_ALL (0x27)
#define ONENAND_CMD_ERASE (0x94)
#define ONENAND_CMD_RESET (0xF0)
#define ONENAND_CMD_OTP_ACCESS (0x65)
Expand Down

0 comments on commit 6957259

Please sign in to comment.