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> 355a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 36ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 37ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell#include <mach/nand.h> 388060ef4da9e73f461adf2ba1922ea5400a61cf98Sekhar Nori#include <mach/aemif.h> 39ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 40ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/* 41ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * This is a device driver for the NAND flash controller found on the 42ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * various DaVinci family chips. It handles up to four SoC chipselects, 43ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * and some flavors of secondary chipselect (e.g. based on A12) as used 44ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * with multichip packages. 45ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 466a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * The 1-bit ECC hardware is supported, as well as the newer 4-bit ECC 47ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * available on chips like the DM355 and OMAP-L137 and needed with the 48ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * more error-prone MLC NAND chips. 49ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 50ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * This driver assumes EM_WAIT connects all the NAND devices' RDY/nBUSY 51ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * outputs in a "wire-AND" configuration, with no per-chip signals. 52ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 53ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstruct davinci_nand_info { 54ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct mtd_info mtd; 55ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct nand_chip chip; 566a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell struct nand_ecclayout ecclayout; 57ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 58ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct device *dev; 59ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct clk *clk; 60ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 616a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell bool is_readmode; 626a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 63ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell void __iomem *base; 64ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell void __iomem *vaddr; 65ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 66ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t ioaddr; 67ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t current_cs; 68ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 69ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t mask_chipsel; 70ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t mask_ale; 71ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t mask_cle; 72ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 73ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t core_chipsel; 74a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori 75a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori struct davinci_aemif_timing *timing; 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]; 3131c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara u32 ecc_state; 3146a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell unsigned num_errors, corrected; 3152bdb053a8119355eada46dfab88782449a26b39dWolfram Sang unsigned long timeo; 3166a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3176a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* All bytes 0xff? It's an erased page; ignore its ECC. */ 3186a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell for (i = 0; i < 10; i++) { 3196a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (ecc_code[i] != 0xff) 3206a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto compare; 3216a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 3226a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return 0; 3236a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3246a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellcompare: 3256a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Unpack ten bytes into eight 10 bit values. We know we're 3266a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * little-endian, and use type punning for less shifting/masking. 3276a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 3286a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (WARN_ON(0x01 & (unsigned) ecc_code)) 3296a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return -EINVAL; 3306a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc16 = (unsigned short *)ecc_code; 3316a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3326a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[0] = (ecc16[0] >> 0) & 0x3ff; 3336a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[1] = ((ecc16[0] >> 10) & 0x3f) | ((ecc16[1] << 6) & 0x3c0); 3346a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[2] = (ecc16[1] >> 4) & 0x3ff; 3356a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[3] = ((ecc16[1] >> 14) & 0x3) | ((ecc16[2] << 2) & 0x3fc); 3366a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[4] = (ecc16[2] >> 8) | ((ecc16[3] << 8) & 0x300); 3376a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[5] = (ecc16[3] >> 2) & 0x3ff; 3386a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[6] = ((ecc16[3] >> 12) & 0xf) | ((ecc16[4] << 4) & 0x3f0); 3396a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc10[7] = (ecc16[4] >> 6) & 0x3ff; 3406a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3416a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Tell ECC controller about the expected ECC codes. */ 3426a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell for (i = 7; i >= 0; i--) 3436a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell davinci_nand_writel(info, NAND_4BIT_ECC_LOAD_OFFSET, ecc10[i]); 3446a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3456a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Allow time for syndrome calculation ... then read it. 3466a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * A syndrome of all zeroes 0 means no detected errors. 3476a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 3486a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell davinci_nand_readl(info, NANDFSR_OFFSET); 3496a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell nand_davinci_readecc_4bit(info, syndrome); 3506a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3])) 3516a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return 0; 3526a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 353f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* 354f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * Clear any previous address calculation by doing a dummy read of an 355f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * error address register. 356f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje */ 357f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje davinci_nand_readl(info, NAND_ERR_ADD1_OFFSET); 358f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje 3596a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Start address calculation, and wait for it to complete. 3606a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * We _could_ start reading more data while this is working, 3616a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * to speed up the overall page read. 3626a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 3636a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell davinci_nand_writel(info, NANDFCR_OFFSET, 3646a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell davinci_nand_readl(info, NANDFCR_OFFSET) | BIT(13)); 3651c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara 3661c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara /* 3671c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara * ECC_STATE field reads 0x3 (Error correction complete) immediately 3681c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately 3691c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara * begin trying to poll for the state, you may fall right out of your 3701c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara * loop without any of the correction calculations having taken place. 371eea116ed0497dc9c4a981b8c7017d758fc835dedWolfram Sang * The recommendation from the hardware team is to initially delay as 372eea116ed0497dc9c4a981b8c7017d758fc835dedWolfram Sang * long as ECC_STATE reads less than 4. After that, ECC HW has entered 373eea116ed0497dc9c4a981b8c7017d758fc835dedWolfram Sang * correction state. 3741c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara */ 3752bdb053a8119355eada46dfab88782449a26b39dWolfram Sang timeo = jiffies + usecs_to_jiffies(100); 3761c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara do { 3771c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara ecc_state = (davinci_nand_readl(info, 3781c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara NANDFSR_OFFSET) >> 8) & 0x0f; 3791c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara cpu_relax(); 3801c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara } while ((ecc_state < 4) && time_before(jiffies, timeo)); 3811c3275b656045aff9a75bb2c9f3251af1043ebb3Sudhakar Rajashekhara 3826a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell for (;;) { 3836a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell u32 fsr = davinci_nand_readl(info, NANDFSR_OFFSET); 3846a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 3856a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell switch ((fsr >> 8) & 0x0f) { 3866a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell case 0: /* no error, should not happen */ 387f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET); 3886a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return 0; 3896a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell case 1: /* five or more errors detected */ 390f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET); 3916a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return -EIO; 3926a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell case 2: /* error addresses computed */ 3936a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell case 3: 3946a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell num_errors = 1 + ((fsr >> 16) & 0x03); 3956a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto correct; 3966a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell default: /* still working on it */ 3976a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell cpu_relax(); 3986a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell continue; 3996a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 4006a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 4016a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4026a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellcorrect: 4036a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* correct each error */ 4046a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell for (i = 0, corrected = 0; i < num_errors; i++) { 4056a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell int error_address, error_value; 4066a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4076a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (i > 1) { 4086a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_address = davinci_nand_readl(info, 4096a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell NAND_ERR_ADD2_OFFSET); 4106a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_value = davinci_nand_readl(info, 4116a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell NAND_ERR_ERRVAL2_OFFSET); 4126a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } else { 4136a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_address = davinci_nand_readl(info, 4146a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell NAND_ERR_ADD1_OFFSET); 4156a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_value = davinci_nand_readl(info, 4166a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell NAND_ERR_ERRVAL1_OFFSET); 4176a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 4186a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4196a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (i & 1) { 4206a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_address >>= 16; 4216a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_value >>= 16; 4226a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 4236a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_address &= 0x3ff; 4246a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell error_address = (512 + 7) - error_address; 4256a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4266a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (error_address < 512) { 4276a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell data[error_address] ^= error_value; 4286a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell corrected++; 4296a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 4306a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 4316a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4326a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell return corrected; 4336a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell} 4346a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4356a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell/*----------------------------------------------------------------------*/ 4366a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 4376a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell/* 438ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * NOTE: NAND boot requires ALE == EM_A[1], CLE == EM_A[2], so that's 439ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * how these chips are normally wired. This translates to both 8 and 16 440ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * bit busses using ALE == BIT(3) in byte addresses, and CLE == BIT(4). 441ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 442ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * For now we assume that configuration, or any other one which ignores 443ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * the two LSBs for NAND access ... so we can issue 32-bit reads/writes 444ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * and have that transparently morphed into multiple NAND operations. 445ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 446ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) 447ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 448ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct nand_chip *chip = mtd->priv; 449ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 450ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0) 451ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ioread32_rep(chip->IO_ADDR_R, buf, len >> 2); 452ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0) 453ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ioread16_rep(chip->IO_ADDR_R, buf, len >> 1); 454ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell else 455ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ioread8_rep(chip->IO_ADDR_R, buf, len); 456ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 457ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 458ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic void nand_davinci_write_buf(struct mtd_info *mtd, 459ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell const uint8_t *buf, int len) 460ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 461ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct nand_chip *chip = mtd->priv; 462ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 463ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0) 464ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2); 465ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0) 466ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1); 467ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell else 468ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iowrite8_rep(chip->IO_ADDR_R, buf, len); 469ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 470ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 471ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/* 472ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * Check hardware register for wait status. Returns 1 if device is ready, 473ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell * 0 if it is still busy. 474ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 475ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic int nand_davinci_dev_ready(struct mtd_info *mtd) 476ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 477ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_info *info = to_davinci_nand(mtd); 478ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 479ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0); 480ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 481ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 482ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell/*----------------------------------------------------------------------*/ 483ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 4846a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell/* An ECC layout for using 4-bit ECC with small-page flash, storing 4856a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * ten ECC bytes plus the manufacturer's bad block marker byte, and 4866a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * and not overlapping the default BBT markers. 4876a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 4886a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellstatic struct nand_ecclayout hwecc4_small __initconst = { 4896a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell .eccbytes = 10, 4906a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell .eccpos = { 0, 1, 2, 3, 4, 4916a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* offset 5 holds the badblock marker */ 4926a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 6, 7, 4936a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 13, 14, 15, }, 4946a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell .oobfree = { 4956a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell {.offset = 8, .length = 5, }, 4966a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell {.offset = 16, }, 4976a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell }, 4986a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell}; 4996a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 500f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje/* An ECC layout for using 4-bit ECC with large-page (2048bytes) flash, 501f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * storing ten ECC bytes plus the manufacturer's bad block marker byte, 502f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * and not overlapping the default BBT markers. 503f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje */ 504f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakajestatic struct nand_ecclayout hwecc4_2048 __initconst = { 505f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje .eccbytes = 40, 506f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje .eccpos = { 507f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* at the end of spare sector */ 508f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 509f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 510f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 511f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 512f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje }, 513f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje .oobfree = { 514f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* 2 bytes at offset 0 hold manufacturer badblock markers */ 515f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje {.offset = 2, .length = 22, }, 516f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* 5 bytes at offset 8 hold BBT markers */ 517f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* 8 bytes at offset 16 hold JFFS2 clean markers */ 518f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje }, 519f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje}; 5206a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 521ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic int __init nand_davinci_probe(struct platform_device *pdev) 522ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 523ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_pdata *pdata = pdev->dev.platform_data; 524ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_info *info; 525ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct resource *res1; 526ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct resource *res2; 527ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell void __iomem *vaddr; 528ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell void __iomem *base; 529ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell int ret; 530ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell uint32_t val; 531ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell nand_ecc_modes_t ecc_mode; 532ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 533533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell /* insist on board-specific configuration */ 534533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell if (!pdata) 535533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell return -ENODEV; 536533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell 537ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* which external chipselect will we be managing? */ 538ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (pdev->id < 0 || pdev->id > 3) 539ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return -ENODEV; 540ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 541ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info = kzalloc(sizeof(*info), GFP_KERNEL); 542ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (!info) { 543ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_err(&pdev->dev, "unable to allocate memory\n"); 544ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = -ENOMEM; 545ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_nomem; 546ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 547ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 548ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell platform_set_drvdata(pdev, info); 549ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 550ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); 551ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); 552ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (!res1 || !res2) { 553ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_err(&pdev->dev, "resource missing\n"); 554ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = -EINVAL; 555ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_nomem; 556ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 557ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 558d8bc55553c416c877267c1efd65b099164acbe3fH Hartley Sweeten vaddr = ioremap(res1->start, resource_size(res1)); 559d8bc55553c416c877267c1efd65b099164acbe3fH Hartley Sweeten base = ioremap(res2->start, resource_size(res2)); 560ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (!vaddr || !base) { 561ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_err(&pdev->dev, "ioremap failed\n"); 562ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = -EINVAL; 563ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_ioremap; 564ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 565ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 566ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->dev = &pdev->dev; 567ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->base = base; 568ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->vaddr = vaddr; 569ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 570ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->mtd.priv = &info->chip; 571ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->mtd.name = dev_name(&pdev->dev); 572ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->mtd.owner = THIS_MODULE; 573ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 57487f39f0493edf7051b1b87c6e9eb7f9a74be8e85David Brownell info->mtd.dev.parent = &pdev->dev; 57587f39f0493edf7051b1b87c6e9eb7f9a74be8e85David Brownell 576ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.IO_ADDR_R = vaddr; 577ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.IO_ADDR_W = vaddr; 578ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.chip_delay = 0; 579ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.select_chip = nand_davinci_select_chip; 580ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 581bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris /* options such as NAND_BBT_USE_FLASH */ 582a40f73419f02e40555f692785ea1c1813d5b4c12Brian Norris info->chip.bbt_options = pdata->bbt_options; 583a40f73419f02e40555f692785ea1c1813d5b4c12Brian Norris /* options such as 16-bit widths */ 584533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell info->chip.options = pdata->options; 585f611a79fe9859a30f2a7ae94b4d24f8e2dd75c91Mark A. Greer info->chip.bbt_td = pdata->bbt_td; 586f611a79fe9859a30f2a7ae94b4d24f8e2dd75c91Mark A. Greer info->chip.bbt_md = pdata->bbt_md; 587a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori info->timing = pdata->timing; 588ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 589ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->ioaddr = (uint32_t __force) vaddr; 590ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 591ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->current_cs = info->ioaddr; 592ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->core_chipsel = pdev->id; 593ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->mask_chipsel = pdata->mask_chipsel; 594ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 595ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* use nandboot-capable ALE/CLE masks by default */ 5965cd0be8ec946ee3901e7f651a795225c6badff8fHemant Pedanekar info->mask_ale = pdata->mask_ale ? : MASK_ALE; 597533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell info->mask_cle = pdata->mask_cle ? : MASK_CLE; 598ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 599ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Set address of hardware control function */ 600ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.cmd_ctrl = nand_davinci_hwcontrol; 601ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.dev_ready = nand_davinci_dev_ready; 602ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 603ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Speed up buffer I/O */ 604ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.read_buf = nand_davinci_read_buf; 605ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.write_buf = nand_davinci_write_buf; 606ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 607533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell /* Use board-specific ECC config */ 608533a0149148ccaa0199a1ee6492cd860e3c8b456David Brownell ecc_mode = pdata->ecc_mode; 609ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 6106a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ret = -EINVAL; 611ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell switch (ecc_mode) { 612ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell case NAND_ECC_NONE: 613ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell case NAND_ECC_SOFT: 6146a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell pdata->ecc_bits = 0; 615ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell break; 616ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell case NAND_ECC_HW: 6176a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (pdata->ecc_bits == 4) { 6186a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* No sanity checks: CPUs must support this, 6196a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * and the chips may not use NAND_BUSWIDTH_16. 6206a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 6216a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 6226a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* No sharing 4-bit hardware between chipselects yet */ 6236a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_lock_irq(&davinci_nand_lock); 6246a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (ecc4_busy) 6256a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ret = -EBUSY; 6266a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell else 6276a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc4_busy = true; 6286a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_unlock_irq(&davinci_nand_lock); 6296a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 6306a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (ret == -EBUSY) 6316a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto err_ecc; 6326a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 6336a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.calculate = nand_davinci_calculate_4bit; 6346a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.correct = nand_davinci_correct_4bit; 6356a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.hwctl = nand_davinci_hwctl_4bit; 6366a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.bytes = 10; 6376a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } else { 6386a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.calculate = nand_davinci_calculate_1bit; 6396a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.correct = nand_davinci_correct_1bit; 6406a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.hwctl = nand_davinci_hwctl_1bit; 6416a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.bytes = 3; 6426a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 643ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.ecc.size = 512; 6446a918bade9dab40aaef80559bd1169c69e8d69cbMike Dunn info->chip.ecc.strength = pdata->ecc_bits; 645ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell break; 646ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell default: 647ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = -EINVAL; 648ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_ecc; 649ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 650ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell info->chip.ecc.mode = ecc_mode; 651ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 652cd24f8c1e7e27a2c6051a9a338d4704a2431dbf0Kevin Hilman info->clk = clk_get(&pdev->dev, "aemif"); 653ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (IS_ERR(info->clk)) { 654ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = PTR_ERR(info->clk); 655cd24f8c1e7e27a2c6051a9a338d4704a2431dbf0Kevin Hilman dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret); 656ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_clk; 657ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 658ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 659ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell ret = clk_enable(info->clk); 660ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (ret < 0) { 661cd24f8c1e7e27a2c6051a9a338d4704a2431dbf0Kevin Hilman dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n", 662cd24f8c1e7e27a2c6051a9a338d4704a2431dbf0Kevin Hilman ret); 663ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_clk_enable; 664ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 665ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 666a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori /* 667a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori * Setup Async configuration register in case we did not boot from 668a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori * NAND and so bootloader did not bother to set it up. 669ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell */ 670a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori val = davinci_nand_readl(info, A1CR_OFFSET + info->core_chipsel * 4); 671a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori 672a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori /* Extended Wait is not valid and Select Strobe mode is not used */ 673a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori val &= ~(ACR_ASIZE_MASK | ACR_EW_MASK | ACR_SS_MASK); 674a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori if (info->chip.options & NAND_BUSWIDTH_16) 675a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori val |= 0x1; 676a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori 677a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori davinci_nand_writel(info, A1CR_OFFSET + info->core_chipsel * 4, val); 678a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori 67947882d78250a8b92a9837d14bab32915622a9f12Heiko Schocher ret = 0; 68047882d78250a8b92a9837d14bab32915622a9f12Heiko Schocher if (info->timing) 68147882d78250a8b92a9837d14bab32915622a9f12Heiko Schocher ret = davinci_aemif_setup_timing(info->timing, info->base, 682a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori info->core_chipsel); 683a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori if (ret < 0) { 684a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori dev_dbg(&pdev->dev, "NAND timing values setup fail\n"); 685a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori goto err_timing; 686a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Nori } 687ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 688ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell spin_lock_irq(&davinci_nand_lock); 689ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 690ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* put CSxNAND into NAND mode */ 691ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell val = davinci_nand_readl(info, NANDFCR_OFFSET); 692ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell val |= BIT(info->core_chipsel); 693ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell davinci_nand_writel(info, NANDFCR_OFFSET, val); 694ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 695ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell spin_unlock_irq(&davinci_nand_lock); 696ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 697ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell /* Scan to find existence of the device(s) */ 6985e81e88a4c140586d9212999cea683bcd66a15c6David Woodhouse ret = nand_scan_ident(&info->mtd, pdata->mask_chipsel ? 2 : 1, NULL); 699ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (ret < 0) { 700ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_dbg(&pdev->dev, "no NAND chip(s) found\n"); 701ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_scan; 702ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell } 703ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 7046a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* Update ECC layout if needed ... for 1-bit HW ECC, the default 7056a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * is OK, but it allocates 6 bytes when only 3 are needed (for 7066a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * each 512 bytes). For the 4-bit HW ECC, that default is not 7076a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * usable: 10 bytes are needed, not 6. 7086a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 7096a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (pdata->ecc_bits == 4) { 7106a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell int chunks = info->mtd.writesize / 512; 7116a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 7126a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (!chunks || info->mtd.oobsize < 16) { 7136a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell dev_dbg(&pdev->dev, "too small\n"); 7146a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ret = -EINVAL; 7156a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto err_scan; 7166a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 7176a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 7186a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell /* For small page chips, preserve the manufacturer's 7196a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * badblock marking data ... and make sure a flash BBT 7206a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell * table marker fits in the free bytes. 7216a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 7226a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (chunks == 1) { 7236a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->ecclayout = hwecc4_small; 7246a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->ecclayout.oobfree[1].length = 7256a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->mtd.oobsize - 16; 7266a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto syndrome_done; 7276a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 728f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje if (chunks == 4) { 729f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje info->ecclayout = hwecc4_2048; 730f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST; 731f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje goto syndrome_done; 732f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje } 7336a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 734f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje /* 4KiB page chips are not yet supported. The eccpos from 735f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * nand_ecclayout cannot hold 80 bytes and change to eccpos[] 736f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * breaks userspace ioctl interface with mtd-utils. Once we 737f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used 738f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje * for the 4KiB page chips. 739cc26c3cd3d1cf40a07f2b19ac4c53d517bee52a5Brian Norris * 740cc26c3cd3d1cf40a07f2b19ac4c53d517bee52a5Brian Norris * TODO: Note that nand_ecclayout has now been expanded and can 741cc26c3cd3d1cf40a07f2b19ac4c53d517bee52a5Brian Norris * hold plenty of OOB entries. 7426a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell */ 7436a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell dev_warn(&pdev->dev, "no 4-bit ECC support yet " 744f12a9473283e68ae708e9ada37cb352ea2652397Sneha Narnakaje "for 4KiB-page NAND\n"); 7456a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ret = -EIO; 7466a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto err_scan; 7476a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 7486a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownellsyndrome_done: 7496a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell info->chip.ecc.layout = &info->ecclayout; 7506a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell } 7516a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 7526a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ret = nand_scan_tail(&info->mtd); 7536a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (ret < 0) 7546a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell goto err_scan; 7556a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 75642d7fbe223ab878b23de9e3b0166f8cd665a2aa5Artem Bityutskiy ret = mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts, 75742d7fbe223ab878b23de9e3b0166f8cd665a2aa5Artem Bityutskiy pdata->nr_parts); 758ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 759ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (ret < 0) 760ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell goto err_scan; 761ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 762ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell val = davinci_nand_readl(info, NRCSR_OFFSET); 763ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell dev_info(&pdev->dev, "controller rev. %d.%d\n", 764ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell (val >> 8) & 0xff, val & 0xff); 765ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 766ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return 0; 767ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 768ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_scan: 769a88dbc5bfdd26132bbf0ad19dd672e036971d74dSekhar Norierr_timing: 770ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell clk_disable(info->clk); 771ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 772ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_clk_enable: 773ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell clk_put(info->clk); 774ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 7756a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_lock_irq(&davinci_nand_lock); 7766a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (ecc_mode == NAND_ECC_HW_SYNDROME) 7776a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc4_busy = false; 7786a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_unlock_irq(&davinci_nand_lock); 7796a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 780ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_ecc: 781ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_clk: 782ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_ioremap: 783ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (base) 784ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iounmap(base); 785ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell if (vaddr) 786ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iounmap(vaddr); 787ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 788ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellerr_nomem: 789ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell kfree(info); 790ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return ret; 791ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 792ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 793ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic int __exit nand_davinci_remove(struct platform_device *pdev) 794ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 795ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell struct davinci_nand_info *info = platform_get_drvdata(pdev); 796ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 7976a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_lock_irq(&davinci_nand_lock); 7986a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME) 7996a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell ecc4_busy = false; 8006a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell spin_unlock_irq(&davinci_nand_lock); 8016a4123e581b3112ff4ea7439ab9ae5cb271a9dbdDavid Brownell 802ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iounmap(info->base); 803ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell iounmap(info->vaddr); 804ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 805ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell nand_release(&info->mtd); 806ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 807ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell clk_disable(info->clk); 808ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell clk_put(info->clk); 809ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 810ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell kfree(info); 811ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 812ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return 0; 813ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 814ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 815ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic struct platform_driver nand_davinci_driver = { 816ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell .remove = __exit_p(nand_davinci_remove), 817ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell .driver = { 818ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell .name = "davinci_nand", 819ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell }, 820ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell}; 821ff4569c752c577c7e71e03c9d59e6ef85ca763c0David BrownellMODULE_ALIAS("platform:davinci_nand"); 822ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 823ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic int __init nand_davinci_init(void) 824ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 825ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell return platform_driver_probe(&nand_davinci_driver, nand_davinci_probe); 826ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 827ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellmodule_init(nand_davinci_init); 828ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 829ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellstatic void __exit nand_davinci_exit(void) 830ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell{ 831ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell platform_driver_unregister(&nand_davinci_driver); 832ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell} 833ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownellmodule_exit(nand_davinci_exit); 834ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 835ff4569c752c577c7e71e03c9d59e6ef85ca763c0David BrownellMODULE_LICENSE("GPL"); 836ff4569c752c577c7e71e03c9d59e6ef85ca763c0David BrownellMODULE_AUTHOR("Texas Instruments"); 837ff4569c752c577c7e71e03c9d59e6ef85ca763c0David BrownellMODULE_DESCRIPTION("Davinci NAND flash driver"); 838ff4569c752c577c7e71e03c9d59e6ef85ca763c0David Brownell 839