ndfc.c revision f99640dee209df4730f35a28b02693affd571ad5
1/* 2 * drivers/mtd/ndfc.c 3 * 4 * Overview: 5 * Platform independent driver for NDFC (NanD Flash Controller) 6 * integrated into EP440 cores 7 * 8 * Ported to an OF platform driver by Sean MacLennan 9 * 10 * The NDFC supports multiple chips, but this driver only supports a 11 * single chip since I do not have access to any boards with 12 * multiple chips. 13 * 14 * Author: Thomas Gleixner 15 * 16 * Copyright 2006 IBM 17 * Copyright 2008 PIKA Technologies 18 * Sean MacLennan <smaclennan@pikatech.com> 19 * 20 * This program is free software; you can redistribute it and/or modify it 21 * under the terms of the GNU General Public License as published by the 22 * Free Software Foundation; either version 2 of the License, or (at your 23 * option) any later version. 24 * 25 */ 26#include <linux/module.h> 27#include <linux/mtd/nand.h> 28#include <linux/mtd/nand_ecc.h> 29#include <linux/mtd/partitions.h> 30#include <linux/mtd/ndfc.h> 31#include <linux/slab.h> 32#include <linux/mtd/mtd.h> 33#include <linux/of_platform.h> 34#include <asm/io.h> 35 36#define NDFC_MAX_CS 4 37 38struct ndfc_controller { 39 struct platform_device *ofdev; 40 void __iomem *ndfcbase; 41 struct mtd_info mtd; 42 struct nand_chip chip; 43 int chip_select; 44 struct nand_hw_control ndfc_control; 45}; 46 47static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS]; 48 49static void ndfc_select_chip(struct mtd_info *mtd, int chip) 50{ 51 uint32_t ccr; 52 struct nand_chip *nchip = mtd->priv; 53 struct ndfc_controller *ndfc = nchip->priv; 54 55 ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); 56 if (chip >= 0) { 57 ccr &= ~NDFC_CCR_BS_MASK; 58 ccr |= NDFC_CCR_BS(chip + ndfc->chip_select); 59 } else 60 ccr |= NDFC_CCR_RESET_CE; 61 out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); 62} 63 64static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) 65{ 66 struct nand_chip *chip = mtd->priv; 67 struct ndfc_controller *ndfc = chip->priv; 68 69 if (cmd == NAND_CMD_NONE) 70 return; 71 72 if (ctrl & NAND_CLE) 73 writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD); 74 else 75 writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE); 76} 77 78static int ndfc_ready(struct mtd_info *mtd) 79{ 80 struct nand_chip *chip = mtd->priv; 81 struct ndfc_controller *ndfc = chip->priv; 82 83 return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; 84} 85 86static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) 87{ 88 uint32_t ccr; 89 struct nand_chip *chip = mtd->priv; 90 struct ndfc_controller *ndfc = chip->priv; 91 92 ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); 93 ccr |= NDFC_CCR_RESET_ECC; 94 out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); 95 wmb(); 96} 97 98static int ndfc_calculate_ecc(struct mtd_info *mtd, 99 const u_char *dat, u_char *ecc_code) 100{ 101 struct nand_chip *chip = mtd->priv; 102 struct ndfc_controller *ndfc = chip->priv; 103 uint32_t ecc; 104 uint8_t *p = (uint8_t *)&ecc; 105 106 wmb(); 107 ecc = in_be32(ndfc->ndfcbase + NDFC_ECC); 108 /* The NDFC uses Smart Media (SMC) bytes order */ 109 ecc_code[0] = p[1]; 110 ecc_code[1] = p[2]; 111 ecc_code[2] = p[3]; 112 113 return 0; 114} 115 116/* 117 * Speedups for buffer read/write/verify 118 * 119 * NDFC allows 32bit read/write of data. So we can speed up the buffer 120 * functions. No further checking, as nand_base will always read/write 121 * page aligned. 122 */ 123static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) 124{ 125 struct nand_chip *chip = mtd->priv; 126 struct ndfc_controller *ndfc = chip->priv; 127 uint32_t *p = (uint32_t *) buf; 128 129 for(;len > 0; len -= 4) 130 *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA); 131} 132 133static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) 134{ 135 struct nand_chip *chip = mtd->priv; 136 struct ndfc_controller *ndfc = chip->priv; 137 uint32_t *p = (uint32_t *) buf; 138 139 for(;len > 0; len -= 4) 140 out_be32(ndfc->ndfcbase + NDFC_DATA, *p++); 141} 142 143static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) 144{ 145 struct nand_chip *chip = mtd->priv; 146 struct ndfc_controller *ndfc = chip->priv; 147 uint32_t *p = (uint32_t *) buf; 148 149 for(;len > 0; len -= 4) 150 if (*p++ != in_be32(ndfc->ndfcbase + NDFC_DATA)) 151 return -EFAULT; 152 return 0; 153} 154 155/* 156 * Initialize chip structure 157 */ 158static int ndfc_chip_init(struct ndfc_controller *ndfc, 159 struct device_node *node) 160{ 161 struct device_node *flash_np; 162 struct nand_chip *chip = &ndfc->chip; 163 struct mtd_part_parser_data ppdata; 164 int ret; 165 166 chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; 167 chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; 168 chip->cmd_ctrl = ndfc_hwcontrol; 169 chip->dev_ready = ndfc_ready; 170 chip->select_chip = ndfc_select_chip; 171 chip->chip_delay = 50; 172 chip->controller = &ndfc->ndfc_control; 173 chip->read_buf = ndfc_read_buf; 174 chip->write_buf = ndfc_write_buf; 175 chip->verify_buf = ndfc_verify_buf; 176 chip->ecc.correct = nand_correct_data; 177 chip->ecc.hwctl = ndfc_enable_hwecc; 178 chip->ecc.calculate = ndfc_calculate_ecc; 179 chip->ecc.mode = NAND_ECC_HW; 180 chip->ecc.size = 256; 181 chip->ecc.bytes = 3; 182 chip->priv = ndfc; 183 184 ndfc->mtd.priv = chip; 185 ndfc->mtd.owner = THIS_MODULE; 186 187 flash_np = of_get_next_child(node, NULL); 188 if (!flash_np) 189 return -ENODEV; 190 191 ppdata.of_node = flash_np; 192 ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s", 193 dev_name(&ndfc->ofdev->dev), flash_np->name); 194 if (!ndfc->mtd.name) { 195 ret = -ENOMEM; 196 goto err; 197 } 198 199 ret = nand_scan(&ndfc->mtd, 1); 200 if (ret) 201 goto err; 202 203 ret = mtd_device_parse_register(&ndfc->mtd, NULL, &ppdata, NULL, 0); 204 205err: 206 of_node_put(flash_np); 207 if (ret) 208 kfree(ndfc->mtd.name); 209 return ret; 210} 211 212static int __devinit ndfc_probe(struct platform_device *ofdev) 213{ 214 struct ndfc_controller *ndfc; 215 const __be32 *reg; 216 u32 ccr; 217 int err, len, cs; 218 219 /* Read the reg property to get the chip select */ 220 reg = of_get_property(ofdev->dev.of_node, "reg", &len); 221 if (reg == NULL || len != 12) { 222 dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); 223 return -ENOENT; 224 } 225 226 cs = be32_to_cpu(reg[0]); 227 if (cs >= NDFC_MAX_CS) { 228 dev_err(&ofdev->dev, "invalid CS number (%d)\n", cs); 229 return -EINVAL; 230 } 231 232 ndfc = &ndfc_ctrl[cs]; 233 ndfc->chip_select = cs; 234 235 spin_lock_init(&ndfc->ndfc_control.lock); 236 init_waitqueue_head(&ndfc->ndfc_control.wq); 237 ndfc->ofdev = ofdev; 238 dev_set_drvdata(&ofdev->dev, ndfc); 239 240 ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0); 241 if (!ndfc->ndfcbase) { 242 dev_err(&ofdev->dev, "failed to get memory\n"); 243 return -EIO; 244 } 245 246 ccr = NDFC_CCR_BS(ndfc->chip_select); 247 248 /* It is ok if ccr does not exist - just default to 0 */ 249 reg = of_get_property(ofdev->dev.of_node, "ccr", NULL); 250 if (reg) 251 ccr |= be32_to_cpup(reg); 252 253 out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); 254 255 /* Set the bank settings if given */ 256 reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL); 257 if (reg) { 258 int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); 259 out_be32(ndfc->ndfcbase + offset, be32_to_cpup(reg)); 260 } 261 262 err = ndfc_chip_init(ndfc, ofdev->dev.of_node); 263 if (err) { 264 iounmap(ndfc->ndfcbase); 265 return err; 266 } 267 268 return 0; 269} 270 271static int __devexit ndfc_remove(struct platform_device *ofdev) 272{ 273 struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); 274 275 nand_release(&ndfc->mtd); 276 kfree(ndfc->mtd.name); 277 278 return 0; 279} 280 281static const struct of_device_id ndfc_match[] = { 282 { .compatible = "ibm,ndfc", }, 283 {} 284}; 285MODULE_DEVICE_TABLE(of, ndfc_match); 286 287static struct platform_driver ndfc_driver = { 288 .driver = { 289 .name = "ndfc", 290 .owner = THIS_MODULE, 291 .of_match_table = ndfc_match, 292 }, 293 .probe = ndfc_probe, 294 .remove = __devexit_p(ndfc_remove), 295}; 296 297module_platform_driver(ndfc_driver); 298 299MODULE_LICENSE("GPL"); 300MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); 301MODULE_DESCRIPTION("OF Platform driver for NDFC"); 302