linux/drivers/memory/fsl_ifc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2011 Freescale Semiconductor, Inc
   4 *
   5 * Freescale Integrated Flash Controller
   6 *
   7 * Author: Dipen Dudhat <Dipen.Dudhat@freescale.com>
   8 */
   9#include <linux/module.h>
  10#include <linux/kernel.h>
  11#include <linux/compiler.h>
  12#include <linux/sched.h>
  13#include <linux/spinlock.h>
  14#include <linux/types.h>
  15#include <linux/slab.h>
  16#include <linux/io.h>
  17#include <linux/of.h>
  18#include <linux/of_device.h>
  19#include <linux/platform_device.h>
  20#include <linux/fsl_ifc.h>
  21#include <linux/irqdomain.h>
  22#include <linux/of_address.h>
  23#include <linux/of_irq.h>
  24
  25struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
  26EXPORT_SYMBOL(fsl_ifc_ctrl_dev);
  27
  28/*
  29 * convert_ifc_address - convert the base address
  30 * @addr_base:  base address of the memory bank
  31 */
  32unsigned int convert_ifc_address(phys_addr_t addr_base)
  33{
  34        return addr_base & CSPR_BA;
  35}
  36EXPORT_SYMBOL(convert_ifc_address);
  37
  38/*
  39 * fsl_ifc_find - find IFC bank
  40 * @addr_base:  base address of the memory bank
  41 *
  42 * This function walks IFC banks comparing "Base address" field of the CSPR
  43 * registers with the supplied addr_base argument. When bases match this
  44 * function returns bank number (starting with 0), otherwise it returns
  45 * appropriate errno value.
  46 */
  47int fsl_ifc_find(phys_addr_t addr_base)
  48{
  49        int i = 0;
  50
  51        if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->gregs)
  52                return -ENODEV;
  53
  54        for (i = 0; i < fsl_ifc_ctrl_dev->banks; i++) {
  55                u32 cspr = ifc_in32(&fsl_ifc_ctrl_dev->gregs->cspr_cs[i].cspr);
  56
  57                if (cspr & CSPR_V && (cspr & CSPR_BA) ==
  58                                convert_ifc_address(addr_base))
  59                        return i;
  60        }
  61
  62        return -ENOENT;
  63}
  64EXPORT_SYMBOL(fsl_ifc_find);
  65
  66static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
  67{
  68        struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
  69
  70        /*
  71         * Clear all the common status and event registers
  72         */
  73        if (ifc_in32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER)
  74                ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);
  75
  76        /* enable all error and events */
  77        ifc_out32(IFC_CM_EVTER_EN_CSEREN, &ifc->cm_evter_en);
  78
  79        /* enable all error and event interrupts */
  80        ifc_out32(IFC_CM_EVTER_INTR_EN_CSERIREN, &ifc->cm_evter_intr_en);
  81        ifc_out32(0x0, &ifc->cm_erattr0);
  82        ifc_out32(0x0, &ifc->cm_erattr1);
  83
  84        return 0;
  85}
  86
  87static int fsl_ifc_ctrl_remove(struct platform_device *dev)
  88{
  89        struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
  90
  91        free_irq(ctrl->nand_irq, ctrl);
  92        free_irq(ctrl->irq, ctrl);
  93
  94        irq_dispose_mapping(ctrl->nand_irq);
  95        irq_dispose_mapping(ctrl->irq);
  96
  97        iounmap(ctrl->gregs);
  98
  99        dev_set_drvdata(&dev->dev, NULL);
 100
 101        return 0;
 102}
 103
 104/*
 105 * NAND events are split between an operational interrupt which only
 106 * receives OPC, and an error interrupt that receives everything else,
 107 * including non-NAND errors.  Whichever interrupt gets to it first
 108 * records the status and wakes the wait queue.
 109 */
 110static DEFINE_SPINLOCK(nand_irq_lock);
 111
 112static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl)
 113{
 114        struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
 115        unsigned long flags;
 116        u32 stat;
 117
 118        spin_lock_irqsave(&nand_irq_lock, flags);
 119
 120        stat = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
 121        if (stat) {
 122                ifc_out32(stat, &ifc->ifc_nand.nand_evter_stat);
 123                ctrl->nand_stat = stat;
 124                wake_up(&ctrl->nand_wait);
 125        }
 126
 127        spin_unlock_irqrestore(&nand_irq_lock, flags);
 128
 129        return stat;
 130}
 131
 132static irqreturn_t fsl_ifc_nand_irq(int irqno, void *data)
 133{
 134        struct fsl_ifc_ctrl *ctrl = data;
 135
 136        if (check_nand_stat(ctrl))
 137                return IRQ_HANDLED;
 138
 139        return IRQ_NONE;
 140}
 141
 142/*
 143 * NOTE: This interrupt is used to report ifc events of various kinds,
 144 * such as transaction errors on the chipselects.
 145 */
 146static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
 147{
 148        struct fsl_ifc_ctrl *ctrl = data;
 149        struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
 150        u32 err_axiid, err_srcid, status, cs_err, err_addr;
 151        irqreturn_t ret = IRQ_NONE;
 152
 153        /* read for chip select error */
 154        cs_err = ifc_in32(&ifc->cm_evter_stat);
 155        if (cs_err) {
 156                dev_err(ctrl->dev, "transaction sent to IFC is not mapped to any memory bank 0x%08X\n",
 157                        cs_err);
 158                /* clear the chip select error */
 159                ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);
 160
 161                /* read error attribute registers print the error information */
 162                status = ifc_in32(&ifc->cm_erattr0);
 163                err_addr = ifc_in32(&ifc->cm_erattr1);
 164
 165                if (status & IFC_CM_ERATTR0_ERTYP_READ)
 166                        dev_err(ctrl->dev, "Read transaction error CM_ERATTR0 0x%08X\n",
 167                                status);
 168                else
 169                        dev_err(ctrl->dev, "Write transaction error CM_ERATTR0 0x%08X\n",
 170                                status);
 171
 172                err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>
 173                                        IFC_CM_ERATTR0_ERAID_SHIFT;
 174                dev_err(ctrl->dev, "AXI ID of the error transaction 0x%08X\n",
 175                        err_axiid);
 176
 177                err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>
 178                                        IFC_CM_ERATTR0_ESRCID_SHIFT;
 179                dev_err(ctrl->dev, "SRC ID of the error transaction 0x%08X\n",
 180                        err_srcid);
 181
 182                dev_err(ctrl->dev, "Transaction Address corresponding to error ERADDR 0x%08X\n",
 183                        err_addr);
 184
 185                ret = IRQ_HANDLED;
 186        }
 187
 188        if (check_nand_stat(ctrl))
 189                ret = IRQ_HANDLED;
 190
 191        return ret;
 192}
 193
 194/*
 195 * fsl_ifc_ctrl_probe
 196 *
 197 * called by device layer when it finds a device matching
 198 * one our driver can handled. This code allocates all of
 199 * the resources needed for the controller only.  The
 200 * resources for the NAND banks themselves are allocated
 201 * in the chip probe function.
 202 */
 203static int fsl_ifc_ctrl_probe(struct platform_device *dev)
 204{
 205        int ret = 0;
 206        int version, banks;
 207        void __iomem *addr;
 208
 209        dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
 210
 211        fsl_ifc_ctrl_dev = devm_kzalloc(&dev->dev, sizeof(*fsl_ifc_ctrl_dev),
 212                                        GFP_KERNEL);
 213        if (!fsl_ifc_ctrl_dev)
 214                return -ENOMEM;
 215
 216        dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
 217
 218        /* IOMAP the entire IFC region */
 219        fsl_ifc_ctrl_dev->gregs = of_iomap(dev->dev.of_node, 0);
 220        if (!fsl_ifc_ctrl_dev->gregs) {
 221                dev_err(&dev->dev, "failed to get memory region\n");
 222                return -ENODEV;
 223        }
 224
 225        if (of_property_read_bool(dev->dev.of_node, "little-endian")) {
 226                fsl_ifc_ctrl_dev->little_endian = true;
 227                dev_dbg(&dev->dev, "IFC REGISTERS are LITTLE endian\n");
 228        } else {
 229                fsl_ifc_ctrl_dev->little_endian = false;
 230                dev_dbg(&dev->dev, "IFC REGISTERS are BIG endian\n");
 231        }
 232
 233        version = ifc_in32(&fsl_ifc_ctrl_dev->gregs->ifc_rev) &
 234                        FSL_IFC_VERSION_MASK;
 235
 236        banks = (version == FSL_IFC_VERSION_1_0_0) ? 4 : 8;
 237        dev_info(&dev->dev, "IFC version %d.%d, %d banks\n",
 238                version >> 24, (version >> 16) & 0xf, banks);
 239
 240        fsl_ifc_ctrl_dev->version = version;
 241        fsl_ifc_ctrl_dev->banks = banks;
 242
 243        addr = fsl_ifc_ctrl_dev->gregs;
 244        if (version >= FSL_IFC_VERSION_2_0_0)
 245                addr += PGOFFSET_64K;
 246        else
 247                addr += PGOFFSET_4K;
 248        fsl_ifc_ctrl_dev->rregs = addr;
 249
 250        /* get the Controller level irq */
 251        fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
 252        if (fsl_ifc_ctrl_dev->irq == 0) {
 253                dev_err(&dev->dev, "failed to get irq resource for IFC\n");
 254                ret = -ENODEV;
 255                goto err;
 256        }
 257
 258        /* get the nand machine irq */
 259        fsl_ifc_ctrl_dev->nand_irq =
 260                        irq_of_parse_and_map(dev->dev.of_node, 1);
 261
 262        fsl_ifc_ctrl_dev->dev = &dev->dev;
 263
 264        ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
 265        if (ret < 0)
 266                goto err;
 267
 268        init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
 269
 270        ret = request_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_irq, IRQF_SHARED,
 271                          "fsl-ifc", fsl_ifc_ctrl_dev);
 272        if (ret != 0) {
 273                dev_err(&dev->dev, "failed to install irq (%d)\n",
 274                        fsl_ifc_ctrl_dev->irq);
 275                goto err_irq;
 276        }
 277
 278        if (fsl_ifc_ctrl_dev->nand_irq) {
 279                ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq,
 280                                0, "fsl-ifc-nand", fsl_ifc_ctrl_dev);
 281                if (ret != 0) {
 282                        dev_err(&dev->dev, "failed to install irq (%d)\n",
 283                                fsl_ifc_ctrl_dev->nand_irq);
 284                        goto err_nandirq;
 285                }
 286        }
 287
 288        return 0;
 289
 290err_nandirq:
 291        free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
 292        irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
 293err_irq:
 294        free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
 295        irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
 296err:
 297        iounmap(fsl_ifc_ctrl_dev->gregs);
 298        return ret;
 299}
 300
 301static const struct of_device_id fsl_ifc_match[] = {
 302        {
 303                .compatible = "fsl,ifc",
 304        },
 305        {},
 306};
 307
 308static struct platform_driver fsl_ifc_ctrl_driver = {
 309        .driver = {
 310                .name   = "fsl-ifc",
 311                .of_match_table = fsl_ifc_match,
 312        },
 313        .probe       = fsl_ifc_ctrl_probe,
 314        .remove      = fsl_ifc_ctrl_remove,
 315};
 316
 317static int __init fsl_ifc_init(void)
 318{
 319        return platform_driver_register(&fsl_ifc_ctrl_driver);
 320}
 321subsys_initcall(fsl_ifc_init);
 322
 323MODULE_LICENSE("GPL");
 324MODULE_AUTHOR("Freescale Semiconductor");
 325MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");
 326