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