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-rda-intc.c (2601B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * RDA8810PL SoC irqchip driver
      4 *
      5 * Copyright RDA Microelectronics Company Limited
      6 * Copyright (c) 2017 Andreas Färber
      7 * Copyright (c) 2018 Manivannan Sadhasivam
      8 */
      9
     10#include <linux/init.h>
     11#include <linux/interrupt.h>
     12#include <linux/irq.h>
     13#include <linux/irqchip.h>
     14#include <linux/irqdomain.h>
     15#include <linux/of_address.h>
     16
     17#include <asm/exception.h>
     18
     19#define RDA_INTC_FINALSTATUS	0x00
     20#define RDA_INTC_MASK_SET	0x08
     21#define RDA_INTC_MASK_CLR	0x0c
     22
     23#define RDA_IRQ_MASK_ALL	0xFFFFFFFF
     24
     25#define RDA_NR_IRQS 32
     26
     27static void __iomem *rda_intc_base;
     28static struct irq_domain *rda_irq_domain;
     29
     30static void rda_intc_mask_irq(struct irq_data *d)
     31{
     32	writel_relaxed(BIT(d->hwirq), rda_intc_base + RDA_INTC_MASK_CLR);
     33}
     34
     35static void rda_intc_unmask_irq(struct irq_data *d)
     36{
     37	writel_relaxed(BIT(d->hwirq), rda_intc_base + RDA_INTC_MASK_SET);
     38}
     39
     40static int rda_intc_set_type(struct irq_data *data, unsigned int flow_type)
     41{
     42	/* Hardware supports only level triggered interrupts */
     43	if ((flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) == flow_type)
     44		return 0;
     45
     46	return -EINVAL;
     47}
     48
     49static void __exception_irq_entry rda_handle_irq(struct pt_regs *regs)
     50{
     51	u32 stat = readl_relaxed(rda_intc_base + RDA_INTC_FINALSTATUS);
     52	u32 hwirq;
     53
     54	while (stat) {
     55		hwirq = __fls(stat);
     56		generic_handle_domain_irq(rda_irq_domain, hwirq);
     57		stat &= ~BIT(hwirq);
     58	}
     59}
     60
     61static struct irq_chip rda_irq_chip = {
     62	.name		= "rda-intc",
     63	.irq_mask	= rda_intc_mask_irq,
     64	.irq_unmask	= rda_intc_unmask_irq,
     65	.irq_set_type	= rda_intc_set_type,
     66};
     67
     68static int rda_irq_map(struct irq_domain *d,
     69		       unsigned int virq, irq_hw_number_t hw)
     70{
     71	irq_set_status_flags(virq, IRQ_LEVEL);
     72	irq_set_chip_and_handler(virq, &rda_irq_chip, handle_level_irq);
     73	irq_set_chip_data(virq, d->host_data);
     74	irq_set_probe(virq);
     75
     76	return 0;
     77}
     78
     79static const struct irq_domain_ops rda_irq_domain_ops = {
     80	.map = rda_irq_map,
     81	.xlate = irq_domain_xlate_onecell,
     82};
     83
     84static int __init rda8810_intc_init(struct device_node *node,
     85				    struct device_node *parent)
     86{
     87	rda_intc_base = of_io_request_and_map(node, 0, "rda-intc");
     88	if (IS_ERR(rda_intc_base))
     89		return PTR_ERR(rda_intc_base);
     90
     91	/* Mask all interrupt sources */
     92	writel_relaxed(RDA_IRQ_MASK_ALL, rda_intc_base + RDA_INTC_MASK_CLR);
     93
     94	rda_irq_domain = irq_domain_create_linear(&node->fwnode, RDA_NR_IRQS,
     95						  &rda_irq_domain_ops,
     96						  rda_intc_base);
     97	if (!rda_irq_domain) {
     98		iounmap(rda_intc_base);
     99		return -ENOMEM;
    100	}
    101
    102	set_handle_irq(rda_handle_irq);
    103
    104	return 0;
    105}
    106
    107IRQCHIP_DECLARE(rda_intc, "rda,8810pl-intc", rda8810_intc_init);