5  *   Platform independend driver for NDFC (NanD Flash Controller)
 
   6  *   integrated into EP440 cores
 
   8  *  Author: Thomas Gleixner
 
  12  *  This program is free software; you can redistribute  it and/or modify it
 
  13  *  under  the terms of  the GNU General  Public License as published by the
 
  14  *  Free Software Foundation;  either version 2 of the  License, or (at your
 
  15  *  option) any later version.
 
  18 #include <linux/module.h>
 
  19 #include <linux/mtd/nand.h>
 
  20 #include <linux/mtd/nand_ecc.h>
 
  21 #include <linux/mtd/partitions.h>
 
  22 #include <linux/mtd/ndfc.h>
 
  23 #include <linux/mtd/mtd.h>
 
  24 #include <linux/platform_device.h>
 
  27 #include <asm/ibm44x.h>
 
  29 struct ndfc_nand_mtd {
 
  31         struct nand_chip                chip;
 
  32         struct platform_nand_chip       *pl_chip;
 
  35 static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS];
 
  37 struct ndfc_controller {
 
  38         void __iomem            *ndfcbase;
 
  39         struct nand_hw_control  ndfc_control;
 
  40         atomic_t                childs_active;
 
  43 static struct ndfc_controller ndfc_ctrl;
 
  45 static void ndfc_select_chip(struct mtd_info *mtd, int chip)
 
  48         struct ndfc_controller *ndfc = &ndfc_ctrl;
 
  49         struct nand_chip *nandchip = mtd->priv;
 
  50         struct ndfc_nand_mtd *nandmtd = nandchip->priv;
 
  51         struct platform_nand_chip *pchip = nandmtd->pl_chip;
 
  53         ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
 
  55                 ccr &= ~NDFC_CCR_BS_MASK;
 
  56                 ccr |= NDFC_CCR_BS(chip + pchip->chip_offset);
 
  58                 ccr |= NDFC_CCR_RESET_CE;
 
  59         writel(ccr, ndfc->ndfcbase + NDFC_CCR);
 
  62 static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 
  64         struct nand_chip *chip = mtd->priv;
 
  66         if (cmd == NAND_CMD_NONE)
 
  70                 writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_CMD);
 
  72                 writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_ALE);
 
  75 static int ndfc_ready(struct mtd_info *mtd)
 
  77         struct ndfc_controller *ndfc = &ndfc_ctrl;
 
  79         return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
 
  82 static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
 
  85         struct ndfc_controller *ndfc = &ndfc_ctrl;
 
  87         ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
 
  88         ccr |= NDFC_CCR_RESET_ECC;
 
  89         __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
 
  93 static int ndfc_calculate_ecc(struct mtd_info *mtd,
 
  94                               const u_char *dat, u_char *ecc_code)
 
  96         struct ndfc_controller *ndfc = &ndfc_ctrl;
 
  98         uint8_t *p = (uint8_t *)&ecc;
 
 101         ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC);
 
 110  * Speedups for buffer read/write/verify
 
 112  * NDFC allows 32bit read/write of data. So we can speed up the buffer
 
 113  * functions. No further checking, as nand_base will always read/write
 
 116 static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 
 118         struct ndfc_controller *ndfc = &ndfc_ctrl;
 
 119         uint32_t *p = (uint32_t *) buf;
 
 121         for(;len > 0; len -= 4)
 
 122                 *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA);
 
 125 static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 
 127         struct ndfc_controller *ndfc = &ndfc_ctrl;
 
 128         uint32_t *p = (uint32_t *) buf;
 
 130         for(;len > 0; len -= 4)
 
 131                 __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA);
 
 134 static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 
 136         struct ndfc_controller *ndfc = &ndfc_ctrl;
 
 137         uint32_t *p = (uint32_t *) buf;
 
 139         for(;len > 0; len -= 4)
 
 140                 if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA))
 
 146  * Initialize chip structure
 
 148 static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
 
 150         struct ndfc_controller *ndfc = &ndfc_ctrl;
 
 151         struct nand_chip *chip = &mtd->chip;
 
 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;
 
 160         chip->options = mtd->pl_chip->options;
 
 161         chip->controller = &ndfc->ndfc_control;
 
 162         chip->read_buf = ndfc_read_buf;
 
 163         chip->write_buf = ndfc_write_buf;
 
 164         chip->verify_buf = ndfc_verify_buf;
 
 165         chip->ecc.correct = nand_correct_data;
 
 166         chip->ecc.hwctl = ndfc_enable_hwecc;
 
 167         chip->ecc.calculate = ndfc_calculate_ecc;
 
 168         chip->ecc.mode = NAND_ECC_HW;
 
 169         chip->ecc.size = 256;
 
 171         chip->ecclayout = mtd->pl_chip->ecclayout;
 
 172         mtd->mtd.priv = chip;
 
 173         mtd->mtd.owner = THIS_MODULE;
 
 176 static int ndfc_chip_probe(struct platform_device *pdev)
 
 178         struct platform_nand_chip *nc = pdev->dev.platform_data;
 
 179         struct ndfc_chip_settings *settings = nc->priv;
 
 180         struct ndfc_controller *ndfc = &ndfc_ctrl;
 
 181         struct ndfc_nand_mtd *nandmtd;
 
 183         if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS)
 
 186         /* Set the bank settings */
 
 187         __raw_writel(settings->bank_settings,
 
 188                      ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2));
 
 190         nandmtd = &ndfc_mtd[pdev->id];
 
 191         if (nandmtd->pl_chip)
 
 194         nandmtd->pl_chip = nc;
 
 195         ndfc_chip_init(nandmtd);
 
 198         if (nand_scan(&nandmtd->mtd, nc->nr_chips)) {
 
 199                 nandmtd->pl_chip = NULL;
 
 203 #ifdef CONFIG_MTD_PARTITIONS
 
 204         printk("Number of partitions %d\n", nc->nr_partitions);
 
 205         if (nc->nr_partitions) {
 
 206                 /* Add the full device, so complete dumps can be made */
 
 207                 add_mtd_device(&nandmtd->mtd);
 
 208                 add_mtd_partitions(&nandmtd->mtd, nc->partitions,
 
 213                 add_mtd_device(&nandmtd->mtd);
 
 216         atomic_inc(&ndfc->childs_active);
 
 220 static int ndfc_chip_remove(struct platform_device *pdev)
 
 225 static int ndfc_nand_probe(struct platform_device *pdev)
 
 227         struct platform_nand_ctrl *nc = pdev->dev.platform_data;
 
 228         struct ndfc_controller_settings *settings = nc->priv;
 
 229         struct resource *res = pdev->resource;
 
 230         struct ndfc_controller *ndfc = &ndfc_ctrl;
 
 231         unsigned long long phys = settings->ndfc_erpn | res->start;
 
 233         ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
 
 234         if (!ndfc->ndfcbase) {
 
 235                 printk(KERN_ERR "NDFC: ioremap failed\n");
 
 239         __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR);
 
 241         spin_lock_init(&ndfc->ndfc_control.lock);
 
 242         init_waitqueue_head(&ndfc->ndfc_control.wq);
 
 244         platform_set_drvdata(pdev, ndfc);
 
 246         printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n",
 
 247                __raw_readl(ndfc->ndfcbase + NDFC_REVID));
 
 252 static int ndfc_nand_remove(struct platform_device *pdev)
 
 254         struct ndfc_controller *ndfc = platform_get_drvdata(pdev);
 
 256         if (atomic_read(&ndfc->childs_active))
 
 260                 platform_set_drvdata(pdev, NULL);
 
 261                 iounmap(ndfc_ctrl.ndfcbase);
 
 262                 ndfc_ctrl.ndfcbase = NULL;
 
 267 /* driver device registration */
 
 269 static struct platform_driver ndfc_chip_driver = {
 
 270         .probe          = ndfc_chip_probe,
 
 271         .remove         = ndfc_chip_remove,
 
 274                 .owner  = THIS_MODULE,
 
 278 static struct platform_driver ndfc_nand_driver = {
 
 279         .probe          = ndfc_nand_probe,
 
 280         .remove         = ndfc_nand_remove,
 
 283                 .owner  = THIS_MODULE,
 
 287 static int __init ndfc_nand_init(void)
 
 291         spin_lock_init(&ndfc_ctrl.ndfc_control.lock);
 
 292         init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq);
 
 294         ret = platform_driver_register(&ndfc_nand_driver);
 
 296                 ret = platform_driver_register(&ndfc_chip_driver);
 
 300 static void __exit ndfc_nand_exit(void)
 
 302         platform_driver_unregister(&ndfc_chip_driver);
 
 303         platform_driver_unregister(&ndfc_nand_driver);
 
 306 module_init(ndfc_nand_init);
 
 307 module_exit(ndfc_nand_exit);
 
 309 MODULE_LICENSE("GPL");
 
 310 MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
 
 311 MODULE_DESCRIPTION("Platform driver for NDFC");