1b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* linux/drivers/mtd/nand/bf5xx_nand.c 2b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 3afc4bca63941746f1d49394620d294074150e664Michael Hennerich * Copyright 2006-2008 Analog Devices Inc. 4b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * http://blackfin.uclinux.org/ 5b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Bryan Wu <bryan.wu@analog.com> 6b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 78e87d7820a6362b6304924befb22d1ee79b754f3Joe Perches * Blackfin BF5xx on-chip NAND flash controller driver 8b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 9b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Derived from drivers/mtd/nand/s3c2410.c 10b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk> 11b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 12b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Derived from drivers/mtd/nand/cafe.c 13b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Copyright © 2006 Red Hat, Inc. 14b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> 15b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 16b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Changelog: 17b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 12-Jun-2007 Bryan Wu: Initial version 18b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 18-Jul-2007 Bryan Wu: 19b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * - ECC_HW and ECC_SW supported 20b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * - DMA supported in ECC_HW 21b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * - YAFFS tested as rootfs in both ECC_HW and ECC_SW 22b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 23b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * This program is free software; you can redistribute it and/or modify 24b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * it under the terms of the GNU General Public License as published by 25b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * the Free Software Foundation; either version 2 of the License, or 26b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * (at your option) any later version. 27b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 28b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * This program is distributed in the hope that it will be useful, 29b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * but WITHOUT ANY WARRANTY; without even the implied warranty of 30b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * GNU General Public License for more details. 32b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 33b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * You should have received a copy of the GNU General Public License 34b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * along with this program; if not, write to the Free Software 35b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 36b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu*/ 37b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 38b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/module.h> 39b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/types.h> 40b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/init.h> 41b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/kernel.h> 42b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/string.h> 43b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/ioport.h> 44b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/platform_device.h> 45b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/delay.h> 46b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/dma-mapping.h> 47b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/err.h> 48b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/slab.h> 49b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/io.h> 50b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/bitops.h> 51b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 52b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/mtd/mtd.h> 53b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/mtd/nand.h> 54b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/mtd/nand_ecc.h> 55b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <linux/mtd/partitions.h> 56b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 57b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <asm/blackfin.h> 58b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <asm/dma.h> 59b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <asm/cacheflush.h> 60b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <asm/nand.h> 61b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#include <asm/portmux.h> 62b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 63b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define DRV_NAME "bf5xx-nand" 64b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define DRV_VERSION "1.2" 65b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define DRV_AUTHOR "Bryan Wu <bryan.wu@analog.com>" 66b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define DRV_DESC "BF5xx on-chip NAND FLash Controller Driver" 67b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 68ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger/* NFC_STAT Masks */ 69ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define NBUSY 0x01 /* Not Busy */ 70ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define WB_FULL 0x02 /* Write Buffer Full */ 71ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define PG_WR_STAT 0x04 /* Page Write Pending */ 72ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define PG_RD_STAT 0x08 /* Page Read Pending */ 73ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define WB_EMPTY 0x10 /* Write Buffer Empty */ 74ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger 75ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger/* NFC_IRQSTAT Masks */ 76ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define NBUSYIRQ 0x01 /* Not Busy IRQ */ 77ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define WB_OVF 0x02 /* Write Buffer Overflow */ 78ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define WB_EDGE 0x04 /* Write Buffer Edge Detect */ 79ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define RD_RDY 0x08 /* Read Data Ready */ 80ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define WR_DONE 0x10 /* Page Write Done */ 81ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger 82ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger/* NFC_RST Masks */ 83ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define ECC_RST 0x01 /* ECC (and NFC counters) Reset */ 84ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger 85ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger/* NFC_PGCTL Masks */ 86ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define PG_RD_START 0x01 /* Page Read Start */ 87ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger#define PG_WR_START 0x02 /* Page Write Start */ 88ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger 89b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#ifdef CONFIG_MTD_NAND_BF5XX_HWECC 90b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int hardware_ecc = 1; 91b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#else 92b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int hardware_ecc; 93b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#endif 94b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 95afc4bca63941746f1d49394620d294074150e664Michael Hennerichstatic const unsigned short bfin_nfc_pin_req[] = 96a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich {P_NAND_CE, 97a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_RB, 98a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_D0, 99a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_D1, 100a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_D2, 101a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_D3, 102a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_D4, 103a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_D5, 104a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_D6, 105a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_D7, 106a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_WE, 107a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_RE, 108a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_CLE, 109a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich P_NAND_ALE, 110a25b7fee537ab4dbc6eb301bd455ee8d01b707f6Michael Hennerich 0}; 111b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 112fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC 113fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysingerstatic struct nand_ecclayout bootrom_ecclayout = { 114fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger .eccbytes = 24, 115fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger .eccpos = { 116fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger 0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2, 117fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger 0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2, 118fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger 0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2, 119fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger 0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2, 120fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger 0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2, 121fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger 0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2, 122fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger 0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2, 123fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger 0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2 124fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger }, 125fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger .oobfree = { 126fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger { 0x8 * 0 + 3, 5 }, 127fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger { 0x8 * 1 + 3, 5 }, 128fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger { 0x8 * 2 + 3, 5 }, 129fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger { 0x8 * 3 + 3, 5 }, 130fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger { 0x8 * 4 + 3, 5 }, 131fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger { 0x8 * 5 + 3, 5 }, 132fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger { 0x8 * 6 + 3, 5 }, 133fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger { 0x8 * 7 + 3, 5 }, 134fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger } 135fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger}; 136fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger#endif 137fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger 138b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 139b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Data structures for bf5xx nand flash controller driver 140b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 141b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 142b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* bf5xx nand info */ 143b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustruct bf5xx_nand_info { 144b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* mtd info */ 145b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct nand_hw_control controller; 146b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct mtd_info mtd; 147b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct nand_chip chip; 148b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 149b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* platform info */ 150b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_platform *platform; 151b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 152b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* device info */ 153b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct device *device; 154b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 155b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* DMA stuff */ 156b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct completion dma_completion; 157b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}; 158b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 159b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 160b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Conversion functions 161b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 162b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd) 163b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 164b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return container_of(mtd, struct bf5xx_nand_info, mtd); 165b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 166b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 167b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev) 168b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 169b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return platform_get_drvdata(pdev); 170b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 171b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 172b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev) 173b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 174b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return pdev->dev.platform_data; 175b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 176b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 177b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 178b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * struct nand_chip interface function pointers 179b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 180b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 181b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 182b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * bf5xx_nand_hwcontrol 183b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 184b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Issue command and address cycles to the chip 185b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 186b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd, 187b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu unsigned int ctrl) 188b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 189b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (cmd == NAND_CMD_NONE) 190b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return; 191b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 192b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu while (bfin_read_NFC_STAT() & WB_FULL) 193b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu cpu_relax(); 194b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 195b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (ctrl & NAND_CLE) 196b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bfin_write_NFC_CMD(cmd); 197fd508da2208696db146cd1be2bb2e8b799f6e3a2Barry Song else if (ctrl & NAND_ALE) 198b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bfin_write_NFC_ADDR(cmd); 199b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu SSYNC(); 200b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 201b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 202b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 203b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * bf5xx_nand_devready() 204b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 205b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * returns 0 if the nand is busy, 1 if it is ready 206b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 207b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_devready(struct mtd_info *mtd) 208b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 209d2350c2ab51df7088d3db73a4c85ad73ded37a01Barry Song unsigned short val = bfin_read_NFC_STAT(); 210b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 211d2350c2ab51df7088d3db73a4c85ad73ded37a01Barry Song if ((val & NBUSY) == NBUSY) 212b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 1; 213b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu else 214b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 0; 215b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 216b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 217b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 218b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * ECC functions 219b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * These allow the bf5xx to use the controller's ECC 220b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * generator block to ECC the data as it passes through 221b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 222b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 223b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 224b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * ECC error correction function 225b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 226b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, 227b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu u_char *read_ecc, u_char *calc_ecc) 228b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 229b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); 230b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu u32 syndrome[5]; 231b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu u32 calced, stored; 232b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu int i; 233b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu unsigned short failing_bit, failing_byte; 234b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu u_char data; 235b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 236b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16); 237b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16); 238b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 239b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu syndrome[0] = (calced ^ stored); 240b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 241b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* 242b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * syndrome 0: all zero 243b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * No error in data 244b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * No action 245b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 246b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (!syndrome[0] || !calced || !stored) 247b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 0; 248b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 249b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* 250b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * sysdrome 0: only one bit is one 251b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * ECC data was incorrect 252b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * No action 253b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 254b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (hweight32(syndrome[0]) == 1) { 255b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_err(info->device, "ECC data was incorrect!\n"); 256b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 1; 257b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu } 258b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 259b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF); 260b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF); 261b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF); 262b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu syndrome[4] = syndrome[2] ^ syndrome[3]; 263b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 264b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu for (i = 0; i < 5; i++) 265b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]); 266b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 267b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_info(info->device, 268b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu "calced[0x%08x], stored[0x%08x]\n", 269b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu calced, stored); 270b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 271b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* 272b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * sysdrome 0: exactly 11 bits are one, each parity 273b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * and parity' pair is 1 & 0 or 0 & 1. 274b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 1-bit correctable error 275b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Correct the error 276b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 277b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) { 278b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_info(info->device, 279b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu "1-bit correctable error, correct it.\n"); 280b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_info(info->device, 281b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu "syndrome[1] 0x%08x\n", syndrome[1]); 282b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 283b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu failing_bit = syndrome[1] & 0x7; 284b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu failing_byte = syndrome[1] >> 0x3; 285b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu data = *(dat + failing_byte); 286b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu data = data ^ (0x1 << failing_bit); 287b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu *(dat + failing_byte) = data; 288b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 289b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 0; 290b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu } 291b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 292b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* 293b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * sysdrome 0: random data 294b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * More than 1-bit error, non-correctable error 295b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Discard data, mark bad block 296b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 297b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_err(info->device, 298b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu "More than 1-bit error, non-correctable error.\n"); 299b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_err(info->device, 300b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu "Please discard data, mark bad block\n"); 301b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 302b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 1; 303b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 304b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 305b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, 306b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu u_char *read_ecc, u_char *calc_ecc) 307b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 30844299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song struct nand_chip *chip = mtd->priv; 309b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu int ret; 310b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 311b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); 312b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 31344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song /* If ecc size is 512, correct second 256 bytes */ 31444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song if (chip->ecc.size == 512) { 315b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dat += 256; 31644299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song read_ecc += 3; 31744299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song calc_ecc += 3; 318e274f025e2caaadc1a6dd41adc9c9a19be075110Mike Frysinger ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); 319b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu } 320b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 321b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return ret; 322b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 323b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 324b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode) 325b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 326b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return; 327b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 328b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 329b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, 330b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu const u_char *dat, u_char *ecc_code) 331b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 332b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); 33344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song struct nand_chip *chip = mtd->priv; 334b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu u16 ecc0, ecc1; 335b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu u32 code[2]; 336b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu u8 *p; 337b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 33844299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song /* first 3 bytes ECC code for 256 page size */ 339b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu ecc0 = bfin_read_NFC_ECC0(); 340b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu ecc1 = bfin_read_NFC_ECC1(); 341b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 342cf840392e83914b9fcdbce8a8a2bc17a84cf0353Mike Frysinger code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); 343b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 344b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); 345b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 3465eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu p = (u8 *) code; 3475eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu memcpy(ecc_code, p, 3); 3485eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu 34944299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song /* second 3 bytes ECC code for 512 ecc size */ 35044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song if (chip->ecc.size == 512) { 351b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu ecc0 = bfin_read_NFC_ECC2(); 352b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu ecc1 = bfin_read_NFC_ECC3(); 353cf840392e83914b9fcdbce8a8a2bc17a84cf0353Mike Frysinger code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); 3545eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu 3555eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu /* second 3 bytes in ecc_code for second 256 3565eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu * bytes of 512 page size 3575eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu */ 3585eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu p = (u8 *) (code + 1); 3595eb91034f3d825f43b3c8ace7b69f94752b7dedaBryan Wu memcpy((ecc_code + 3), p, 3); 360b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]); 361b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu } 362b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 363b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 0; 364b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 365b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 366b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 367b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * PIO mode for buffer writing and reading 368b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 369b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) 370b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 371b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu int i; 372b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu unsigned short val; 373b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 374b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* 375b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Data reads are requested by first writing to NFC_DATA_RD 376b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * and then reading back from NFC_READ. 377b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 378b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu for (i = 0; i < len; i++) { 379b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu while (bfin_read_NFC_STAT() & WB_FULL) 380b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu cpu_relax(); 381b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 382b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* Contents do not matter */ 383b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bfin_write_NFC_DATA_RD(0x0000); 384b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu SSYNC(); 385b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 386b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY) 387b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu cpu_relax(); 388b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 389b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu buf[i] = bfin_read_NFC_READ(); 390b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 391b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu val = bfin_read_NFC_IRQSTAT(); 392b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu val |= RD_RDY; 393b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bfin_write_NFC_IRQSTAT(val); 394b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu SSYNC(); 395b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu } 396b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 397b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 398b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd) 399b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 400b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu uint8_t val; 401b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 402b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bf5xx_nand_read_buf(mtd, &val, 1); 403b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 404b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return val; 405b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 406b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 407b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_write_buf(struct mtd_info *mtd, 408b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu const uint8_t *buf, int len) 409b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 410b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu int i; 411b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 412b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu for (i = 0; i < len; i++) { 413b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu while (bfin_read_NFC_STAT() & WB_FULL) 414b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu cpu_relax(); 415b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 416b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bfin_write_NFC_DATA_WR(buf[i]); 417b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu SSYNC(); 418b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu } 419b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 420b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 421b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) 422b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 423b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu int i; 424b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu u16 *p = (u16 *) buf; 425b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu len >>= 1; 426b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 427b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* 428b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Data reads are requested by first writing to NFC_DATA_RD 429b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * and then reading back from NFC_READ. 430b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 431b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bfin_write_NFC_DATA_RD(0x5555); 432b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 433b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu SSYNC(); 434b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 435b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu for (i = 0; i < len; i++) 436b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu p[i] = bfin_read_NFC_READ(); 437b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 438b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 439b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_write_buf16(struct mtd_info *mtd, 440b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu const uint8_t *buf, int len) 441b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 442b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu int i; 443b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu u16 *p = (u16 *) buf; 444b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu len >>= 1; 445b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 446b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu for (i = 0; i < len; i++) 447b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bfin_write_NFC_DATA_WR(p[i]); 448b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 449b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu SSYNC(); 450b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 451b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 452b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 453b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * DMA functions for buffer writing and reading 454b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 455b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id) 456b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 457b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_info *info = dev_id; 458b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 459b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu clear_dma_irqstat(CH_NFC); 460b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu disable_dma(CH_NFC); 461b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu complete(&info->dma_completion); 462b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 463b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return IRQ_HANDLED; 464b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 465b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 466530c3b60658687e2ad7bf98ef83631a8280ae8a6Mike Frysingerstatic void bf5xx_nand_dma_rw(struct mtd_info *mtd, 467b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu uint8_t *buf, int is_read) 468b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 469b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); 47044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song struct nand_chip *chip = mtd->priv; 471b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu unsigned short val; 472b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 473b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n", 474b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu mtd, buf, is_read); 475b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 476b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* 477b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Before starting a dma transfer, be sure to invalidate/flush 478b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * the cache over the address range of your DMA buffer to 479b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * prevent cache coherency problems. Otherwise very subtle bugs 480b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * can be introduced to your driver. 481b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 482b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (is_read) 483b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu invalidate_dcache_range((unsigned int)buf, 48444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song (unsigned int)(buf + chip->ecc.size)); 485b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu else 486b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu flush_dcache_range((unsigned int)buf, 48744299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song (unsigned int)(buf + chip->ecc.size)); 488b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 489b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* 490b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * This register must be written before each page is 491b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * transferred to generate the correct ECC register 492b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * values. 493b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 494ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger bfin_write_NFC_RST(ECC_RST); 495b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu SSYNC(); 496752b957a37ee1cc09fccb39a8bc5843edf32119bBarry Song while (bfin_read_NFC_RST() & ECC_RST) 497752b957a37ee1cc09fccb39a8bc5843edf32119bBarry Song cpu_relax(); 498b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 499b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu disable_dma(CH_NFC); 500b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu clear_dma_irqstat(CH_NFC); 501b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 502b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* setup DMA register with Blackfin DMA API */ 503b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu set_dma_config(CH_NFC, 0x0); 504b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu set_dma_start_addr(CH_NFC, (unsigned long) buf); 505c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai 506ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger /* The DMAs have different size on BF52x and BF54x */ 507c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai#ifdef CONFIG_BF52x 50844299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song set_dma_x_count(CH_NFC, (chip->ecc.size >> 1)); 509c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai set_dma_x_modify(CH_NFC, 2); 510c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai val = DI_EN | WDSIZE_16; 511c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai#endif 512c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai 513c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai#ifdef CONFIG_BF54x 51444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song set_dma_x_count(CH_NFC, (chip->ecc.size >> 2)); 515b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu set_dma_x_modify(CH_NFC, 4); 516b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu val = DI_EN | WDSIZE_32; 517c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai#endif 518c3a9f35673290f49ec115d36ad283961c82c135aCliff Cai /* setup write or read operation */ 519b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (is_read) 520b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu val |= WNR; 521b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu set_dma_config(CH_NFC, val); 522b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu enable_dma(CH_NFC); 523b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 524b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* Start PAGE read/write operation */ 525b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (is_read) 526ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger bfin_write_NFC_PGCTL(PG_RD_START); 527b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu else 528ac39ee304ac33f15107e42adb5ee5b0d0ce2dc4aMike Frysinger bfin_write_NFC_PGCTL(PG_WR_START); 529b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu wait_for_completion(&info->dma_completion); 530b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 531b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 532b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_dma_read_buf(struct mtd_info *mtd, 533b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu uint8_t *buf, int len) 534b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 535b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); 53644299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song struct nand_chip *chip = mtd->priv; 537b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 538b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len); 539b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 54044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song if (len == chip->ecc.size) 541b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bf5xx_nand_dma_rw(mtd, buf, 1); 542b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu else 543b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bf5xx_nand_read_buf(mtd, buf, len); 544b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 545b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 546b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, 547b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu const uint8_t *buf, int len) 548b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 549b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); 55044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song struct nand_chip *chip = mtd->priv; 551b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 552b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len); 553b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 55444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song if (len == chip->ecc.size) 555b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0); 556b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu else 557b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bf5xx_nand_write_buf(mtd, buf, len); 558b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 559b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 560085d45fb5216c25b69103e5d861fabdc4389e221Barry Songstatic int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, 561085d45fb5216c25b69103e5d861fabdc4389e221Barry Song uint8_t *buf, int page) 562085d45fb5216c25b69103e5d861fabdc4389e221Barry Song{ 563085d45fb5216c25b69103e5d861fabdc4389e221Barry Song bf5xx_nand_read_buf(mtd, buf, mtd->writesize); 564085d45fb5216c25b69103e5d861fabdc4389e221Barry Song bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize); 565085d45fb5216c25b69103e5d861fabdc4389e221Barry Song 566085d45fb5216c25b69103e5d861fabdc4389e221Barry Song return 0; 567085d45fb5216c25b69103e5d861fabdc4389e221Barry Song} 568085d45fb5216c25b69103e5d861fabdc4389e221Barry Song 569085d45fb5216c25b69103e5d861fabdc4389e221Barry Songstatic void bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, 570085d45fb5216c25b69103e5d861fabdc4389e221Barry Song const uint8_t *buf) 571085d45fb5216c25b69103e5d861fabdc4389e221Barry Song{ 572085d45fb5216c25b69103e5d861fabdc4389e221Barry Song bf5xx_nand_write_buf(mtd, buf, mtd->writesize); 573085d45fb5216c25b69103e5d861fabdc4389e221Barry Song bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); 574085d45fb5216c25b69103e5d861fabdc4389e221Barry Song} 575085d45fb5216c25b69103e5d861fabdc4389e221Barry Song 576b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 577b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * System initialization functions 578b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 579b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) 580b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 581b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu int ret; 582b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 583b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* Do not use dma */ 584b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (!hardware_ecc) 585b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 0; 586b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 587b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu init_completion(&info->dma_completion); 588b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 589b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* Request NFC DMA channel */ 590b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu ret = request_dma(CH_NFC, "BF5XX NFC driver"); 591b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (ret < 0) { 592b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_err(info->device, " unable to get DMA channel\n"); 593b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return ret; 594b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu } 595b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 59608d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger#ifdef CONFIG_BF54x 59708d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger /* Setup DMAC1 channel mux for NFC which shared with SDH */ 59808d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() & ~1); 59908d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger SSYNC(); 60008d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger#endif 60108d2503ecc2337275942c1f52822b7a464c0c0a3Mike Frysinger 602bfc492571e7ad1eb4b9fe3ac8ab0a7cdaecf8ecaMike Frysinger set_dma_callback(CH_NFC, bf5xx_nand_dma_irq, info); 603b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 604b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* Turn off the DMA channel first */ 605b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu disable_dma(CH_NFC); 606b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 0; 607b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 608b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 6094f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wustatic void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info) 6104f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu{ 6114f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu /* Free NFC DMA channel */ 6124f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu if (hardware_ecc) 6134f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu free_dma(CH_NFC); 6144f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu} 6154f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu 616b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 617b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * BF5XX NFC hardware initialization 618b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * - pin mux setup 619b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * - clear interrupt status 620b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 621b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_hw_init(struct bf5xx_nand_info *info) 622b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 623b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu int err = 0; 624b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu unsigned short val; 625b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_platform *plat = info->platform; 626b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 627b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* setup NFC_CTL register */ 628b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_info(info->device, 62944299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song "data_width=%d, wr_dly=%d, rd_dly=%d\n", 630b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu (plat->data_width ? 16 : 8), 631b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu plat->wr_dly, plat->rd_dly); 632b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 63344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song val = (1 << NFC_PG_SIZE_OFFSET) | 634b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu (plat->data_width << NFC_NWIDTH_OFFSET) | 635b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu (plat->rd_dly << NFC_RDDLY_OFFSET) | 63600355b0baadf949f02ab7d3e2bd222e3fbcc72eeBarry Song (plat->wr_dly << NFC_WRDLY_OFFSET); 637b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val); 638b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 639b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bfin_write_NFC_CTL(val); 640b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu SSYNC(); 641b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 642b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* clear interrupt status */ 643b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bfin_write_NFC_IRQMASK(0x0); 644b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu SSYNC(); 645b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu val = bfin_read_NFC_IRQSTAT(); 646b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bfin_write_NFC_IRQSTAT(val); 647b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu SSYNC(); 648b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 649b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* DMA initialization */ 650b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (bf5xx_nand_dma_init(info)) 651b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu err = -ENXIO; 652b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 653b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return err; 654b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 655b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 656b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 657b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * Device management interface 658b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 6598d30cab06920f9efb7e089f2c69e451b2a637d8aMike Frysingerstatic int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info) 660b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 661b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct mtd_info *mtd = &info->mtd; 662b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct mtd_partition *parts = info->platform->partitions; 663b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu int nr = info->platform->nr_partitions; 664b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 66588146872f0fbd89e425e3e0db71d42df8db9d932Jamie Iles return mtd_device_register(mtd, parts, nr); 666b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 667b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 6682445af3853928bf3ee7960e09f548a1b07924091Mike Frysingerstatic int __devexit bf5xx_nand_remove(struct platform_device *pdev) 669b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 670b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_info *info = to_nand_info(pdev); 671b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 672b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu platform_set_drvdata(pdev, NULL); 673b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 674b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* first thing we need to do is release all our mtds 675b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * and their partitions, then go through freeing the 676b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * resources used 677b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 6788b865d5efd9205b131dd9a43a6f450c05d38aaa1Mike Frysinger nand_release(&info->mtd); 679b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 680b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu peripheral_free_list(bfin_nfc_pin_req); 6814f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu bf5xx_nand_dma_remove(info); 682b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 683b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* free the common resources */ 684b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu kfree(info); 685b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 686b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 0; 687b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 688b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 68944299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Songstatic int bf5xx_nand_scan(struct mtd_info *mtd) 69044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song{ 69144299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song struct nand_chip *chip = mtd->priv; 69244299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song int ret; 69344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song 694eac15a429a27cb74115daaf4c1127c5e854d50e4Mike Frysinger ret = nand_scan_ident(mtd, 1, NULL); 69544299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song if (ret) 69644299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song return ret; 69744299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song 69844299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song if (hardware_ecc) { 69944299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song /* 70044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song * for nand with page size > 512B, think it as several sections with 512B 70144299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song */ 70244299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song if (likely(mtd->writesize >= 512)) { 70344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song chip->ecc.size = 512; 70444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song chip->ecc.bytes = 6; 7056a918bade9dab40aaef80559bd1169c69e8d69cbMike Dunn chip->ecc.strength = 2; 70644299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song } else { 70744299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song chip->ecc.size = 256; 70844299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song chip->ecc.bytes = 3; 7096a918bade9dab40aaef80559bd1169c69e8d69cbMike Dunn chip->ecc.strength = 1; 71044299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET)); 71144299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song SSYNC(); 71244299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song } 71344299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song } 71444299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song 71544299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song return nand_scan_tail(mtd); 71644299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song} 71744299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song 718b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* 719b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * bf5xx_nand_probe 720b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * 721b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * called by device layer when it finds a device matching 722b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * one our driver can handled. This code checks to see if 723b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * it can allocate all necessary resources then calls the 724b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu * nand layer to look for devices 725b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu */ 7262445af3853928bf3ee7960e09f548a1b07924091Mike Frysingerstatic int __devinit bf5xx_nand_probe(struct platform_device *pdev) 727b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 728b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_platform *plat = to_nand_plat(pdev); 729b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_info *info = NULL; 730b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct nand_chip *chip = NULL; 731b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct mtd_info *mtd = NULL; 732b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu int err = 0; 733b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 734b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_dbg(&pdev->dev, "(%p)\n", pdev); 735b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 7364f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu if (!plat) { 7374f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu dev_err(&pdev->dev, "no platform specific information\n"); 7384f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu return -EINVAL; 7394f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu } 7404f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu 741afc4bca63941746f1d49394620d294074150e664Michael Hennerich if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { 7420ee002b041cb45ab3cc5384b86271d41ccf90fe1Mike Frysinger dev_err(&pdev->dev, "requesting Peripherals failed\n"); 743afc4bca63941746f1d49394620d294074150e664Michael Hennerich return -EFAULT; 744afc4bca63941746f1d49394620d294074150e664Michael Hennerich } 745afc4bca63941746f1d49394620d294074150e664Michael Hennerich 746b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu info = kzalloc(sizeof(*info), GFP_KERNEL); 747b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (info == NULL) { 748b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_err(&pdev->dev, "no memory for flash info\n"); 749b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu err = -ENOMEM; 7504f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu goto out_err_kzalloc; 751b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu } 752b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 753b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu platform_set_drvdata(pdev, info); 754b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 755b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu spin_lock_init(&info->controller.lock); 756b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu init_waitqueue_head(&info->controller.wq); 757b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 758b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu info->device = &pdev->dev; 759b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu info->platform = plat; 760b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 761b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* initialise chip data struct */ 762b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip = &info->chip; 763b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 764b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (plat->data_width) 765b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->options |= NAND_BUSWIDTH_16; 766b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 767b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN; 768b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 769b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->read_buf = (plat->data_width) ? 770b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bf5xx_nand_read_buf16 : bf5xx_nand_read_buf; 771b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->write_buf = (plat->data_width) ? 772b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bf5xx_nand_write_buf16 : bf5xx_nand_write_buf; 773b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 774b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->read_byte = bf5xx_nand_read_byte; 775b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 776b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->cmd_ctrl = bf5xx_nand_hwcontrol; 777b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->dev_ready = bf5xx_nand_devready; 778b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 779b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->priv = &info->mtd; 780b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->controller = &info->controller; 781b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 782b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->IO_ADDR_R = (void __iomem *) NFC_READ; 783b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->IO_ADDR_W = (void __iomem *) NFC_DATA_WR; 784b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 785b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->chip_delay = 0; 786b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 787b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* initialise mtd info data struct */ 788b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu mtd = &info->mtd; 789b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu mtd->priv = chip; 790b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu mtd->owner = THIS_MODULE; 791b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 792b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* initialise the hardware */ 793b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu err = bf5xx_nand_hw_init(info); 7944f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu if (err) 7954f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu goto out_err_hw_init; 796b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 797b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* setup hardware ECC data struct */ 798b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu if (hardware_ecc) { 799fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC 800fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger chip->ecc.layout = &bootrom_ecclayout; 801fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14Mike Frysinger#endif 802b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->read_buf = bf5xx_nand_dma_read_buf; 803b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->write_buf = bf5xx_nand_dma_write_buf; 804b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->ecc.calculate = bf5xx_nand_calculate_ecc; 805b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->ecc.correct = bf5xx_nand_correct_data; 806b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->ecc.mode = NAND_ECC_HW; 807b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->ecc.hwctl = bf5xx_nand_enable_hwecc; 808085d45fb5216c25b69103e5d861fabdc4389e221Barry Song chip->ecc.read_page_raw = bf5xx_nand_read_page_raw; 809085d45fb5216c25b69103e5d861fabdc4389e221Barry Song chip->ecc.write_page_raw = bf5xx_nand_write_page_raw; 810b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu } else { 811b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu chip->ecc.mode = NAND_ECC_SOFT; 812b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu } 813b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 814b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* scan hardware nand chip and setup mtd info data struct */ 81544299179c0e87cc6d8b753c1ca8c97b1cf9340e1Barry Song if (bf5xx_nand_scan(mtd)) { 816b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu err = -ENXIO; 8174f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu goto out_err_nand_scan; 818b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu } 819b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 8205954c47c2194abcdeeae5f752e64b7c75770dbd3Mike Frysinger#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC 8215954c47c2194abcdeeae5f752e64b7c75770dbd3Mike Frysinger chip->badblockpos = 63; 8225954c47c2194abcdeeae5f752e64b7c75770dbd3Mike Frysinger#endif 8235954c47c2194abcdeeae5f752e64b7c75770dbd3Mike Frysinger 824b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu /* add NAND partition */ 825b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu bf5xx_nand_add_partition(info); 826b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 827b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu dev_dbg(&pdev->dev, "initialised ok\n"); 828b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 0; 829b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 8304f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wuout_err_nand_scan: 8314f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu bf5xx_nand_dma_remove(info); 8324f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wuout_err_hw_init: 8334f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu platform_set_drvdata(pdev, NULL); 8344f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu kfree(info); 8354f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wuout_err_kzalloc: 8364f0ca70e52b67f41287d853f0d572dafa875e485Bryan Wu peripheral_free_list(bfin_nfc_pin_req); 837b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 838b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return err; 839b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 840b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 841b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* PM Support */ 842b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#ifdef CONFIG_PM 843b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 844b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_suspend(struct platform_device *dev, pm_message_t pm) 845b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 846b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_info *info = platform_get_drvdata(dev); 847b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 848b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 0; 849b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 850b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 851b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int bf5xx_nand_resume(struct platform_device *dev) 852b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 853b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu struct bf5xx_nand_info *info = platform_get_drvdata(dev); 854b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 855b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return 0; 856b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 857b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 858b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#else 859b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define bf5xx_nand_suspend NULL 860b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#define bf5xx_nand_resume NULL 861b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu#endif 862b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 863b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu/* driver device registration */ 864b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic struct platform_driver bf5xx_nand_driver = { 865b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu .probe = bf5xx_nand_probe, 8662445af3853928bf3ee7960e09f548a1b07924091Mike Frysinger .remove = __devexit_p(bf5xx_nand_remove), 867b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu .suspend = bf5xx_nand_suspend, 868b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu .resume = bf5xx_nand_resume, 869b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu .driver = { 870b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu .name = DRV_NAME, 871b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu .owner = THIS_MODULE, 872b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu }, 873b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu}; 874b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 875b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic int __init bf5xx_nand_init(void) 876b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 877b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu printk(KERN_INFO "%s, Version %s (c) 2007 Analog Devices, Inc.\n", 878b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu DRV_DESC, DRV_VERSION); 879b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 880b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu return platform_driver_register(&bf5xx_nand_driver); 881b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 882b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 883b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wustatic void __exit bf5xx_nand_exit(void) 884b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu{ 885b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu platform_driver_unregister(&bf5xx_nand_driver); 886b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu} 887b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 888b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wumodule_init(bf5xx_nand_init); 889b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wumodule_exit(bf5xx_nand_exit); 890b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan Wu 891b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan WuMODULE_LICENSE("GPL"); 892b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan WuMODULE_AUTHOR(DRV_AUTHOR); 893b37bde147890c8fea8369a5a4e230dabdea4ebfbBryan WuMODULE_DESCRIPTION(DRV_DESC); 8941ff184225b15930ea118ac2130f074c741d34f08Kay SieversMODULE_ALIAS("platform:" DRV_NAME); 895