brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · 15e919c Raw
330 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright 2011 Freescale Semiconductor, Inc4 *5 * Freescale Integrated Flash Controller6 *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_platform.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 address30 * @addr_base:	base address of the memory bank31 */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 bank40 * @addr_base:	base address of the memory bank41 *42 * This function walks IFC banks comparing "Base address" field of the CSPR43 * registers with the supplied addr_base argument. When bases match this44 * function returns bank number (starting with 0), otherwise it returns45 * 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 registers72	 */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 void fsl_ifc_ctrl_remove(struct platform_device *dev)88{89	struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);90 91	of_platform_depopulate(&dev->dev);92	free_irq(ctrl->nand_irq, ctrl);93	free_irq(ctrl->irq, ctrl);94 95	irq_dispose_mapping(ctrl->nand_irq);96	irq_dispose_mapping(ctrl->irq);97 98	iounmap(ctrl->gregs);99 100	dev_set_drvdata(&dev->dev, NULL);101}102 103/*104 * NAND events are split between an operational interrupt which only105 * receives OPC, and an error interrupt that receives everything else,106 * including non-NAND errors.  Whichever interrupt gets to it first107 * records the status and wakes the wait queue.108 */109static DEFINE_SPINLOCK(nand_irq_lock);110 111static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl)112{113	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;114	unsigned long flags;115	u32 stat;116 117	spin_lock_irqsave(&nand_irq_lock, flags);118 119	stat = ifc_in32(&ifc->ifc_nand.nand_evter_stat);120	if (stat) {121		ifc_out32(stat, &ifc->ifc_nand.nand_evter_stat);122		ctrl->nand_stat = stat;123		wake_up(&ctrl->nand_wait);124	}125 126	spin_unlock_irqrestore(&nand_irq_lock, flags);127 128	return stat;129}130 131static irqreturn_t fsl_ifc_nand_irq(int irqno, void *data)132{133	struct fsl_ifc_ctrl *ctrl = data;134 135	if (check_nand_stat(ctrl))136		return IRQ_HANDLED;137 138	return IRQ_NONE;139}140 141/*142 * NOTE: This interrupt is used to report ifc events of various kinds,143 * such as transaction errors on the chipselects.144 */145static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)146{147	struct fsl_ifc_ctrl *ctrl = data;148	struct fsl_ifc_global __iomem *ifc = ctrl->gregs;149	u32 err_axiid, err_srcid, status, cs_err, err_addr;150	irqreturn_t ret = IRQ_NONE;151 152	/* read for chip select error */153	cs_err = ifc_in32(&ifc->cm_evter_stat);154	if (cs_err) {155		dev_err(ctrl->dev, "transaction sent to IFC is not mapped to any memory bank 0x%08X\n",156			cs_err);157		/* clear the chip select error */158		ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);159 160		/* read error attribute registers print the error information */161		status = ifc_in32(&ifc->cm_erattr0);162		err_addr = ifc_in32(&ifc->cm_erattr1);163 164		if (status & IFC_CM_ERATTR0_ERTYP_READ)165			dev_err(ctrl->dev, "Read transaction error CM_ERATTR0 0x%08X\n",166				status);167		else168			dev_err(ctrl->dev, "Write transaction error CM_ERATTR0 0x%08X\n",169				status);170 171		err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>172					IFC_CM_ERATTR0_ERAID_SHIFT;173		dev_err(ctrl->dev, "AXI ID of the error transaction 0x%08X\n",174			err_axiid);175 176		err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>177					IFC_CM_ERATTR0_ESRCID_SHIFT;178		dev_err(ctrl->dev, "SRC ID of the error transaction 0x%08X\n",179			err_srcid);180 181		dev_err(ctrl->dev, "Transaction Address corresponding to error ERADDR 0x%08X\n",182			err_addr);183 184		ret = IRQ_HANDLED;185	}186 187	if (check_nand_stat(ctrl))188		ret = IRQ_HANDLED;189 190	return ret;191}192 193/*194 * fsl_ifc_ctrl_probe195 *196 * called by device layer when it finds a device matching197 * one our driver can handled. This code allocates all of198 * the resources needed for the controller only.  The199 * resources for the NAND banks themselves are allocated200 * in the chip probe function.201 */202static int fsl_ifc_ctrl_probe(struct platform_device *dev)203{204	int ret = 0;205	int version, banks;206	void __iomem *addr;207 208	dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");209 210	fsl_ifc_ctrl_dev = devm_kzalloc(&dev->dev, sizeof(*fsl_ifc_ctrl_dev),211					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		return -ENODEV;222	}223 224	if (of_property_read_bool(dev->dev.of_node, "little-endian")) {225		fsl_ifc_ctrl_dev->little_endian = true;226		dev_dbg(&dev->dev, "IFC REGISTERS are LITTLE endian\n");227	} else {228		fsl_ifc_ctrl_dev->little_endian = false;229		dev_dbg(&dev->dev, "IFC REGISTERS are BIG endian\n");230	}231 232	version = ifc_in32(&fsl_ifc_ctrl_dev->gregs->ifc_rev) &233			FSL_IFC_VERSION_MASK;234 235	banks = (version == FSL_IFC_VERSION_1_0_0) ? 4 : 8;236	dev_info(&dev->dev, "IFC version %d.%d, %d banks\n",237		version >> 24, (version >> 16) & 0xf, banks);238 239	fsl_ifc_ctrl_dev->version = version;240	fsl_ifc_ctrl_dev->banks = banks;241 242	addr = fsl_ifc_ctrl_dev->gregs;243	if (version >= FSL_IFC_VERSION_2_0_0)244		addr += PGOFFSET_64K;245	else246		addr += PGOFFSET_4K;247	fsl_ifc_ctrl_dev->rregs = addr;248 249	/* get the Controller level irq */250	fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);251	if (fsl_ifc_ctrl_dev->irq == 0) {252		dev_err(&dev->dev, "failed to get irq resource for IFC\n");253		ret = -ENODEV;254		goto err;255	}256 257	/* get the nand machine irq */258	fsl_ifc_ctrl_dev->nand_irq =259			irq_of_parse_and_map(dev->dev.of_node, 1);260 261	fsl_ifc_ctrl_dev->dev = &dev->dev;262 263	ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);264	if (ret < 0)265		goto err_unmap_nandirq;266 267	init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);268 269	ret = request_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_irq, IRQF_SHARED,270			  "fsl-ifc", fsl_ifc_ctrl_dev);271	if (ret != 0) {272		dev_err(&dev->dev, "failed to install irq (%d)\n",273			fsl_ifc_ctrl_dev->irq);274		goto err_unmap_nandirq;275	}276 277	if (fsl_ifc_ctrl_dev->nand_irq) {278		ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq,279				0, "fsl-ifc-nand", fsl_ifc_ctrl_dev);280		if (ret != 0) {281			dev_err(&dev->dev, "failed to install irq (%d)\n",282				fsl_ifc_ctrl_dev->nand_irq);283			goto err_free_irq;284		}285	}286 287	/* legacy dts may still use "simple-bus" compatible */288	ret = of_platform_default_populate(dev->dev.of_node, NULL, &dev->dev);289	if (ret)290		goto err_free_nandirq;291 292	return 0;293 294err_free_nandirq:295	free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);296err_free_irq:297	free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);298err_unmap_nandirq:299	irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);300	irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);301err:302	iounmap(fsl_ifc_ctrl_dev->gregs);303	return ret;304}305 306static const struct of_device_id fsl_ifc_match[] = {307	{308		.compatible = "fsl,ifc",309	},310	{},311};312 313static struct platform_driver fsl_ifc_ctrl_driver = {314	.driver = {315		.name	= "fsl-ifc",316		.of_match_table = fsl_ifc_match,317	},318	.probe       = fsl_ifc_ctrl_probe,319	.remove_new  = fsl_ifc_ctrl_remove,320};321 322static int __init fsl_ifc_init(void)323{324	return platform_driver_register(&fsl_ifc_ctrl_driver);325}326subsys_initcall(fsl_ifc_init);327 328MODULE_AUTHOR("Freescale Semiconductor");329MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");330