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

irq-clps711x.c (6118B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  CLPS711X IRQ driver
      4 *
      5 *  Copyright (C) 2013 Alexander Shiyan <shc_work@mail.ru>
      6 */
      7
      8#include <linux/io.h>
      9#include <linux/irq.h>
     10#include <linux/irqchip.h>
     11#include <linux/irqdomain.h>
     12#include <linux/of_address.h>
     13#include <linux/of_irq.h>
     14#include <linux/slab.h>
     15
     16#include <asm/exception.h>
     17#include <asm/mach/irq.h>
     18
     19#define CLPS711X_INTSR1	(0x0240)
     20#define CLPS711X_INTMR1	(0x0280)
     21#define CLPS711X_BLEOI	(0x0600)
     22#define CLPS711X_MCEOI	(0x0640)
     23#define CLPS711X_TEOI	(0x0680)
     24#define CLPS711X_TC1EOI	(0x06c0)
     25#define CLPS711X_TC2EOI	(0x0700)
     26#define CLPS711X_RTCEOI	(0x0740)
     27#define CLPS711X_UMSEOI	(0x0780)
     28#define CLPS711X_COEOI	(0x07c0)
     29#define CLPS711X_INTSR2	(0x1240)
     30#define CLPS711X_INTMR2	(0x1280)
     31#define CLPS711X_SRXEOF	(0x1600)
     32#define CLPS711X_KBDEOI	(0x1700)
     33#define CLPS711X_INTSR3	(0x2240)
     34#define CLPS711X_INTMR3	(0x2280)
     35
     36static const struct {
     37#define CLPS711X_FLAG_EN	(1 << 0)
     38#define CLPS711X_FLAG_FIQ	(1 << 1)
     39	unsigned int	flags;
     40	phys_addr_t	eoi;
     41} clps711x_irqs[] = {
     42	[1]	= { CLPS711X_FLAG_FIQ, CLPS711X_BLEOI, },
     43	[3]	= { CLPS711X_FLAG_FIQ, CLPS711X_MCEOI, },
     44	[4]	= { CLPS711X_FLAG_EN, CLPS711X_COEOI, },
     45	[5]	= { CLPS711X_FLAG_EN, },
     46	[6]	= { CLPS711X_FLAG_EN, },
     47	[7]	= { CLPS711X_FLAG_EN, },
     48	[8]	= { CLPS711X_FLAG_EN, CLPS711X_TC1EOI, },
     49	[9]	= { CLPS711X_FLAG_EN, CLPS711X_TC2EOI, },
     50	[10]	= { CLPS711X_FLAG_EN, CLPS711X_RTCEOI, },
     51	[11]	= { CLPS711X_FLAG_EN, CLPS711X_TEOI, },
     52	[12]	= { CLPS711X_FLAG_EN, },
     53	[13]	= { CLPS711X_FLAG_EN, },
     54	[14]	= { CLPS711X_FLAG_EN, CLPS711X_UMSEOI, },
     55	[15]	= { CLPS711X_FLAG_EN, CLPS711X_SRXEOF, },
     56	[16]	= { CLPS711X_FLAG_EN, CLPS711X_KBDEOI, },
     57	[17]	= { CLPS711X_FLAG_EN, },
     58	[18]	= { CLPS711X_FLAG_EN, },
     59	[28]	= { CLPS711X_FLAG_EN, },
     60	[29]	= { CLPS711X_FLAG_EN, },
     61	[32]	= { CLPS711X_FLAG_FIQ, },
     62};
     63
     64static struct {
     65	void __iomem		*base;
     66	void __iomem		*intmr[3];
     67	void __iomem		*intsr[3];
     68	struct irq_domain	*domain;
     69	struct irq_domain_ops	ops;
     70} *clps711x_intc;
     71
     72static asmlinkage void __exception_irq_entry clps711x_irqh(struct pt_regs *regs)
     73{
     74	u32 irqstat;
     75
     76	do {
     77		irqstat = readw_relaxed(clps711x_intc->intmr[0]) &
     78			  readw_relaxed(clps711x_intc->intsr[0]);
     79		if (irqstat)
     80			generic_handle_domain_irq(clps711x_intc->domain,
     81						  fls(irqstat) - 1);
     82
     83		irqstat = readw_relaxed(clps711x_intc->intmr[1]) &
     84			  readw_relaxed(clps711x_intc->intsr[1]);
     85		if (irqstat)
     86			generic_handle_domain_irq(clps711x_intc->domain,
     87						  fls(irqstat) - 1 + 16);
     88	} while (irqstat);
     89}
     90
     91static void clps711x_intc_eoi(struct irq_data *d)
     92{
     93	irq_hw_number_t hwirq = irqd_to_hwirq(d);
     94
     95	writel_relaxed(0, clps711x_intc->base + clps711x_irqs[hwirq].eoi);
     96}
     97
     98static void clps711x_intc_mask(struct irq_data *d)
     99{
    100	irq_hw_number_t hwirq = irqd_to_hwirq(d);
    101	void __iomem *intmr = clps711x_intc->intmr[hwirq / 16];
    102	u32 tmp;
    103
    104	tmp = readl_relaxed(intmr);
    105	tmp &= ~(1 << (hwirq % 16));
    106	writel_relaxed(tmp, intmr);
    107}
    108
    109static void clps711x_intc_unmask(struct irq_data *d)
    110{
    111	irq_hw_number_t hwirq = irqd_to_hwirq(d);
    112	void __iomem *intmr = clps711x_intc->intmr[hwirq / 16];
    113	u32 tmp;
    114
    115	tmp = readl_relaxed(intmr);
    116	tmp |= 1 << (hwirq % 16);
    117	writel_relaxed(tmp, intmr);
    118}
    119
    120static struct irq_chip clps711x_intc_chip = {
    121	.name		= "clps711x-intc",
    122	.irq_eoi	= clps711x_intc_eoi,
    123	.irq_mask	= clps711x_intc_mask,
    124	.irq_unmask	= clps711x_intc_unmask,
    125};
    126
    127static int __init clps711x_intc_irq_map(struct irq_domain *h, unsigned int virq,
    128					irq_hw_number_t hw)
    129{
    130	irq_flow_handler_t handler = handle_level_irq;
    131	unsigned int flags = 0;
    132
    133	if (!clps711x_irqs[hw].flags)
    134		return 0;
    135
    136	if (clps711x_irqs[hw].flags & CLPS711X_FLAG_FIQ) {
    137		handler = handle_bad_irq;
    138		flags |= IRQ_NOAUTOEN;
    139	} else if (clps711x_irqs[hw].eoi) {
    140		handler = handle_fasteoi_irq;
    141	}
    142
    143	/* Clear down pending interrupt */
    144	if (clps711x_irqs[hw].eoi)
    145		writel_relaxed(0, clps711x_intc->base + clps711x_irqs[hw].eoi);
    146
    147	irq_set_chip_and_handler(virq, &clps711x_intc_chip, handler);
    148	irq_modify_status(virq, IRQ_NOPROBE, flags);
    149
    150	return 0;
    151}
    152
    153static int __init _clps711x_intc_init(struct device_node *np,
    154				      phys_addr_t base, resource_size_t size)
    155{
    156	int err;
    157
    158	clps711x_intc = kzalloc(sizeof(*clps711x_intc), GFP_KERNEL);
    159	if (!clps711x_intc)
    160		return -ENOMEM;
    161
    162	clps711x_intc->base = ioremap(base, size);
    163	if (!clps711x_intc->base) {
    164		err = -ENOMEM;
    165		goto out_kfree;
    166	}
    167
    168	clps711x_intc->intsr[0] = clps711x_intc->base + CLPS711X_INTSR1;
    169	clps711x_intc->intmr[0] = clps711x_intc->base + CLPS711X_INTMR1;
    170	clps711x_intc->intsr[1] = clps711x_intc->base + CLPS711X_INTSR2;
    171	clps711x_intc->intmr[1] = clps711x_intc->base + CLPS711X_INTMR2;
    172	clps711x_intc->intsr[2] = clps711x_intc->base + CLPS711X_INTSR3;
    173	clps711x_intc->intmr[2] = clps711x_intc->base + CLPS711X_INTMR3;
    174
    175	/* Mask all interrupts */
    176	writel_relaxed(0, clps711x_intc->intmr[0]);
    177	writel_relaxed(0, clps711x_intc->intmr[1]);
    178	writel_relaxed(0, clps711x_intc->intmr[2]);
    179
    180	err = irq_alloc_descs(-1, 0, ARRAY_SIZE(clps711x_irqs), numa_node_id());
    181	if (err < 0)
    182		goto out_iounmap;
    183
    184	clps711x_intc->ops.map = clps711x_intc_irq_map;
    185	clps711x_intc->ops.xlate = irq_domain_xlate_onecell;
    186	clps711x_intc->domain =
    187		irq_domain_add_legacy(np, ARRAY_SIZE(clps711x_irqs),
    188				      0, 0, &clps711x_intc->ops, NULL);
    189	if (!clps711x_intc->domain) {
    190		err = -ENOMEM;
    191		goto out_irqfree;
    192	}
    193
    194	irq_set_default_host(clps711x_intc->domain);
    195	set_handle_irq(clps711x_irqh);
    196
    197#ifdef CONFIG_FIQ
    198	init_FIQ(0);
    199#endif
    200
    201	return 0;
    202
    203out_irqfree:
    204	irq_free_descs(0, ARRAY_SIZE(clps711x_irqs));
    205
    206out_iounmap:
    207	iounmap(clps711x_intc->base);
    208
    209out_kfree:
    210	kfree(clps711x_intc);
    211
    212	return err;
    213}
    214
    215void __init clps711x_intc_init(phys_addr_t base, resource_size_t size)
    216{
    217	BUG_ON(_clps711x_intc_init(NULL, base, size));
    218}
    219
    220#ifdef CONFIG_IRQCHIP
    221static int __init clps711x_intc_init_dt(struct device_node *np,
    222					struct device_node *parent)
    223{
    224	struct resource res;
    225	int err;
    226
    227	err = of_address_to_resource(np, 0, &res);
    228	if (err)
    229		return err;
    230
    231	return _clps711x_intc_init(np, res.start, resource_size(&res));
    232}
    233IRQCHIP_DECLARE(clps711x, "cirrus,ep7209-intc", clps711x_intc_init_dt);
    234#endif