root/drivers/memory/fsl_ifc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. convert_ifc_address
  2. fsl_ifc_find
  3. fsl_ifc_ctrl_init
  4. fsl_ifc_ctrl_remove
  5. check_nand_stat
  6. fsl_ifc_nand_irq
  7. fsl_ifc_ctrl_irq
  8. fsl_ifc_ctrl_probe
  9. fsl_ifc_init

   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 
  25 struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
  26 EXPORT_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  */
  32 unsigned int convert_ifc_address(phys_addr_t addr_base)
  33 {
  34         return addr_base & CSPR_BA;
  35 }
  36 EXPORT_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  */
  47 int 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                 if (cspr & CSPR_V && (cspr & CSPR_BA) ==
  57                                 convert_ifc_address(addr_base))
  58                         return i;
  59         }
  60 
  61         return -ENOENT;
  62 }
  63 EXPORT_SYMBOL(fsl_ifc_find);
  64 
  65 static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
  66 {
  67         struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
  68 
  69         /*
  70          * Clear all the common status and event registers
  71          */
  72         if (ifc_in32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER)
  73                 ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);
  74 
  75         /* enable all error and events */
  76         ifc_out32(IFC_CM_EVTER_EN_CSEREN, &ifc->cm_evter_en);
  77 
  78         /* enable all error and event interrupts */
  79         ifc_out32(IFC_CM_EVTER_INTR_EN_CSERIREN, &ifc->cm_evter_intr_en);
  80         ifc_out32(0x0, &ifc->cm_erattr0);
  81         ifc_out32(0x0, &ifc->cm_erattr1);
  82 
  83         return 0;
  84 }
  85 
  86 static int fsl_ifc_ctrl_remove(struct platform_device *dev)
  87 {
  88         struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
  89 
  90         free_irq(ctrl->nand_irq, ctrl);
  91         free_irq(ctrl->irq, ctrl);
  92 
  93         irq_dispose_mapping(ctrl->nand_irq);
  94         irq_dispose_mapping(ctrl->irq);
  95 
  96         iounmap(ctrl->gregs);
  97 
  98         dev_set_drvdata(&dev->dev, NULL);
  99         kfree(ctrl);
 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  */
 110 static DEFINE_SPINLOCK(nand_irq_lock);
 111 
 112 static 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 
 132 static 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  */
 146 static 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"
 157                                 "any memory bank 0x%08X\n", 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"
 167                                 "CM_ERATTR0 0x%08X\n", status);
 168                 else
 169                         dev_err(ctrl->dev, "Write transaction error"
 170                                 "CM_ERATTR0 0x%08X\n", 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"
 175                                         "transaction 0x%08X\n", 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"
 180                                         "transaction 0x%08X\n", err_srcid);
 181 
 182                 dev_err(ctrl->dev, "Transaction Address corresponding to error"
 183                                         "ERADDR 0x%08X\n", 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 */
 203 static 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 = kzalloc(sizeof(*fsl_ifc_ctrl_dev), GFP_KERNEL);
 212         if (!fsl_ifc_ctrl_dev)
 213                 return -ENOMEM;
 214 
 215         dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
 216 
 217         /* IOMAP the entire IFC region */
 218         fsl_ifc_ctrl_dev->gregs = of_iomap(dev->dev.of_node, 0);
 219         if (!fsl_ifc_ctrl_dev->gregs) {
 220                 dev_err(&dev->dev, "failed to get memory region\n");
 221                 ret = -ENODEV;
 222                 goto err;
 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 "
 254                                                         "for IFC\n");
 255                 ret = -ENODEV;
 256                 goto err;
 257         }
 258 
 259         /* get the nand machine irq */
 260         fsl_ifc_ctrl_dev->nand_irq =
 261                         irq_of_parse_and_map(dev->dev.of_node, 1);
 262 
 263         fsl_ifc_ctrl_dev->dev = &dev->dev;
 264 
 265         ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
 266         if (ret < 0)
 267                 goto err;
 268 
 269         init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
 270 
 271         ret = request_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_irq, IRQF_SHARED,
 272                           "fsl-ifc", fsl_ifc_ctrl_dev);
 273         if (ret != 0) {
 274                 dev_err(&dev->dev, "failed to install irq (%d)\n",
 275                         fsl_ifc_ctrl_dev->irq);
 276                 goto err_irq;
 277         }
 278 
 279         if (fsl_ifc_ctrl_dev->nand_irq) {
 280                 ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq,
 281                                 0, "fsl-ifc-nand", fsl_ifc_ctrl_dev);
 282                 if (ret != 0) {
 283                         dev_err(&dev->dev, "failed to install irq (%d)\n",
 284                                 fsl_ifc_ctrl_dev->nand_irq);
 285                         goto err_nandirq;
 286                 }
 287         }
 288 
 289         return 0;
 290 
 291 err_nandirq:
 292         free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
 293         irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
 294 err_irq:
 295         free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
 296         irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
 297 err:
 298         return ret;
 299 }
 300 
 301 static const struct of_device_id fsl_ifc_match[] = {
 302         {
 303                 .compatible = "fsl,ifc",
 304         },
 305         {},
 306 };
 307 
 308 static 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 
 317 static int __init fsl_ifc_init(void)
 318 {
 319         return platform_driver_register(&fsl_ifc_ctrl_driver);
 320 }
 321 subsys_initcall(fsl_ifc_init);
 322 
 323 MODULE_LICENSE("GPL");
 324 MODULE_AUTHOR("Freescale Semiconductor");
 325 MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");

/* [<][>][^][v][top][bottom][index][help] */