davinci_nand.c revision 5e81e88a4c140586d9212999cea683bcd66a15c6
1ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/* 2ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * davinci_nand.c - NAND Flash Driver for DaVinci family chips 3ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 4ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * Copyright © 2006 Texas Instruments. 5ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 6ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * Port to 2.6.23 Copyright © 2008 by: 7ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * Sander Huijsen <Shuijsen@optelecom-nkf.com> 8ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * Troy Kisky <troy.kisky@boundarydevices.com> 9ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * Dirk Behme <Dirk.Behme@gmail.com> 10ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 11ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * This program is free software; you can redistribute it and/or modify 12ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * it under the terms of the GNU General Public License as published by 13ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * the Free Software Foundation; either version 2 of the License, or 14ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * (at your option) any later version. 15ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 16ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * This program is distributed in the hope that it will be useful, 17ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * but WITHOUT ANY WARRANTY; without even the implied warranty of 18ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * GNU General Public License for more details. 20ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 21ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * You should have received a copy of the GNU General Public License 22ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * along with this program; if not, write to the Free Software 23ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 25ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 26ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <linux/kernel.h> 27ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <linux/init.h> 28ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <linux/module.h> 29ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <linux/platform_device.h> 30ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <linux/err.h> 31ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <linux/clk.h> 32ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <linux/io.h> 33ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <linux/mtd/nand.h> 34ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <linux/mtd/partitions.h> 35ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 36ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <mach/nand.h> 37ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 38ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <asm/mach-types.h> 39ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 40ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 41ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/* 42ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * This is a device driver for the NAND flash controller found on the 43ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * various DaVinci family chips. It handles up to four SoC chipselects, 44ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * and some flavors of secondary chipselect (e.g. based on A12) as used 45ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * with multichip packages. 46ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 476a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * The 1-bit ECC hardware is supported, as well as the newer 4-bit ECC 48ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * available on chips like the DM355 and OMAP-L137 and needed with the 49ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * more error-prone MLC NAND chips. 50ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 51ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * This driver assumes EM_WAIT connects all the NAND devices' RDY/nBUSY 52ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * outputs in a "wire-AND" configuration, with no per-chip signals. 53ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 54ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstruct davinci_nand_info { 55ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct mtd_info mtd; 56ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct nand_chip chip; 576a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell struct nand_ecclayout ecclayout; 58ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 59ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct device *dev; 60ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct clk *clk; 61ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell bool partitioned; 62ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 636a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell bool is_readmode; 646a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 65ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell void __iomem *base; 66ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell void __iomem *vaddr; 67ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 68ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t ioaddr; 69ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t current_cs; 70ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 71ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t mask_chipsel; 72ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t mask_ale; 73ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t mask_cle; 74ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 75ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t core_chipsel; 76ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell}; 77ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 78ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic DEFINE_SPINLOCK(davinci_nand_lock); 796a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellstatic bool ecc4_busy; 80ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 81ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#define to_davinci_nand(m) container_of(m, struct davinci_nand_info, mtd) 82ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 83ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 84ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic inline unsigned int davinci_nand_readl(struct davinci_nand_info *info, 85ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell int offset) 86ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 87ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return __raw_readl(info->base + offset); 88ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 89ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 90ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic inline void davinci_nand_writel(struct davinci_nand_info *info, 91ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell int offset, unsigned long value) 92ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 93ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell __raw_writel(value, info->base + offset); 94ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 95ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 96ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/*----------------------------------------------------------------------*/ 97ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 98ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/* 99ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * Access to hardware control lines: ALE, CLE, secondary chipselect. 100ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 101ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 102ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, 103ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell unsigned int ctrl) 104ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 105ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_info *info = to_davinci_nand(mtd); 106ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t addr = info->current_cs; 107ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct nand_chip *nand = mtd->priv; 108ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 109ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Did the control lines change? */ 110ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (ctrl & NAND_CTRL_CHANGE) { 111ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if ((ctrl & NAND_CTRL_CLE) == NAND_CTRL_CLE) 112ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell addr |= info->mask_cle; 113ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE) 114ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell addr |= info->mask_ale; 115ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 116ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell nand->IO_ADDR_W = (void __iomem __force *)addr; 117ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 118ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 119ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (cmd != NAND_CMD_NONE) 120ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iowrite8(cmd, nand->IO_ADDR_W); 121ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 122ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 123ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic void nand_davinci_select_chip(struct mtd_info *mtd, int chip) 124ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 125ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_info *info = to_davinci_nand(mtd); 126ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t addr = info->ioaddr; 127ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 128ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* maybe kick in a second chipselect */ 129ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (chip > 0) 130ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell addr |= info->mask_chipsel; 131ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->current_cs = addr; 132ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 133ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.IO_ADDR_W = (void __iomem __force *)addr; 134ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.IO_ADDR_R = info->chip.IO_ADDR_W; 135ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 136ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 137ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/*----------------------------------------------------------------------*/ 138ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 139ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/* 140ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 1-bit hardware ECC ... context maintained for each core chipselect 141ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 142ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 143ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd) 144ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 145ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_info *info = to_davinci_nand(mtd); 146ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 147ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return davinci_nand_readl(info, NANDF1ECC_OFFSET 148ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell + 4 * info->core_chipsel); 149ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 150ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 151ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode) 152ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 153ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_info *info; 154ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t nandcfr; 155ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell unsigned long flags; 156ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 157ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info = to_davinci_nand(mtd); 158ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 159ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Reset ECC hardware */ 160ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell nand_davinci_readecc_1bit(mtd); 161ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 162ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell spin_lock_irqsave(&davinci_nand_lock, flags); 163ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 164ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Restart ECC hardware */ 165ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell nandcfr = davinci_nand_readl(info, NANDFCR_OFFSET); 166ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell nandcfr |= BIT(8 + info->core_chipsel); 167ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell davinci_nand_writel(info, NANDFCR_OFFSET, nandcfr); 168ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 169ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell spin_unlock_irqrestore(&davinci_nand_lock, flags); 170ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 171ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 172ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/* 173ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * Read hardware ECC value and pack into three bytes 174ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 175ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic int nand_davinci_calculate_1bit(struct mtd_info *mtd, 176ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell const u_char *dat, u_char *ecc_code) 177ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 178ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell unsigned int ecc_val = nand_davinci_readecc_1bit(mtd); 179ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4); 180ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 181ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* invert so that erased block ecc is correct */ 182ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ecc24 = ~ecc24; 183ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ecc_code[0] = (u_char)(ecc24); 184ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ecc_code[1] = (u_char)(ecc24 >> 8); 185ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ecc_code[2] = (u_char)(ecc24 >> 16); 186ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 187ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return 0; 188ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 189ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 190ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat, 191ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell u_char *read_ecc, u_char *calc_ecc) 192ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 193ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct nand_chip *chip = mtd->priv; 194ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) | 195ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell (read_ecc[2] << 16); 196ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) | 197ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell (calc_ecc[2] << 16); 198ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t diff = eccCalc ^ eccNand; 199ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 200ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (diff) { 201ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) { 202ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Correctable error */ 203ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if ((diff >> (12 + 3)) < chip->ecc.size) { 204ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7); 205ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return 1; 206ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } else { 207ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return -1; 208ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 209ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } else if (!(diff & (diff - 1))) { 210ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Single bit ECC error in the ECC itself, 211ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * nothing to fix */ 212ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return 1; 213ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } else { 214ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Uncorrectable error */ 215ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return -1; 216ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 217ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 218ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 219ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return 0; 220ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 221ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 222ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/*----------------------------------------------------------------------*/ 223ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 224ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/* 2256a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * 4-bit hardware ECC ... context maintained over entire AEMIF 2266a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * 2276a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * This is a syndrome engine, but we avoid NAND_ECC_HW_SYNDROME 2286a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * since that forces use of a problematic "infix OOB" layout. 2296a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * Among other things, it trashes manufacturer bad block markers. 2306a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * Also, and specific to this hardware, it ECC-protects the "prepad" 2316a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * in the OOB ... while having ECC protection for parts of OOB would 2326a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * seem useful, the current MTD stack sometimes wants to update the 2336a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * OOB without recomputing ECC. 2346a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 2356a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 2366a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellstatic void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode) 2376a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell{ 2386a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell struct davinci_nand_info *info = to_davinci_nand(mtd); 2396a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell unsigned long flags; 2406a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell u32 val; 2416a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 2426a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_lock_irqsave(&davinci_nand_lock, flags); 2436a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 2446a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Start 4-bit ECC calculation for read/write */ 2456a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell val = davinci_nand_readl(info, NANDFCR_OFFSET); 2466a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell val &= ~(0x03 << 4); 2476a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell val |= (info->core_chipsel << 4) | BIT(12); 2486a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell davinci_nand_writel(info, NANDFCR_OFFSET, val); 2496a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 2506a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->is_readmode = (mode == NAND_ECC_READ); 2516a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 2526a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_unlock_irqrestore(&davinci_nand_lock, flags); 2536a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell} 2546a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 2556a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell/* Read raw ECC code after writing to NAND. */ 2566a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellstatic void 2576a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellnand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4]) 2586a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell{ 2596a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell const u32 mask = 0x03ff03ff; 2606a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 2616a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell code[0] = davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET) & mask; 2626a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell code[1] = davinci_nand_readl(info, NAND_4BIT_ECC2_OFFSET) & mask; 2636a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell code[2] = davinci_nand_readl(info, NAND_4BIT_ECC3_OFFSET) & mask; 2646a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell code[3] = davinci_nand_readl(info, NAND_4BIT_ECC4_OFFSET) & mask; 2656a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell} 2666a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 2676a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell/* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */ 2686a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellstatic int nand_davinci_calculate_4bit(struct mtd_info *mtd, 2696a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell const u_char *dat, u_char *ecc_code) 2706a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell{ 2716a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell struct davinci_nand_info *info = to_davinci_nand(mtd); 2726a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell u32 raw_ecc[4], *p; 2736a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell unsigned i; 2746a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 2756a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* After a read, terminate ECC calculation by a dummy read 2766a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * of some 4-bit ECC register. ECC covers everything that 2776a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * was read; correct() just uses the hardware state, so 2786a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * ecc_code is not needed. 2796a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 2806a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (info->is_readmode) { 2816a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET); 2826a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return 0; 2836a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 2846a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 2856a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Pack eight raw 10-bit ecc values into ten bytes, making 2866a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * two passes which each convert four values (in upper and 2876a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * lower halves of two 32-bit words) into five bytes. The 2886a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * ROM boot loader uses this same packing scheme. 2896a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 2906a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell nand_davinci_readecc_4bit(info, raw_ecc); 2916a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell for (i = 0, p = raw_ecc; i < 2; i++, p += 2) { 2926a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell *ecc_code++ = p[0] & 0xff; 2936a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell *ecc_code++ = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc); 2946a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell *ecc_code++ = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0); 2956a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell *ecc_code++ = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0); 2966a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell *ecc_code++ = (p[1] >> 18) & 0xff; 2976a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 2986a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 2996a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return 0; 3006a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell} 3016a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3026a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell/* Correct up to 4 bits in data we just read, using state left in the 3036a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * hardware plus the ecc_code computed when it was first written. 3046a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 3056a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellstatic int nand_davinci_correct_4bit(struct mtd_info *mtd, 3066a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell u_char *data, u_char *ecc_code, u_char *null) 3076a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell{ 3086a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell int i; 3096a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell struct davinci_nand_info *info = to_davinci_nand(mtd); 3106a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell unsigned short ecc10[8]; 3116a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell unsigned short *ecc16; 3126a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell u32 syndrome[4]; 3136a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell unsigned num_errors, corrected; 3146a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3156a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* All bytes 0xff? It's an erased page; ignore its ECC. */ 3166a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell for (i = 0; i < 10; i++) { 3176a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (ecc_code[i] != 0xff) 3186a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto compare; 3196a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 3206a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return 0; 3216a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3226a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellcompare: 3236a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Unpack ten bytes into eight 10 bit values. We know we're 3246a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * little-endian, and use type punning for less shifting/masking. 3256a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 3266a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (WARN_ON(0x01 & (unsigned) ecc_code)) 3276a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return -EINVAL; 3286a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc16 = (unsigned short *)ecc_code; 3296a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3306a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[0] = (ecc16[0] >> 0) & 0x3ff; 3316a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[1] = ((ecc16[0] >> 10) & 0x3f) | ((ecc16[1] << 6) & 0x3c0); 3326a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[2] = (ecc16[1] >> 4) & 0x3ff; 3336a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[3] = ((ecc16[1] >> 14) & 0x3) | ((ecc16[2] << 2) & 0x3fc); 3346a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[4] = (ecc16[2] >> 8) | ((ecc16[3] << 8) & 0x300); 3356a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[5] = (ecc16[3] >> 2) & 0x3ff; 3366a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[6] = ((ecc16[3] >> 12) & 0xf) | ((ecc16[4] << 4) & 0x3f0); 3376a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[7] = (ecc16[4] >> 6) & 0x3ff; 3386a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3396a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Tell ECC controller about the expected ECC codes. */ 3406a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell for (i = 7; i >= 0; i--) 3416a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell davinci_nand_writel(info, NAND_4BIT_ECC_LOAD_OFFSET, ecc10[i]); 3426a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3436a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Allow time for syndrome calculation ... then read it. 3446a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * A syndrome of all zeroes 0 means no detected errors. 3456a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 3466a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell davinci_nand_readl(info, NANDFSR_OFFSET); 3476a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell nand_davinci_readecc_4bit(info, syndrome); 3486a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3])) 3496a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return 0; 3506a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 351f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* 352f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * Clear any previous address calculation by doing a dummy read of an 353f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * error address register. 354f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje */ 355f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje davinci_nand_readl(info, NAND_ERR_ADD1_OFFSET); 356f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje 3576a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Start address calculation, and wait for it to complete. 3586a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * We _could_ start reading more data while this is working, 3596a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * to speed up the overall page read. 3606a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 3616a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell davinci_nand_writel(info, NANDFCR_OFFSET, 3626a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell davinci_nand_readl(info, NANDFCR_OFFSET) | BIT(13)); 3636a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell for (;;) { 3646a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell u32 fsr = davinci_nand_readl(info, NANDFSR_OFFSET); 3656a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3666a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell switch ((fsr >> 8) & 0x0f) { 3676a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell case 0: /* no error, should not happen */ 368f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET); 3696a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return 0; 3706a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell case 1: /* five or more errors detected */ 371f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET); 3726a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return -EIO; 3736a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell case 2: /* error addresses computed */ 3746a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell case 3: 3756a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell num_errors = 1 + ((fsr >> 16) & 0x03); 3766a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto correct; 3776a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell default: /* still working on it */ 3786a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell cpu_relax(); 3796a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell continue; 3806a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 3816a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 3826a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3836a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellcorrect: 3846a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* correct each error */ 3856a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell for (i = 0, corrected = 0; i < num_errors; i++) { 3866a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell int error_address, error_value; 3876a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3886a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (i > 1) { 3896a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_address = davinci_nand_readl(info, 3906a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell NAND_ERR_ADD2_OFFSET); 3916a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_value = davinci_nand_readl(info, 3926a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell NAND_ERR_ERRVAL2_OFFSET); 3936a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } else { 3946a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_address = davinci_nand_readl(info, 3956a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell NAND_ERR_ADD1_OFFSET); 3966a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_value = davinci_nand_readl(info, 3976a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell NAND_ERR_ERRVAL1_OFFSET); 3986a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 3996a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4006a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (i & 1) { 4016a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_address >>= 16; 4026a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_value >>= 16; 4036a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 4046a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_address &= 0x3ff; 4056a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_address = (512 + 7) - error_address; 4066a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4076a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (error_address < 512) { 4086a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell data[error_address] ^= error_value; 4096a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell corrected++; 4106a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 4116a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 4126a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4136a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return corrected; 4146a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell} 4156a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4166a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell/*----------------------------------------------------------------------*/ 4176a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4186a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell/* 419ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * NOTE: NAND boot requires ALE == EM_A[1], CLE == EM_A[2], so that's 420ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * how these chips are normally wired. This translates to both 8 and 16 421ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * bit busses using ALE == BIT(3) in byte addresses, and CLE == BIT(4). 422ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 423ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * For now we assume that configuration, or any other one which ignores 424ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * the two LSBs for NAND access ... so we can issue 32-bit reads/writes 425ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * and have that transparently morphed into multiple NAND operations. 426ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 427ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) 428ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 429ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct nand_chip *chip = mtd->priv; 430ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 431ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0) 432ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ioread32_rep(chip->IO_ADDR_R, buf, len >> 2); 433ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0) 434ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ioread16_rep(chip->IO_ADDR_R, buf, len >> 1); 435ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell else 436ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ioread8_rep(chip->IO_ADDR_R, buf, len); 437ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 438ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 439ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic void nand_davinci_write_buf(struct mtd_info *mtd, 440ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell const uint8_t *buf, int len) 441ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 442ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct nand_chip *chip = mtd->priv; 443ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 444ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0) 445ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2); 446ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0) 447ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1); 448ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell else 449ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iowrite8_rep(chip->IO_ADDR_R, buf, len); 450ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 451ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 452ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/* 453ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * Check hardware register for wait status. Returns 1 if device is ready, 454ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 0 if it is still busy. 455ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 456ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic int nand_davinci_dev_ready(struct mtd_info *mtd) 457ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 458ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_info *info = to_davinci_nand(mtd); 459ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 460ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0); 461ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 462ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 463ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic void __init nand_dm6446evm_flash_init(struct davinci_nand_info *info) 464ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 465ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t regval, a1cr; 466ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 467ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* 468ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * NAND FLASH timings @ PLL1 == 459 MHz 469ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * - AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz 470ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * - AEMIF.CLK period = 1/76.5 MHz = 13.1 ns 471ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 472ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell regval = 0 473ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell | (0 << 31) /* selectStrobe */ 474ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell | (0 << 30) /* extWait (never with NAND) */ 475ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell | (1 << 26) /* writeSetup 10 ns */ 476ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell | (3 << 20) /* writeStrobe 40 ns */ 477ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell | (1 << 17) /* writeHold 10 ns */ 478ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell | (0 << 13) /* readSetup 10 ns */ 479ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell | (3 << 7) /* readStrobe 60 ns */ 480ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell | (0 << 4) /* readHold 10 ns */ 481ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell | (3 << 2) /* turnAround ?? ns */ 482ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell | (0 << 0) /* asyncSize 8-bit bus */ 483ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ; 484ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell a1cr = davinci_nand_readl(info, A1CR_OFFSET); 485ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (a1cr != regval) { 486ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_dbg(info->dev, "Warning: NAND config: Set A1CR " \ 487ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell "reg to 0x%08x, was 0x%08x, should be done by " \ 488ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell "bootloader.\n", regval, a1cr); 489ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell davinci_nand_writel(info, A1CR_OFFSET, regval); 490ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 491ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 492ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 493ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/*----------------------------------------------------------------------*/ 494ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 4956a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell/* An ECC layout for using 4-bit ECC with small-page flash, storing 4966a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * ten ECC bytes plus the manufacturer's bad block marker byte, and 4976a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * and not overlapping the default BBT markers. 4986a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 4996a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellstatic struct nand_ecclayout hwecc4_small __initconst = { 5006a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell .eccbytes = 10, 5016a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell .eccpos = { 0, 1, 2, 3, 4, 5026a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* offset 5 holds the badblock marker */ 5036a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 6, 7, 5046a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 13, 14, 15, }, 5056a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell .oobfree = { 5066a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell {.offset = 8, .length = 5, }, 5076a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell {.offset = 16, }, 5086a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell }, 5096a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell}; 5106a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 511f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje/* An ECC layout for using 4-bit ECC with large-page (2048bytes) flash, 512f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * storing ten ECC bytes plus the manufacturer's bad block marker byte, 513f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * and not overlapping the default BBT markers. 514f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje */ 515f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakajestatic struct nand_ecclayout hwecc4_2048 __initconst = { 516f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje .eccbytes = 40, 517f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje .eccpos = { 518f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* at the end of spare sector */ 519f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 520f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 521f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 522f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 523f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje }, 524f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje .oobfree = { 525f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* 2 bytes at offset 0 hold manufacturer badblock markers */ 526f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje {.offset = 2, .length = 22, }, 527f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* 5 bytes at offset 8 hold BBT markers */ 528f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* 8 bytes at offset 16 hold JFFS2 clean markers */ 529f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje }, 530f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje}; 5316a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 532ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic int __init nand_davinci_probe(struct platform_device *pdev) 533ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 534ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_pdata *pdata = pdev->dev.platform_data; 535ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_info *info; 536ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct resource *res1; 537ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct resource *res2; 538ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell void __iomem *vaddr; 539ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell void __iomem *base; 540ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell int ret; 541ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t val; 542ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell nand_ecc_modes_t ecc_mode; 543ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 544533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell /* insist on board-specific configuration */ 545533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell if (!pdata) 546533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell return -ENODEV; 547533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell 548ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* which external chipselect will we be managing? */ 549ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (pdev->id < 0 || pdev->id > 3) 550ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return -ENODEV; 551ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 552ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info = kzalloc(sizeof(*info), GFP_KERNEL); 553ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (!info) { 554ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_err(&pdev->dev, "unable to allocate memory\n"); 555ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = -ENOMEM; 556ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_nomem; 557ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 558ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 559ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell platform_set_drvdata(pdev, info); 560ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 561ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); 562ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); 563ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (!res1 || !res2) { 564ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_err(&pdev->dev, "resource missing\n"); 565ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = -EINVAL; 566ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_nomem; 567ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 568ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 569d8bc55553c416c877267c1efd65b099164acbe3fH Hartley Sweeten vaddr = ioremap(res1->start, resource_size(res1)); 570d8bc55553c416c877267c1efd65b099164acbe3fH Hartley Sweeten base = ioremap(res2->start, resource_size(res2)); 571ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (!vaddr || !base) { 572ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_err(&pdev->dev, "ioremap failed\n"); 573ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = -EINVAL; 574ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_ioremap; 575ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 576ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 577ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->dev = &pdev->dev; 578ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->base = base; 579ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->vaddr = vaddr; 580ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 581ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->mtd.priv = &info->chip; 582ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->mtd.name = dev_name(&pdev->dev); 583ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->mtd.owner = THIS_MODULE; 584ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 58587f39f0493edf7051b1b87c6e9eb7f9a74be8e85David Brownell info->mtd.dev.parent = &pdev->dev; 58687f39f0493edf7051b1b87c6e9eb7f9a74be8e85David Brownell 587ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.IO_ADDR_R = vaddr; 588ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.IO_ADDR_W = vaddr; 589ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.chip_delay = 0; 590ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.select_chip = nand_davinci_select_chip; 591ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 592ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* options such as NAND_USE_FLASH_BBT or 16-bit widths */ 593533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell info->chip.options = pdata->options; 594f611a79fe9859a30f2a7ae94b4d24f8e2dd75c91Mark A. Greer info->chip.bbt_td = pdata->bbt_td; 595f611a79fe9859a30f2a7ae94b4d24f8e2dd75c91Mark A. Greer info->chip.bbt_md = pdata->bbt_md; 596ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 597ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->ioaddr = (uint32_t __force) vaddr; 598ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 599ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->current_cs = info->ioaddr; 600ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->core_chipsel = pdev->id; 601ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->mask_chipsel = pdata->mask_chipsel; 602ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 603ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* use nandboot-capable ALE/CLE masks by default */ 6045cd0be8ec946ee3901e7f651a795225c6badff8fHemant Pedanekar info->mask_ale = pdata->mask_ale ? : MASK_ALE; 605533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell info->mask_cle = pdata->mask_cle ? : MASK_CLE; 606ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 607ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Set address of hardware control function */ 608ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.cmd_ctrl = nand_davinci_hwcontrol; 609ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.dev_ready = nand_davinci_dev_ready; 610ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 611ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Speed up buffer I/O */ 612ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.read_buf = nand_davinci_read_buf; 613ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.write_buf = nand_davinci_write_buf; 614ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 615533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell /* Use board-specific ECC config */ 616533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell ecc_mode = pdata->ecc_mode; 617ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 6186a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ret = -EINVAL; 619ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell switch (ecc_mode) { 620ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell case NAND_ECC_NONE: 621ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell case NAND_ECC_SOFT: 6226a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell pdata->ecc_bits = 0; 623ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell break; 624ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell case NAND_ECC_HW: 6256a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (pdata->ecc_bits == 4) { 6266a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* No sanity checks: CPUs must support this, 6276a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * and the chips may not use NAND_BUSWIDTH_16. 6286a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 6296a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 6306a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* No sharing 4-bit hardware between chipselects yet */ 6316a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_lock_irq(&davinci_nand_lock); 6326a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (ecc4_busy) 6336a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ret = -EBUSY; 6346a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell else 6356a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc4_busy = true; 6366a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_unlock_irq(&davinci_nand_lock); 6376a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 6386a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (ret == -EBUSY) 6396a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto err_ecc; 6406a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 6416a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.calculate = nand_davinci_calculate_4bit; 6426a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.correct = nand_davinci_correct_4bit; 6436a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.hwctl = nand_davinci_hwctl_4bit; 6446a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.bytes = 10; 6456a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } else { 6466a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.calculate = nand_davinci_calculate_1bit; 6476a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.correct = nand_davinci_correct_1bit; 6486a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.hwctl = nand_davinci_hwctl_1bit; 6496a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.bytes = 3; 6506a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 651ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.ecc.size = 512; 652ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell break; 653ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell default: 654ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = -EINVAL; 655ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_ecc; 656ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 657ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.ecc.mode = ecc_mode; 658ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 659cd24f8c1e7e27a2c6051a9a338d4704a2431dbf0Kevin Hilman info->clk = clk_get(&pdev->dev, "aemif"); 660ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (IS_ERR(info->clk)) { 661ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = PTR_ERR(info->clk); 662cd24f8c1e7e27a2c6051a9a338d4704a2431dbf0Kevin Hilman dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret); 663ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_clk; 664ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 665ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 666ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = clk_enable(info->clk); 667ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (ret < 0) { 668cd24f8c1e7e27a2c6051a9a338d4704a2431dbf0Kevin Hilman dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n", 669cd24f8c1e7e27a2c6051a9a338d4704a2431dbf0Kevin Hilman ret); 670ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_clk_enable; 671ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 672ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 673ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* EMIF timings should normally be set by the boot loader, 674ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * especially after boot-from-NAND. The *only* reason to 675ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * have this special casing for the DM6446 EVM is to work 676ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * with boot-from-NOR ... with CS0 manually re-jumpered 677ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * (after startup) so it addresses the NAND flash, not NOR. 678ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * Even for dev boards, that's unusually rude... 679ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 680ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (machine_is_davinci_evm()) 681ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell nand_dm6446evm_flash_init(info); 682ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 683ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell spin_lock_irq(&davinci_nand_lock); 684ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 685ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* put CSxNAND into NAND mode */ 686ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell val = davinci_nand_readl(info, NANDFCR_OFFSET); 687ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell val |= BIT(info->core_chipsel); 688ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell davinci_nand_writel(info, NANDFCR_OFFSET, val); 689ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 690ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell spin_unlock_irq(&davinci_nand_lock); 691ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 692ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Scan to find existence of the device(s) */ 6935e81e88a4c140586d9212999cea683bcd66a15c6David Woodhouse ret = nand_scan_ident(&info->mtd, pdata->mask_chipsel ? 2 : 1, NULL); 694ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (ret < 0) { 695ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_dbg(&pdev->dev, "no NAND chip(s) found\n"); 696ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_scan; 697ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 698ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 6996a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Update ECC layout if needed ... for 1-bit HW ECC, the default 7006a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * is OK, but it allocates 6 bytes when only 3 are needed (for 7016a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * each 512 bytes). For the 4-bit HW ECC, that default is not 7026a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * usable: 10 bytes are needed, not 6. 7036a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 7046a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (pdata->ecc_bits == 4) { 7056a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell int chunks = info->mtd.writesize / 512; 7066a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 7076a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (!chunks || info->mtd.oobsize < 16) { 7086a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell dev_dbg(&pdev->dev, "too small\n"); 7096a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ret = -EINVAL; 7106a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto err_scan; 7116a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 7126a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 7136a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* For small page chips, preserve the manufacturer's 7146a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * badblock marking data ... and make sure a flash BBT 7156a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * table marker fits in the free bytes. 7166a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 7176a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (chunks == 1) { 7186a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->ecclayout = hwecc4_small; 7196a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->ecclayout.oobfree[1].length = 7206a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->mtd.oobsize - 16; 7216a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto syndrome_done; 7226a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 723f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje if (chunks == 4) { 724f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje info->ecclayout = hwecc4_2048; 725f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST; 726f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje goto syndrome_done; 727f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje } 7286a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 729f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* 4KiB page chips are not yet supported. The eccpos from 730f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * nand_ecclayout cannot hold 80 bytes and change to eccpos[] 731f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * breaks userspace ioctl interface with mtd-utils. Once we 732f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used 733f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * for the 4KiB page chips. 7346a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 7356a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell dev_warn(&pdev->dev, "no 4-bit ECC support yet " 736f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje "for 4KiB-page NAND\n"); 7376a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ret = -EIO; 7386a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto err_scan; 7396a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 7406a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellsyndrome_done: 7416a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.layout = &info->ecclayout; 7426a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 7436a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 7446a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ret = nand_scan_tail(&info->mtd); 7456a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (ret < 0) 7466a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto err_scan; 7476a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 748ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (mtd_has_partitions()) { 749ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct mtd_partition *mtd_parts = NULL; 750ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell int mtd_parts_nb = 0; 751ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 752ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (mtd_has_cmdlinepart()) { 753ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell static const char *probes[] __initconst = 754ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell { "cmdlinepart", NULL }; 755ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 756ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell mtd_parts_nb = parse_mtd_partitions(&info->mtd, probes, 757ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell &mtd_parts, 0); 758ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 759ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 760533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell if (mtd_parts_nb <= 0) { 761ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell mtd_parts = pdata->parts; 762ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell mtd_parts_nb = pdata->nr_parts; 763ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 764ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 765ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Register any partitions */ 766ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (mtd_parts_nb > 0) { 767ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = add_mtd_partitions(&info->mtd, 768ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell mtd_parts, mtd_parts_nb); 769ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (ret == 0) 770ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->partitioned = true; 771ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 772ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 773533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell } else if (pdata->nr_parts) { 774ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_warn(&pdev->dev, "ignoring %d default partitions on %s\n", 775ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell pdata->nr_parts, info->mtd.name); 776ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 777ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 778ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* If there's no partition info, just package the whole chip 779ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * as a single MTD device. 780ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 781ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (!info->partitioned) 782ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = add_mtd_device(&info->mtd) ? -ENODEV : 0; 783ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 784ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (ret < 0) 785ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_scan; 786ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 787ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell val = davinci_nand_readl(info, NRCSR_OFFSET); 788ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_info(&pdev->dev, "controller rev. %d.%d\n", 789ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell (val >> 8) & 0xff, val & 0xff); 790ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 791ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return 0; 792ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 793ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_scan: 794ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell clk_disable(info->clk); 795ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 796ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_clk_enable: 797ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell clk_put(info->clk); 798ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 7996a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_lock_irq(&davinci_nand_lock); 8006a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (ecc_mode == NAND_ECC_HW_SYNDROME) 8016a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc4_busy = false; 8026a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_unlock_irq(&davinci_nand_lock); 8036a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 804ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_ecc: 805ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_clk: 806ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_ioremap: 807ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (base) 808ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iounmap(base); 809ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (vaddr) 810ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iounmap(vaddr); 811ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 812ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_nomem: 813ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell kfree(info); 814ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return ret; 815ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 816ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 817ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic int __exit nand_davinci_remove(struct platform_device *pdev) 818ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 819ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_info *info = platform_get_drvdata(pdev); 820ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell int status; 821ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 822ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (mtd_has_partitions() && info->partitioned) 823ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell status = del_mtd_partitions(&info->mtd); 824ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell else 825ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell status = del_mtd_device(&info->mtd); 826ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 8276a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_lock_irq(&davinci_nand_lock); 8286a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME) 8296a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc4_busy = false; 8306a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_unlock_irq(&davinci_nand_lock); 8316a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 832ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iounmap(info->base); 833ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iounmap(info->vaddr); 834ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 835ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell nand_release(&info->mtd); 836ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 837ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell clk_disable(info->clk); 838ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell clk_put(info->clk); 839ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 840ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell kfree(info); 841ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 842ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return 0; 843ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 844ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 845ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic struct platform_driver nand_davinci_driver = { 846ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell .remove = __exit_p(nand_davinci_remove), 847ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell .driver = { 848ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell .name = "davinci_nand", 849ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell }, 850ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell}; 851ff4569c752c577c7e71e03c9d59e6ef85ca763c0David BrownellMODULE_ALIAS("platform:davinci_nand"); 852ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 853ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic int __init nand_davinci_init(void) 854ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 855ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return platform_driver_probe(&nand_davinci_driver, nand_davinci_probe); 856ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 857ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellmodule_init(nand_davinci_init); 858ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 859ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic void __exit nand_davinci_exit(void) 860ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 861ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell platform_driver_unregister(&nand_davinci_driver); 862ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 863ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellmodule_exit(nand_davinci_exit); 864ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 865ff4569c752c577c7e71e03c9d59e6ef85ca763c0David BrownellMODULE_LICENSE("GPL"); 866ff4569c752c577c7e71e03c9d59e6ef85ca763c0David BrownellMODULE_AUTHOR("Texas Instruments"); 867ff4569c752c577c7e71e03c9d59e6ef85ca763c0David BrownellMODULE_DESCRIPTION("Davinci NAND flash driver"); 868ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 869