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

mpc5121_ads_cpld.c (4209B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
      4 *
      5 * Author: John Rigby, <jrigby@freescale.com>
      6 *
      7 * Description:
      8 * MPC5121ADS CPLD irq handling
      9 */
     10
     11#undef DEBUG
     12
     13#include <linux/kernel.h>
     14#include <linux/interrupt.h>
     15#include <linux/irq.h>
     16#include <linux/io.h>
     17#include <linux/of_address.h>
     18#include <linux/of_irq.h>
     19
     20static struct device_node *cpld_pic_node;
     21static struct irq_domain *cpld_pic_host;
     22
     23/*
     24 * Bits to ignore in the misc_status register
     25 * 0x10 touch screen pendown is hard routed to irq1
     26 * 0x02 pci status is read from pci status register
     27 */
     28#define MISC_IGNORE 0x12
     29
     30/*
     31 * Nothing to ignore in pci status register
     32 */
     33#define PCI_IGNORE 0x00
     34
     35struct cpld_pic {
     36	u8 pci_mask;
     37	u8 pci_status;
     38	u8 route;
     39	u8 misc_mask;
     40	u8 misc_status;
     41	u8 misc_control;
     42};
     43
     44static struct cpld_pic __iomem *cpld_regs;
     45
     46static void __iomem *
     47irq_to_pic_mask(unsigned int irq)
     48{
     49	return irq <= 7 ? &cpld_regs->pci_mask : &cpld_regs->misc_mask;
     50}
     51
     52static unsigned int
     53irq_to_pic_bit(unsigned int irq)
     54{
     55	return 1 << (irq & 0x7);
     56}
     57
     58static void
     59cpld_mask_irq(struct irq_data *d)
     60{
     61	unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);
     62	void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
     63
     64	out_8(pic_mask,
     65	      in_8(pic_mask) | irq_to_pic_bit(cpld_irq));
     66}
     67
     68static void
     69cpld_unmask_irq(struct irq_data *d)
     70{
     71	unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);
     72	void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
     73
     74	out_8(pic_mask,
     75	      in_8(pic_mask) & ~irq_to_pic_bit(cpld_irq));
     76}
     77
     78static struct irq_chip cpld_pic = {
     79	.name = "CPLD PIC",
     80	.irq_mask = cpld_mask_irq,
     81	.irq_ack = cpld_mask_irq,
     82	.irq_unmask = cpld_unmask_irq,
     83};
     84
     85static unsigned int
     86cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp,
     87			    u8 __iomem *maskp)
     88{
     89	u8 status = in_8(statusp);
     90	u8 mask = in_8(maskp);
     91
     92	/* ignore don't cares and masked irqs */
     93	status |= (ignore | mask);
     94
     95	if (status == 0xff)
     96		return ~0;
     97
     98	return ffz(status) + offset;
     99}
    100
    101static void cpld_pic_cascade(struct irq_desc *desc)
    102{
    103	unsigned int hwirq;
    104
    105	hwirq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status,
    106		&cpld_regs->pci_mask);
    107	if (hwirq != ~0) {
    108		generic_handle_domain_irq(cpld_pic_host, hwirq);
    109		return;
    110	}
    111
    112	hwirq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status,
    113		&cpld_regs->misc_mask);
    114	if (hwirq != ~0) {
    115		generic_handle_domain_irq(cpld_pic_host, hwirq);
    116		return;
    117	}
    118}
    119
    120static int
    121cpld_pic_host_match(struct irq_domain *h, struct device_node *node,
    122		    enum irq_domain_bus_token bus_token)
    123{
    124	return cpld_pic_node == node;
    125}
    126
    127static int
    128cpld_pic_host_map(struct irq_domain *h, unsigned int virq,
    129			     irq_hw_number_t hw)
    130{
    131	irq_set_status_flags(virq, IRQ_LEVEL);
    132	irq_set_chip_and_handler(virq, &cpld_pic, handle_level_irq);
    133	return 0;
    134}
    135
    136static const struct irq_domain_ops cpld_pic_host_ops = {
    137	.match = cpld_pic_host_match,
    138	.map = cpld_pic_host_map,
    139};
    140
    141void __init
    142mpc5121_ads_cpld_map(void)
    143{
    144	struct device_node *np = NULL;
    145
    146	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic");
    147	if (!np) {
    148		printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n");
    149		return;
    150	}
    151
    152	cpld_regs = of_iomap(np, 0);
    153	of_node_put(np);
    154}
    155
    156void __init
    157mpc5121_ads_cpld_pic_init(void)
    158{
    159	unsigned int cascade_irq;
    160	struct device_node *np = NULL;
    161
    162	pr_debug("cpld_ic_init\n");
    163
    164	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic");
    165	if (!np) {
    166		printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n");
    167		return;
    168	}
    169
    170	if (!cpld_regs)
    171		goto end;
    172
    173	cascade_irq = irq_of_parse_and_map(np, 0);
    174	if (!cascade_irq)
    175		goto end;
    176
    177	/*
    178	 * statically route touch screen pendown through 1
    179	 * and ignore it here
    180	 * route all others through our cascade irq
    181	 */
    182	out_8(&cpld_regs->route, 0xfd);
    183	out_8(&cpld_regs->pci_mask, 0xff);
    184	/* unmask pci ints in misc mask */
    185	out_8(&cpld_regs->misc_mask, ~(MISC_IGNORE));
    186
    187	cpld_pic_node = of_node_get(np);
    188
    189	cpld_pic_host = irq_domain_add_linear(np, 16, &cpld_pic_host_ops, NULL);
    190	if (!cpld_pic_host) {
    191		printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n");
    192		goto end;
    193	}
    194
    195	irq_set_chained_handler(cascade_irq, cpld_pic_cascade);
    196end:
    197	of_node_put(np);
    198}