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