Loading drivers/mtd/onenand/onenand_base.c +118 −19 Original line number Diff line number Diff line /* * 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 Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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 */ Loading Loading @@ -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; Loading @@ -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[] = { Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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); } Loading include/linux/mtd/onenand.h +4 −2 Original line number Diff line number Diff line /* * 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 Loading Loading @@ -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; Loading Loading @@ -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) /* Loading include/linux/mtd/onenand_regs.h +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) Loading Loading @@ -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) Loading Loading
drivers/mtd/onenand/onenand_base.c +118 −19 Original line number Diff line number Diff line /* * 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 Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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 */ Loading Loading @@ -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; Loading @@ -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[] = { Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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); } Loading
include/linux/mtd/onenand.h +4 −2 Original line number Diff line number Diff line /* * 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 Loading Loading @@ -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; Loading Loading @@ -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) /* Loading
include/linux/mtd/onenand_regs.h +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) Loading Loading @@ -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) Loading