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