cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fsl_ifc.c (8680B)


      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	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	return 0;
    103}
    104
    105/*
    106 * NAND events are split between an operational interrupt which only
    107 * receives OPC, and an error interrupt that receives everything else,
    108 * including non-NAND errors.  Whichever interrupt gets to it first
    109 * records the status and wakes the wait queue.
    110 */
    111static DEFINE_SPINLOCK(nand_irq_lock);
    112
    113static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl)
    114{
    115	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
    116	unsigned long flags;
    117	u32 stat;
    118
    119	spin_lock_irqsave(&nand_irq_lock, flags);
    120
    121	stat = ifc_in32(&ifc->ifc_nand.nand_evter_stat);
    122	if (stat) {
    123		ifc_out32(stat, &ifc->ifc_nand.nand_evter_stat);
    124		ctrl->nand_stat = stat;
    125		wake_up(&ctrl->nand_wait);
    126	}
    127
    128	spin_unlock_irqrestore(&nand_irq_lock, flags);
    129
    130	return stat;
    131}
    132
    133static irqreturn_t fsl_ifc_nand_irq(int irqno, void *data)
    134{
    135	struct fsl_ifc_ctrl *ctrl = data;
    136
    137	if (check_nand_stat(ctrl))
    138		return IRQ_HANDLED;
    139
    140	return IRQ_NONE;
    141}
    142
    143/*
    144 * NOTE: This interrupt is used to report ifc events of various kinds,
    145 * such as transaction errors on the chipselects.
    146 */
    147static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
    148{
    149	struct fsl_ifc_ctrl *ctrl = data;
    150	struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
    151	u32 err_axiid, err_srcid, status, cs_err, err_addr;
    152	irqreturn_t ret = IRQ_NONE;
    153
    154	/* read for chip select error */
    155	cs_err = ifc_in32(&ifc->cm_evter_stat);
    156	if (cs_err) {
    157		dev_err(ctrl->dev, "transaction sent to IFC is not mapped to any memory bank 0x%08X\n",
    158			cs_err);
    159		/* clear the chip select error */
    160		ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);
    161
    162		/* read error attribute registers print the error information */
    163		status = ifc_in32(&ifc->cm_erattr0);
    164		err_addr = ifc_in32(&ifc->cm_erattr1);
    165
    166		if (status & IFC_CM_ERATTR0_ERTYP_READ)
    167			dev_err(ctrl->dev, "Read transaction error CM_ERATTR0 0x%08X\n",
    168				status);
    169		else
    170			dev_err(ctrl->dev, "Write transaction error CM_ERATTR0 0x%08X\n",
    171				status);
    172
    173		err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>
    174					IFC_CM_ERATTR0_ERAID_SHIFT;
    175		dev_err(ctrl->dev, "AXI ID of the error transaction 0x%08X\n",
    176			err_axiid);
    177
    178		err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>
    179					IFC_CM_ERATTR0_ESRCID_SHIFT;
    180		dev_err(ctrl->dev, "SRC ID of the error transaction 0x%08X\n",
    181			err_srcid);
    182
    183		dev_err(ctrl->dev, "Transaction Address corresponding to error ERADDR 0x%08X\n",
    184			err_addr);
    185
    186		ret = IRQ_HANDLED;
    187	}
    188
    189	if (check_nand_stat(ctrl))
    190		ret = IRQ_HANDLED;
    191
    192	return ret;
    193}
    194
    195/*
    196 * fsl_ifc_ctrl_probe
    197 *
    198 * called by device layer when it finds a device matching
    199 * one our driver can handled. This code allocates all of
    200 * the resources needed for the controller only.  The
    201 * resources for the NAND banks themselves are allocated
    202 * in the chip probe function.
    203 */
    204static int fsl_ifc_ctrl_probe(struct platform_device *dev)
    205{
    206	int ret = 0;
    207	int version, banks;
    208	void __iomem *addr;
    209
    210	dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
    211
    212	fsl_ifc_ctrl_dev = devm_kzalloc(&dev->dev, sizeof(*fsl_ifc_ctrl_dev),
    213					GFP_KERNEL);
    214	if (!fsl_ifc_ctrl_dev)
    215		return -ENOMEM;
    216
    217	dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
    218
    219	/* IOMAP the entire IFC region */
    220	fsl_ifc_ctrl_dev->gregs = of_iomap(dev->dev.of_node, 0);
    221	if (!fsl_ifc_ctrl_dev->gregs) {
    222		dev_err(&dev->dev, "failed to get memory region\n");
    223		return -ENODEV;
    224	}
    225
    226	if (of_property_read_bool(dev->dev.of_node, "little-endian")) {
    227		fsl_ifc_ctrl_dev->little_endian = true;
    228		dev_dbg(&dev->dev, "IFC REGISTERS are LITTLE endian\n");
    229	} else {
    230		fsl_ifc_ctrl_dev->little_endian = false;
    231		dev_dbg(&dev->dev, "IFC REGISTERS are BIG endian\n");
    232	}
    233
    234	version = ifc_in32(&fsl_ifc_ctrl_dev->gregs->ifc_rev) &
    235			FSL_IFC_VERSION_MASK;
    236
    237	banks = (version == FSL_IFC_VERSION_1_0_0) ? 4 : 8;
    238	dev_info(&dev->dev, "IFC version %d.%d, %d banks\n",
    239		version >> 24, (version >> 16) & 0xf, banks);
    240
    241	fsl_ifc_ctrl_dev->version = version;
    242	fsl_ifc_ctrl_dev->banks = banks;
    243
    244	addr = fsl_ifc_ctrl_dev->gregs;
    245	if (version >= FSL_IFC_VERSION_2_0_0)
    246		addr += PGOFFSET_64K;
    247	else
    248		addr += PGOFFSET_4K;
    249	fsl_ifc_ctrl_dev->rregs = addr;
    250
    251	/* get the Controller level irq */
    252	fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
    253	if (fsl_ifc_ctrl_dev->irq == 0) {
    254		dev_err(&dev->dev, "failed to get irq resource 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_unmap_nandirq;
    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_unmap_nandirq;
    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_free_irq;
    286		}
    287	}
    288
    289	/* legacy dts may still use "simple-bus" compatible */
    290	ret = of_platform_default_populate(dev->dev.of_node, NULL, &dev->dev);
    291	if (ret)
    292		goto err_free_nandirq;
    293
    294	return 0;
    295
    296err_free_nandirq:
    297	free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
    298err_free_irq:
    299	free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
    300err_unmap_nandirq:
    301	irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
    302	irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
    303err:
    304	iounmap(fsl_ifc_ctrl_dev->gregs);
    305	return ret;
    306}
    307
    308static const struct of_device_id fsl_ifc_match[] = {
    309	{
    310		.compatible = "fsl,ifc",
    311	},
    312	{},
    313};
    314
    315static struct platform_driver fsl_ifc_ctrl_driver = {
    316	.driver = {
    317		.name	= "fsl-ifc",
    318		.of_match_table = fsl_ifc_match,
    319	},
    320	.probe       = fsl_ifc_ctrl_probe,
    321	.remove      = fsl_ifc_ctrl_remove,
    322};
    323
    324static int __init fsl_ifc_init(void)
    325{
    326	return platform_driver_register(&fsl_ifc_ctrl_driver);
    327}
    328subsys_initcall(fsl_ifc_init);
    329
    330MODULE_LICENSE("GPL");
    331MODULE_AUTHOR("Freescale Semiconductor");
    332MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");