OneNAND: Probe correct lock scheme
Subsystems (3)
Kyungmin Park
maintainer[MTD ONENAND] Check OneNAND lock scheme & all block unlock command support
OneNAND lock scheme depends on density and process of chip. Some OneNAND chips support all block unlock
Signed-off-by Kyungmin Park <[email protected]>
---
drivers/mtd/onenand/onenand_base.c +118 -19
@@ -1,7 +1,7 @@/* * linux/drivers/mtd/onenand/onenand_base.c * -* Copyright (C) 2005 Samsung Electronics +* Copyright (C) 2005-2006 Samsung Electronics * Kyungmin Park <[email protected]> * * This program is free software; you can redistribute it and/or modify
@@ -199,6 +199,7 @@ static int onenand_command(struct mtd_incase ONENAND_CMD_UNLOCK :case ONENAND_CMD_LOCK :case ONENAND_CMD_LOCK_TIGHT : +case ONENAND_CMD_UNLOCK_ALL : block =-1 ; page =-1 ;break ;
@@ -1211,11 +1212,11 @@ static int onenand_unlock(struct mtd_inf 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 );
@@ -1236,7 +1237,7 @@ static int onenand_unlock(struct mtd_inf }/* 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 );
@@ -1265,6 +1266,79 @@ static int onenand_unlock(struct mtd_infreturn 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 */
@@ -1564,12 +1638,43 @@ static int onenand_lock_user_prot_reg(st#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;
@@ -1583,6 +1688,7 @@ static void onenand_print_device_info(in (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[] = {
@@ -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;
@@ -1657,14 +1762,16 @@ static int onenand_probe(struct mtd_info/* 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 ;
@@ -1687,16 +1794,8 @@ static int onenand_probe(struct mtd_info 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 ; }
@@ -1832,7 +1931,7 @@ int onenand_scan(struct mtd_info *mtd, i mtd->owner =THIS_MODULE ;/* Unlock whole block */ - mtd->unlock (mtd,0x0 , this->chipsize); +onenand_unlock_all (mtd);return this->scan_bbt (mtd); }
include/linux/mtd/onenand.h +4 -2
@@ -1,7 +1,7 @@/* * linux/include/linux/mtd/onenand.h * -* Copyright (C) 2005 Samsung Electronics +* Copyright (C) 2005-2006 Samsung Electronics * Kyungmin Park <[email protected]> * * This program is free software; you can redistribute it and/or modify
@@ -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;
@@ -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)/*
include/linux/mtd/onenand_regs.h +3 -1
@@ -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
@@ -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)
@@ -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)