sharpsl.c revision 5bd34c091a044d130601370c370f84b1c59f1627
1/* 2 * drivers/mtd/nand/sharpsl.c 3 * 4 * Copyright (C) 2004 Richard Purdie 5 * 6 * $Id: sharpsl.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ 7 * 8 * Based on Sharp's NAND driver sharp_sl.c 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 * 14 */ 15 16#include <linux/genhd.h> 17#include <linux/slab.h> 18#include <linux/module.h> 19#include <linux/delay.h> 20#include <linux/mtd/mtd.h> 21#include <linux/mtd/nand.h> 22#include <linux/mtd/nand_ecc.h> 23#include <linux/mtd/partitions.h> 24#include <linux/interrupt.h> 25#include <asm/io.h> 26#include <asm/hardware.h> 27#include <asm/mach-types.h> 28 29static void __iomem *sharpsl_io_base; 30static int sharpsl_phys_base = 0x0C000000; 31 32/* register offset */ 33#define ECCLPLB sharpsl_io_base+0x00 /* line parity 7 - 0 bit */ 34#define ECCLPUB sharpsl_io_base+0x04 /* line parity 15 - 8 bit */ 35#define ECCCP sharpsl_io_base+0x08 /* column parity 5 - 0 bit */ 36#define ECCCNTR sharpsl_io_base+0x0C /* ECC byte counter */ 37#define ECCCLRR sharpsl_io_base+0x10 /* cleare ECC */ 38#define FLASHIO sharpsl_io_base+0x14 /* Flash I/O */ 39#define FLASHCTL sharpsl_io_base+0x18 /* Flash Control */ 40 41/* Flash control bit */ 42#define FLRYBY (1 << 5) 43#define FLCE1 (1 << 4) 44#define FLWP (1 << 3) 45#define FLALE (1 << 2) 46#define FLCLE (1 << 1) 47#define FLCE0 (1 << 0) 48 49/* 50 * MTD structure for SharpSL 51 */ 52static struct mtd_info *sharpsl_mtd = NULL; 53 54/* 55 * Define partitions for flash device 56 */ 57#define DEFAULT_NUM_PARTITIONS 3 58 59static int nr_partitions; 60static struct mtd_partition sharpsl_nand_default_partition_info[] = { 61 { 62 .name = "System Area", 63 .offset = 0, 64 .size = 7 * 1024 * 1024, 65 }, 66 { 67 .name = "Root Filesystem", 68 .offset = 7 * 1024 * 1024, 69 .size = 30 * 1024 * 1024, 70 }, 71 { 72 .name = "Home Filesystem", 73 .offset = MTDPART_OFS_APPEND, 74 .size = MTDPART_SIZ_FULL, 75 }, 76}; 77 78/* 79 * hardware specific access to control-lines 80 * ctrl: 81 * NAND_CNE: bit 0 -> bit 0 & 4 82 * NAND_CLE: bit 1 -> bit 1 83 * NAND_ALE: bit 2 -> bit 2 84 * 85 */ 86static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, 87 unsigned int ctrl) 88{ 89 struct nand_chip *chip = mtd->priv; 90 91 if (ctrl & NAND_CTRL_CHANGE) { 92 unsigned char bits = ctrl & 0x07; 93 94 bits |= (ctrl & 0x01) << 4; 95 writeb((readb(FLASHCTL) & 0x17) | bits, FLASHCTL); 96 } 97 98 if (cmd != NAND_CMD_NONE) 99 writeb(cmd, chip->IO_ADDR_W); 100} 101 102static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; 103 104static struct nand_bbt_descr sharpsl_bbt = { 105 .options = 0, 106 .offs = 4, 107 .len = 2, 108 .pattern = scan_ff_pattern 109}; 110 111static struct nand_bbt_descr sharpsl_akita_bbt = { 112 .options = 0, 113 .offs = 4, 114 .len = 1, 115 .pattern = scan_ff_pattern 116}; 117 118static struct nand_ecclayout akita_oobinfo = { 119 .eccbytes = 24, 120 .eccpos = { 121 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11, 122 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23, 123 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37}, 124 .oobfree = {{0x08, 0x09}} 125}; 126 127static int sharpsl_nand_dev_ready(struct mtd_info *mtd) 128{ 129 return !((readb(FLASHCTL) & FLRYBY) == 0); 130} 131 132static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode) 133{ 134 writeb(0, ECCCLRR); 135} 136 137static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) 138{ 139 ecc_code[0] = ~readb(ECCLPUB); 140 ecc_code[1] = ~readb(ECCLPLB); 141 ecc_code[2] = (~readb(ECCCP) << 2) | 0x03; 142 return readb(ECCCNTR) != 0; 143} 144 145#ifdef CONFIG_MTD_PARTITIONS 146const char *part_probes[] = { "cmdlinepart", NULL }; 147#endif 148 149/* 150 * Main initialization routine 151 */ 152static int __init sharpsl_nand_init(void) 153{ 154 struct nand_chip *this; 155 struct mtd_partition *sharpsl_partition_info; 156 int err = 0; 157 158 /* Allocate memory for MTD device structure and private data */ 159 sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); 160 if (!sharpsl_mtd) { 161 printk("Unable to allocate SharpSL NAND MTD device structure.\n"); 162 return -ENOMEM; 163 } 164 165 /* map physical adress */ 166 sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); 167 if (!sharpsl_io_base) { 168 printk("ioremap to access Sharp SL NAND chip failed\n"); 169 kfree(sharpsl_mtd); 170 return -EIO; 171 } 172 173 /* Get pointer to private data */ 174 this = (struct nand_chip *)(&sharpsl_mtd[1]); 175 176 /* Initialize structures */ 177 memset(sharpsl_mtd, 0, sizeof(struct mtd_info)); 178 memset(this, 0, sizeof(struct nand_chip)); 179 180 /* Link the private data with the MTD structure */ 181 sharpsl_mtd->priv = this; 182 sharpsl_mtd->owner = THIS_MODULE; 183 184 /* 185 * PXA initialize 186 */ 187 writeb(readb(FLASHCTL) | FLWP, FLASHCTL); 188 189 /* Set address of NAND IO lines */ 190 this->IO_ADDR_R = FLASHIO; 191 this->IO_ADDR_W = FLASHIO; 192 /* Set address of hardware control function */ 193 this->cmd_ctrl = sharpsl_nand_hwcontrol; 194 this->dev_ready = sharpsl_nand_dev_ready; 195 /* 15 us command delay time */ 196 this->chip_delay = 15; 197 /* set eccmode using hardware ECC */ 198 this->ecc.mode = NAND_ECC_HW; 199 this->ecc.size = 256; 200 this->ecc.bytes = 3; 201 this->badblock_pattern = &sharpsl_bbt; 202 if (machine_is_akita() || machine_is_borzoi()) { 203 this->badblock_pattern = &sharpsl_akita_bbt; 204 this->ecc.layout = &akita_oobinfo; 205 } 206 this->ecc.hwctl = sharpsl_nand_enable_hwecc; 207 this->ecc.calculate = sharpsl_nand_calculate_ecc; 208 this->ecc.correct = nand_correct_data; 209 210 /* Scan to find existence of the device */ 211 err = nand_scan(sharpsl_mtd, 1); 212 if (err) { 213 iounmap(sharpsl_io_base); 214 kfree(sharpsl_mtd); 215 return err; 216 } 217 218 /* Register the partitions */ 219 sharpsl_mtd->name = "sharpsl-nand"; 220 nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, &sharpsl_partition_info, 0); 221 222 if (nr_partitions <= 0) { 223 nr_partitions = DEFAULT_NUM_PARTITIONS; 224 sharpsl_partition_info = sharpsl_nand_default_partition_info; 225 if (machine_is_poodle()) { 226 sharpsl_partition_info[1].size = 22 * 1024 * 1024; 227 } else if (machine_is_corgi() || machine_is_shepherd()) { 228 sharpsl_partition_info[1].size = 25 * 1024 * 1024; 229 } else if (machine_is_husky()) { 230 sharpsl_partition_info[1].size = 53 * 1024 * 1024; 231 } else if (machine_is_spitz()) { 232 sharpsl_partition_info[1].size = 5 * 1024 * 1024; 233 } else if (machine_is_akita()) { 234 sharpsl_partition_info[1].size = 58 * 1024 * 1024; 235 } else if (machine_is_borzoi()) { 236 sharpsl_partition_info[1].size = 32 * 1024 * 1024; 237 } 238 } 239 240 if (machine_is_husky() || machine_is_borzoi() || machine_is_akita()) { 241 /* Need to use small eraseblock size for backward compatibility */ 242 sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS; 243 } 244 245 add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions); 246 247 /* Return happy */ 248 return 0; 249} 250 251module_init(sharpsl_nand_init); 252 253/* 254 * Clean up routine 255 */ 256static void __exit sharpsl_nand_cleanup(void) 257{ 258 struct nand_chip *this = (struct nand_chip *)&sharpsl_mtd[1]; 259 260 /* Release resources, unregister device */ 261 nand_release(sharpsl_mtd); 262 263 iounmap(sharpsl_io_base); 264 265 /* Free the MTD device structure */ 266 kfree(sharpsl_mtd); 267} 268 269module_exit(sharpsl_nand_cleanup); 270 271MODULE_LICENSE("GPL"); 272MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); 273MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series"); 274