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-vt8500.c (5967B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  arch/arm/mach-vt8500/irq.c
      4 *
      5 *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
      6 *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
      7 */
      8
      9/*
     10 * This file is copied and modified from the original irq.c provided by
     11 * Alexey Charkov. Minor changes have been made for Device Tree Support.
     12 */
     13
     14#include <linux/slab.h>
     15#include <linux/io.h>
     16#include <linux/irq.h>
     17#include <linux/irqchip.h>
     18#include <linux/irqdomain.h>
     19#include <linux/interrupt.h>
     20#include <linux/bitops.h>
     21
     22#include <linux/of.h>
     23#include <linux/of_irq.h>
     24#include <linux/of_address.h>
     25
     26#include <asm/irq.h>
     27#include <asm/exception.h>
     28#include <asm/mach/irq.h>
     29
     30#define VT8500_ICPC_IRQ		0x20
     31#define VT8500_ICPC_FIQ		0x24
     32#define VT8500_ICDC		0x40		/* Destination Control 64*u32 */
     33#define VT8500_ICIS		0x80		/* Interrupt status, 16*u32 */
     34
     35/* ICPC */
     36#define ICPC_MASK		0x3F
     37#define ICPC_ROTATE		BIT(6)
     38
     39/* IC_DCTR */
     40#define ICDC_IRQ		0x00
     41#define ICDC_FIQ		0x01
     42#define ICDC_DSS0		0x02
     43#define ICDC_DSS1		0x03
     44#define ICDC_DSS2		0x04
     45#define ICDC_DSS3		0x05
     46#define ICDC_DSS4		0x06
     47#define ICDC_DSS5		0x07
     48
     49#define VT8500_INT_DISABLE	0
     50#define VT8500_INT_ENABLE	BIT(3)
     51
     52#define VT8500_TRIGGER_HIGH	0
     53#define VT8500_TRIGGER_RISING	BIT(5)
     54#define VT8500_TRIGGER_FALLING	BIT(6)
     55#define VT8500_EDGE		( VT8500_TRIGGER_RISING \
     56				| VT8500_TRIGGER_FALLING)
     57
     58/* vt8500 has 1 intc, wm8505 and wm8650 have 2 */
     59#define VT8500_INTC_MAX		2
     60
     61struct vt8500_irq_data {
     62	void __iomem 		*base;		/* IO Memory base address */
     63	struct irq_domain	*domain;	/* Domain for this controller */
     64};
     65
     66/* Global variable for accessing io-mem addresses */
     67static struct vt8500_irq_data intc[VT8500_INTC_MAX];
     68static u32 active_cnt = 0;
     69
     70static void vt8500_irq_mask(struct irq_data *d)
     71{
     72	struct vt8500_irq_data *priv = d->domain->host_data;
     73	void __iomem *base = priv->base;
     74	void __iomem *stat_reg = base + VT8500_ICIS + (d->hwirq < 32 ? 0 : 4);
     75	u8 edge, dctr;
     76	u32 status;
     77
     78	edge = readb(base + VT8500_ICDC + d->hwirq) & VT8500_EDGE;
     79	if (edge) {
     80		status = readl(stat_reg);
     81
     82		status |= (1 << (d->hwirq & 0x1f));
     83		writel(status, stat_reg);
     84	} else {
     85		dctr = readb(base + VT8500_ICDC + d->hwirq);
     86		dctr &= ~VT8500_INT_ENABLE;
     87		writeb(dctr, base + VT8500_ICDC + d->hwirq);
     88	}
     89}
     90
     91static void vt8500_irq_unmask(struct irq_data *d)
     92{
     93	struct vt8500_irq_data *priv = d->domain->host_data;
     94	void __iomem *base = priv->base;
     95	u8 dctr;
     96
     97	dctr = readb(base + VT8500_ICDC + d->hwirq);
     98	dctr |= VT8500_INT_ENABLE;
     99	writeb(dctr, base + VT8500_ICDC + d->hwirq);
    100}
    101
    102static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type)
    103{
    104	struct vt8500_irq_data *priv = d->domain->host_data;
    105	void __iomem *base = priv->base;
    106	u8 dctr;
    107
    108	dctr = readb(base + VT8500_ICDC + d->hwirq);
    109	dctr &= ~VT8500_EDGE;
    110
    111	switch (flow_type) {
    112	case IRQF_TRIGGER_LOW:
    113		return -EINVAL;
    114	case IRQF_TRIGGER_HIGH:
    115		dctr |= VT8500_TRIGGER_HIGH;
    116		irq_set_handler_locked(d, handle_level_irq);
    117		break;
    118	case IRQF_TRIGGER_FALLING:
    119		dctr |= VT8500_TRIGGER_FALLING;
    120		irq_set_handler_locked(d, handle_edge_irq);
    121		break;
    122	case IRQF_TRIGGER_RISING:
    123		dctr |= VT8500_TRIGGER_RISING;
    124		irq_set_handler_locked(d, handle_edge_irq);
    125		break;
    126	}
    127	writeb(dctr, base + VT8500_ICDC + d->hwirq);
    128
    129	return 0;
    130}
    131
    132static struct irq_chip vt8500_irq_chip = {
    133	.name = "vt8500",
    134	.irq_ack = vt8500_irq_mask,
    135	.irq_mask = vt8500_irq_mask,
    136	.irq_unmask = vt8500_irq_unmask,
    137	.irq_set_type = vt8500_irq_set_type,
    138};
    139
    140static void __init vt8500_init_irq_hw(void __iomem *base)
    141{
    142	u32 i;
    143
    144	/* Enable rotating priority for IRQ */
    145	writel(ICPC_ROTATE, base + VT8500_ICPC_IRQ);
    146	writel(0x00, base + VT8500_ICPC_FIQ);
    147
    148	/* Disable all interrupts and route them to IRQ */
    149	for (i = 0; i < 64; i++)
    150		writeb(VT8500_INT_DISABLE | ICDC_IRQ, base + VT8500_ICDC + i);
    151}
    152
    153static int vt8500_irq_map(struct irq_domain *h, unsigned int virq,
    154							irq_hw_number_t hw)
    155{
    156	irq_set_chip_and_handler(virq, &vt8500_irq_chip, handle_level_irq);
    157
    158	return 0;
    159}
    160
    161static const struct irq_domain_ops vt8500_irq_domain_ops = {
    162	.map = vt8500_irq_map,
    163	.xlate = irq_domain_xlate_onecell,
    164};
    165
    166static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
    167{
    168	u32 stat, i;
    169	int irqnr;
    170	void __iomem *base;
    171
    172	/* Loop through each active controller */
    173	for (i=0; i<active_cnt; i++) {
    174		base = intc[i].base;
    175		irqnr = readl_relaxed(base) & 0x3F;
    176		/*
    177		  Highest Priority register default = 63, so check that this
    178		  is a real interrupt by checking the status register
    179		*/
    180		if (irqnr == 63) {
    181			stat = readl_relaxed(base + VT8500_ICIS + 4);
    182			if (!(stat & BIT(31)))
    183				continue;
    184		}
    185
    186		generic_handle_domain_irq(intc[i].domain, irqnr);
    187	}
    188}
    189
    190static int __init vt8500_irq_init(struct device_node *node,
    191				  struct device_node *parent)
    192{
    193	int irq, i;
    194	struct device_node *np = node;
    195
    196	if (active_cnt == VT8500_INTC_MAX) {
    197		pr_err("%s: Interrupt controllers > VT8500_INTC_MAX\n",
    198								__func__);
    199		goto out;
    200	}
    201
    202	intc[active_cnt].base = of_iomap(np, 0);
    203	intc[active_cnt].domain = irq_domain_add_linear(node, 64,
    204			&vt8500_irq_domain_ops,	&intc[active_cnt]);
    205
    206	if (!intc[active_cnt].base) {
    207		pr_err("%s: Unable to map IO memory\n", __func__);
    208		goto out;
    209	}
    210
    211	if (!intc[active_cnt].domain) {
    212		pr_err("%s: Unable to add irq domain!\n", __func__);
    213		goto out;
    214	}
    215
    216	set_handle_irq(vt8500_handle_irq);
    217
    218	vt8500_init_irq_hw(intc[active_cnt].base);
    219
    220	pr_info("vt8500-irq: Added interrupt controller\n");
    221
    222	active_cnt++;
    223
    224	/* check if this is a slaved controller */
    225	if (of_irq_count(np) != 0) {
    226		/* check that we have the correct number of interrupts */
    227		if (of_irq_count(np) != 8) {
    228			pr_err("%s: Incorrect IRQ map for slaved controller\n",
    229					__func__);
    230			return -EINVAL;
    231		}
    232
    233		for (i = 0; i < 8; i++) {
    234			irq = irq_of_parse_and_map(np, i);
    235			enable_irq(irq);
    236		}
    237
    238		pr_info("vt8500-irq: Enabled slave->parent interrupts\n");
    239	}
    240out:
    241	return 0;
    242}
    243
    244IRQCHIP_DECLARE(vt8500_irq, "via,vt8500-intc", vt8500_irq_init);