0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/kernel.h>
0011 #include <linux/compiler.h>
0012 #include <linux/sched.h>
0013 #include <linux/spinlock.h>
0014 #include <linux/types.h>
0015 #include <linux/slab.h>
0016 #include <linux/io.h>
0017 #include <linux/of.h>
0018 #include <linux/of_device.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/fsl_ifc.h>
0021 #include <linux/irqdomain.h>
0022 #include <linux/of_address.h>
0023 #include <linux/of_irq.h>
0024
0025 struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
0026 EXPORT_SYMBOL(fsl_ifc_ctrl_dev);
0027
0028
0029
0030
0031
0032 unsigned int convert_ifc_address(phys_addr_t addr_base)
0033 {
0034 return addr_base & CSPR_BA;
0035 }
0036 EXPORT_SYMBOL(convert_ifc_address);
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 int fsl_ifc_find(phys_addr_t addr_base)
0048 {
0049 int i = 0;
0050
0051 if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->gregs)
0052 return -ENODEV;
0053
0054 for (i = 0; i < fsl_ifc_ctrl_dev->banks; i++) {
0055 u32 cspr = ifc_in32(&fsl_ifc_ctrl_dev->gregs->cspr_cs[i].cspr);
0056
0057 if (cspr & CSPR_V && (cspr & CSPR_BA) ==
0058 convert_ifc_address(addr_base))
0059 return i;
0060 }
0061
0062 return -ENOENT;
0063 }
0064 EXPORT_SYMBOL(fsl_ifc_find);
0065
0066 static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
0067 {
0068 struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
0069
0070
0071
0072
0073 if (ifc_in32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER)
0074 ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);
0075
0076
0077 ifc_out32(IFC_CM_EVTER_EN_CSEREN, &ifc->cm_evter_en);
0078
0079
0080 ifc_out32(IFC_CM_EVTER_INTR_EN_CSERIREN, &ifc->cm_evter_intr_en);
0081 ifc_out32(0x0, &ifc->cm_erattr0);
0082 ifc_out32(0x0, &ifc->cm_erattr1);
0083
0084 return 0;
0085 }
0086
0087 static int fsl_ifc_ctrl_remove(struct platform_device *dev)
0088 {
0089 struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
0090
0091 of_platform_depopulate(&dev->dev);
0092 free_irq(ctrl->nand_irq, ctrl);
0093 free_irq(ctrl->irq, ctrl);
0094
0095 irq_dispose_mapping(ctrl->nand_irq);
0096 irq_dispose_mapping(ctrl->irq);
0097
0098 iounmap(ctrl->gregs);
0099
0100 dev_set_drvdata(&dev->dev, NULL);
0101
0102 return 0;
0103 }
0104
0105
0106
0107
0108
0109
0110
0111 static DEFINE_SPINLOCK(nand_irq_lock);
0112
0113 static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl)
0114 {
0115 struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
0116 unsigned long flags;
0117 u32 stat;
0118
0119 spin_lock_irqsave(&nand_irq_lock, flags);
0120
0121 stat = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
0122 if (stat) {
0123 ifc_out32(stat, &ifc->ifc_nand.nand_evter_stat);
0124 ctrl->nand_stat = stat;
0125 wake_up(&ctrl->nand_wait);
0126 }
0127
0128 spin_unlock_irqrestore(&nand_irq_lock, flags);
0129
0130 return stat;
0131 }
0132
0133 static irqreturn_t fsl_ifc_nand_irq(int irqno, void *data)
0134 {
0135 struct fsl_ifc_ctrl *ctrl = data;
0136
0137 if (check_nand_stat(ctrl))
0138 return IRQ_HANDLED;
0139
0140 return IRQ_NONE;
0141 }
0142
0143
0144
0145
0146
0147 static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
0148 {
0149 struct fsl_ifc_ctrl *ctrl = data;
0150 struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
0151 u32 err_axiid, err_srcid, status, cs_err, err_addr;
0152 irqreturn_t ret = IRQ_NONE;
0153
0154
0155 cs_err = ifc_in32(&ifc->cm_evter_stat);
0156 if (cs_err) {
0157 dev_err(ctrl->dev, "transaction sent to IFC is not mapped to any memory bank 0x%08X\n",
0158 cs_err);
0159
0160 ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);
0161
0162
0163 status = ifc_in32(&ifc->cm_erattr0);
0164 err_addr = ifc_in32(&ifc->cm_erattr1);
0165
0166 if (status & IFC_CM_ERATTR0_ERTYP_READ)
0167 dev_err(ctrl->dev, "Read transaction error CM_ERATTR0 0x%08X\n",
0168 status);
0169 else
0170 dev_err(ctrl->dev, "Write transaction error CM_ERATTR0 0x%08X\n",
0171 status);
0172
0173 err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>
0174 IFC_CM_ERATTR0_ERAID_SHIFT;
0175 dev_err(ctrl->dev, "AXI ID of the error transaction 0x%08X\n",
0176 err_axiid);
0177
0178 err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>
0179 IFC_CM_ERATTR0_ESRCID_SHIFT;
0180 dev_err(ctrl->dev, "SRC ID of the error transaction 0x%08X\n",
0181 err_srcid);
0182
0183 dev_err(ctrl->dev, "Transaction Address corresponding to error ERADDR 0x%08X\n",
0184 err_addr);
0185
0186 ret = IRQ_HANDLED;
0187 }
0188
0189 if (check_nand_stat(ctrl))
0190 ret = IRQ_HANDLED;
0191
0192 return ret;
0193 }
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204 static int fsl_ifc_ctrl_probe(struct platform_device *dev)
0205 {
0206 int ret = 0;
0207 int version, banks;
0208 void __iomem *addr;
0209
0210 dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
0211
0212 fsl_ifc_ctrl_dev = devm_kzalloc(&dev->dev, sizeof(*fsl_ifc_ctrl_dev),
0213 GFP_KERNEL);
0214 if (!fsl_ifc_ctrl_dev)
0215 return -ENOMEM;
0216
0217 dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
0218
0219
0220 fsl_ifc_ctrl_dev->gregs = of_iomap(dev->dev.of_node, 0);
0221 if (!fsl_ifc_ctrl_dev->gregs) {
0222 dev_err(&dev->dev, "failed to get memory region\n");
0223 return -ENODEV;
0224 }
0225
0226 if (of_property_read_bool(dev->dev.of_node, "little-endian")) {
0227 fsl_ifc_ctrl_dev->little_endian = true;
0228 dev_dbg(&dev->dev, "IFC REGISTERS are LITTLE endian\n");
0229 } else {
0230 fsl_ifc_ctrl_dev->little_endian = false;
0231 dev_dbg(&dev->dev, "IFC REGISTERS are BIG endian\n");
0232 }
0233
0234 version = ifc_in32(&fsl_ifc_ctrl_dev->gregs->ifc_rev) &
0235 FSL_IFC_VERSION_MASK;
0236
0237 banks = (version == FSL_IFC_VERSION_1_0_0) ? 4 : 8;
0238 dev_info(&dev->dev, "IFC version %d.%d, %d banks\n",
0239 version >> 24, (version >> 16) & 0xf, banks);
0240
0241 fsl_ifc_ctrl_dev->version = version;
0242 fsl_ifc_ctrl_dev->banks = banks;
0243
0244 addr = fsl_ifc_ctrl_dev->gregs;
0245 if (version >= FSL_IFC_VERSION_2_0_0)
0246 addr += PGOFFSET_64K;
0247 else
0248 addr += PGOFFSET_4K;
0249 fsl_ifc_ctrl_dev->rregs = addr;
0250
0251
0252 fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
0253 if (fsl_ifc_ctrl_dev->irq == 0) {
0254 dev_err(&dev->dev, "failed to get irq resource for IFC\n");
0255 ret = -ENODEV;
0256 goto err;
0257 }
0258
0259
0260 fsl_ifc_ctrl_dev->nand_irq =
0261 irq_of_parse_and_map(dev->dev.of_node, 1);
0262
0263 fsl_ifc_ctrl_dev->dev = &dev->dev;
0264
0265 ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
0266 if (ret < 0)
0267 goto err_unmap_nandirq;
0268
0269 init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
0270
0271 ret = request_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_irq, IRQF_SHARED,
0272 "fsl-ifc", fsl_ifc_ctrl_dev);
0273 if (ret != 0) {
0274 dev_err(&dev->dev, "failed to install irq (%d)\n",
0275 fsl_ifc_ctrl_dev->irq);
0276 goto err_unmap_nandirq;
0277 }
0278
0279 if (fsl_ifc_ctrl_dev->nand_irq) {
0280 ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq,
0281 0, "fsl-ifc-nand", fsl_ifc_ctrl_dev);
0282 if (ret != 0) {
0283 dev_err(&dev->dev, "failed to install irq (%d)\n",
0284 fsl_ifc_ctrl_dev->nand_irq);
0285 goto err_free_irq;
0286 }
0287 }
0288
0289
0290 ret = of_platform_default_populate(dev->dev.of_node, NULL, &dev->dev);
0291 if (ret)
0292 goto err_free_nandirq;
0293
0294 return 0;
0295
0296 err_free_nandirq:
0297 free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
0298 err_free_irq:
0299 free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
0300 err_unmap_nandirq:
0301 irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
0302 irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
0303 err:
0304 iounmap(fsl_ifc_ctrl_dev->gregs);
0305 return ret;
0306 }
0307
0308 static const struct of_device_id fsl_ifc_match[] = {
0309 {
0310 .compatible = "fsl,ifc",
0311 },
0312 {},
0313 };
0314
0315 static struct platform_driver fsl_ifc_ctrl_driver = {
0316 .driver = {
0317 .name = "fsl-ifc",
0318 .of_match_table = fsl_ifc_match,
0319 },
0320 .probe = fsl_ifc_ctrl_probe,
0321 .remove = fsl_ifc_ctrl_remove,
0322 };
0323
0324 static int __init fsl_ifc_init(void)
0325 {
0326 return platform_driver_register(&fsl_ifc_ctrl_driver);
0327 }
0328 subsys_initcall(fsl_ifc_init);
0329
0330 MODULE_LICENSE("GPL");
0331 MODULE_AUTHOR("Freescale Semiconductor");
0332 MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");