blob: 75a8c38df9394f3d80e3b2e40c53b565ba5b77b6 [file] [log] [blame]
Thomas Gleixner74ba9202019-05-20 09:19:02 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +05302/*
3 * Copyright 2011 Freescale Semiconductor, Inc
4 *
5 * Freescale Integrated Flash Controller
6 *
7 * Author: Dipen Dudhat <Dipen.Dudhat@freescale.com>
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +05308 */
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +05309#include <linux/module.h>
10#include <linux/kernel.h>
11#include <linux/compiler.h>
Lijun Panc4aa1932015-12-11 13:55:02 -060012#include <linux/sched.h>
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +053013#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>
Prabhakar Kushwahad2ae2e22014-01-17 11:15:16 +053020#include <linux/fsl_ifc.h>
Raghav Dogra8ea126b2016-07-01 21:32:30 +053021#include <linux/irqdomain.h>
22#include <linux/of_address.h>
23#include <linux/of_irq.h>
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +053024
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
Raghav Dogra7a654172016-02-17 16:54:18 +053051 if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->gregs)
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +053052 return -ENODEV;
53
Aaron Sierra09691662014-08-26 18:18:33 -050054 for (i = 0; i < fsl_ifc_ctrl_dev->banks; i++) {
Raghav Dogra7a654172016-02-17 16:54:18 +053055 u32 cspr = ifc_in32(&fsl_ifc_ctrl_dev->gregs->cspr_cs[i].cspr);
Krzysztof Kozlowskia269ff32020-07-24 09:40:35 +020056
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +053057 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
Greg Kroah-Hartmancad5cef2012-12-21 14:04:10 -080066static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +053067{
Raghav Dogra7a654172016-02-17 16:54:18 +053068 struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +053069
70 /*
71 * Clear all the common status and event registers
72 */
Jaiprakash Singhcf184dc2015-05-20 21:17:11 -050073 if (ifc_in32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER)
74 ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +053075
76 /* enable all error and events */
Jaiprakash Singhcf184dc2015-05-20 21:17:11 -050077 ifc_out32(IFC_CM_EVTER_EN_CSEREN, &ifc->cm_evter_en);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +053078
79 /* enable all error and event interrupts */
Jaiprakash Singhcf184dc2015-05-20 21:17:11 -050080 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);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +053083
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
Raghav Dogra7a654172016-02-17 16:54:18 +053097 iounmap(ctrl->gregs);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +053098
99 dev_set_drvdata(&dev->dev, NULL);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530100
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{
Raghav Dogra7a654172016-02-17 16:54:18 +0530114 struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530115 unsigned long flags;
116 u32 stat;
117
118 spin_lock_irqsave(&nand_irq_lock, flags);
119
Jaiprakash Singhcf184dc2015-05-20 21:17:11 -0500120 stat = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530121 if (stat) {
Jaiprakash Singhcf184dc2015-05-20 21:17:11 -0500122 ifc_out32(stat, &ifc->ifc_nand.nand_evter_stat);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530123 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;
Raghav Dogra7a654172016-02-17 16:54:18 +0530149 struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530150 u32 err_axiid, err_srcid, status, cs_err, err_addr;
151 irqreturn_t ret = IRQ_NONE;
152
153 /* read for chip select error */
Jaiprakash Singhcf184dc2015-05-20 21:17:11 -0500154 cs_err = ifc_in32(&ifc->cm_evter_stat);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530155 if (cs_err) {
Krzysztof Kozlowskia269ff32020-07-24 09:40:35 +0200156 dev_err(ctrl->dev, "transaction sent to IFC is not mapped to any memory bank 0x%08X\n",
157 cs_err);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530158 /* clear the chip select error */
Jaiprakash Singhcf184dc2015-05-20 21:17:11 -0500159 ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530160
161 /* read error attribute registers print the error information */
Jaiprakash Singhcf184dc2015-05-20 21:17:11 -0500162 status = ifc_in32(&ifc->cm_erattr0);
163 err_addr = ifc_in32(&ifc->cm_erattr1);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530164
165 if (status & IFC_CM_ERATTR0_ERTYP_READ)
Krzysztof Kozlowskia269ff32020-07-24 09:40:35 +0200166 dev_err(ctrl->dev, "Read transaction error CM_ERATTR0 0x%08X\n",
167 status);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530168 else
Krzysztof Kozlowskia269ff32020-07-24 09:40:35 +0200169 dev_err(ctrl->dev, "Write transaction error CM_ERATTR0 0x%08X\n",
170 status);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530171
172 err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>
173 IFC_CM_ERATTR0_ERAID_SHIFT;
Krzysztof Kozlowskia269ff32020-07-24 09:40:35 +0200174 dev_err(ctrl->dev, "AXI ID of the error transaction 0x%08X\n",
175 err_axiid);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530176
177 err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>
178 IFC_CM_ERATTR0_ESRCID_SHIFT;
Krzysztof Kozlowskia269ff32020-07-24 09:40:35 +0200179 dev_err(ctrl->dev, "SRC ID of the error transaction 0x%08X\n",
180 err_srcid);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530181
Krzysztof Kozlowskia269ff32020-07-24 09:40:35 +0200182 dev_err(ctrl->dev, "Transaction Address corresponding to error ERADDR 0x%08X\n",
183 err_addr);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530184
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.
Krzysztof Kozlowskia269ff32020-07-24 09:40:35 +0200202 */
Greg Kroah-Hartmancad5cef2012-12-21 14:04:10 -0800203static int fsl_ifc_ctrl_probe(struct platform_device *dev)
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530204{
205 int ret = 0;
Aaron Sierra09691662014-08-26 18:18:33 -0500206 int version, banks;
Raghav Dogra7a654172016-02-17 16:54:18 +0530207 void __iomem *addr;
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530208
209 dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
210
Krzysztof Kozlowski8e0d09b2021-05-27 11:43:22 -0400211 fsl_ifc_ctrl_dev = devm_kzalloc(&dev->dev, sizeof(*fsl_ifc_ctrl_dev),
212 GFP_KERNEL);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530213 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 */
Raghav Dogra7a654172016-02-17 16:54:18 +0530219 fsl_ifc_ctrl_dev->gregs = of_iomap(dev->dev.of_node, 0);
220 if (!fsl_ifc_ctrl_dev->gregs) {
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530221 dev_err(&dev->dev, "failed to get memory region\n");
Krzysztof Kozlowski3b132ab2021-05-27 11:43:21 -0400222 return -ENODEV;
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530223 }
224
Jaiprakash Singhcf184dc2015-05-20 21:17:11 -0500225 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
Raghav Dogra7a654172016-02-17 16:54:18 +0530233 version = ifc_in32(&fsl_ifc_ctrl_dev->gregs->ifc_rev) &
Aaron Sierra09691662014-08-26 18:18:33 -0500234 FSL_IFC_VERSION_MASK;
Raghav Dogra7a654172016-02-17 16:54:18 +0530235
Aaron Sierra09691662014-08-26 18:18:33 -0500236 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
Raghav Dogra7a654172016-02-17 16:54:18 +0530243 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
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530250 /* get the Controller level irq */
251 fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
Raghav Dograed4eeba2015-12-16 16:11:31 +0530252 if (fsl_ifc_ctrl_dev->irq == 0) {
Krzysztof Kozlowskia269ff32020-07-24 09:40:35 +0200253 dev_err(&dev->dev, "failed to get irq resource for IFC\n");
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530254 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);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530261
262 fsl_ifc_ctrl_dev->dev = &dev->dev;
263
264 ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
265 if (ret < 0)
Dongliang Mu4ed2f352021-09-25 23:14:32 +0800266 goto err_unmap_nandirq;
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530267
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);
Dongliang Mu4ed2f352021-09-25 23:14:32 +0800275 goto err_unmap_nandirq;
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530276 }
277
Prabhakar Kushwaha721c0702012-09-13 13:34:11 +0530278 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);
Dongliang Mu4ed2f352021-09-25 23:14:32 +0800284 goto err_free_irq;
Prabhakar Kushwaha721c0702012-09-13 13:34:11 +0530285 }
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530286 }
287
288 return 0;
289
Dongliang Mu4ed2f352021-09-25 23:14:32 +0800290err_free_irq:
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530291 free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
Dongliang Mu4ed2f352021-09-25 23:14:32 +0800292err_unmap_nandirq:
293 irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530294 irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
295err:
Krzysztof Kozlowski3b132ab2021-05-27 11:43:21 -0400296 iounmap(fsl_ifc_ctrl_dev->gregs);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530297 return ret;
298}
299
300static const struct of_device_id fsl_ifc_match[] = {
301 {
302 .compatible = "fsl,ifc",
303 },
304 {},
305};
306
307static struct platform_driver fsl_ifc_ctrl_driver = {
308 .driver = {
309 .name = "fsl-ifc",
310 .of_match_table = fsl_ifc_match,
311 },
312 .probe = fsl_ifc_ctrl_probe,
313 .remove = fsl_ifc_ctrl_remove,
314};
315
Prabhakar Kushwahad2ae2e22014-01-17 11:15:16 +0530316static int __init fsl_ifc_init(void)
317{
318 return platform_driver_register(&fsl_ifc_ctrl_driver);
319}
320subsys_initcall(fsl_ifc_init);
Prabhakar Kushwahaa20cbdef2011-12-27 17:39:13 +0530321
322MODULE_LICENSE("GPL");
323MODULE_AUTHOR("Freescale Semiconductor");
324MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");