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-ftintc010.c (5494B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * irqchip for the Faraday Technology FTINTC010 Copyright (C) 2017 Linus
      4 * Walleij <linus.walleij@linaro.org>
      5 *
      6 * Based on arch/arm/mach-gemini/irq.c
      7 * Copyright (C) 2001-2006 Storlink, Corp.
      8 * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@gmail.com>
      9 */
     10#include <linux/bitops.h>
     11#include <linux/irq.h>
     12#include <linux/io.h>
     13#include <linux/irqchip.h>
     14#include <linux/irqdomain.h>
     15#include <linux/module.h>
     16#include <linux/of.h>
     17#include <linux/of_address.h>
     18#include <linux/of_irq.h>
     19#include <linux/cpu.h>
     20
     21#include <asm/exception.h>
     22#include <asm/mach/irq.h>
     23
     24#define FT010_NUM_IRQS 32
     25
     26#define FT010_IRQ_SOURCE(base_addr)	(base_addr + 0x00)
     27#define FT010_IRQ_MASK(base_addr)	(base_addr + 0x04)
     28#define FT010_IRQ_CLEAR(base_addr)	(base_addr + 0x08)
     29/* Selects level- or edge-triggered */
     30#define FT010_IRQ_MODE(base_addr)	(base_addr + 0x0C)
     31/* Selects active low/high or falling/rising edge */
     32#define FT010_IRQ_POLARITY(base_addr)	(base_addr + 0x10)
     33#define FT010_IRQ_STATUS(base_addr)	(base_addr + 0x14)
     34#define FT010_FIQ_SOURCE(base_addr)	(base_addr + 0x20)
     35#define FT010_FIQ_MASK(base_addr)	(base_addr + 0x24)
     36#define FT010_FIQ_CLEAR(base_addr)	(base_addr + 0x28)
     37#define FT010_FIQ_MODE(base_addr)	(base_addr + 0x2C)
     38#define FT010_FIQ_POLARITY(base_addr)	(base_addr + 0x30)
     39#define FT010_FIQ_STATUS(base_addr)	(base_addr + 0x34)
     40
     41/**
     42 * struct ft010_irq_data - irq data container for the Faraday IRQ controller
     43 * @base: memory offset in virtual memory
     44 * @chip: chip container for this instance
     45 * @domain: IRQ domain for this instance
     46 */
     47struct ft010_irq_data {
     48	void __iomem *base;
     49	struct irq_chip chip;
     50	struct irq_domain *domain;
     51};
     52
     53static void ft010_irq_mask(struct irq_data *d)
     54{
     55	struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
     56	unsigned int mask;
     57
     58	mask = readl(FT010_IRQ_MASK(f->base));
     59	mask &= ~BIT(irqd_to_hwirq(d));
     60	writel(mask, FT010_IRQ_MASK(f->base));
     61}
     62
     63static void ft010_irq_unmask(struct irq_data *d)
     64{
     65	struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
     66	unsigned int mask;
     67
     68	mask = readl(FT010_IRQ_MASK(f->base));
     69	mask |= BIT(irqd_to_hwirq(d));
     70	writel(mask, FT010_IRQ_MASK(f->base));
     71}
     72
     73static void ft010_irq_ack(struct irq_data *d)
     74{
     75	struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
     76
     77	writel(BIT(irqd_to_hwirq(d)), FT010_IRQ_CLEAR(f->base));
     78}
     79
     80static int ft010_irq_set_type(struct irq_data *d, unsigned int trigger)
     81{
     82	struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
     83	int offset = irqd_to_hwirq(d);
     84	u32 mode, polarity;
     85
     86	mode = readl(FT010_IRQ_MODE(f->base));
     87	polarity = readl(FT010_IRQ_POLARITY(f->base));
     88
     89	if (trigger & (IRQ_TYPE_LEVEL_LOW)) {
     90		irq_set_handler_locked(d, handle_level_irq);
     91		mode &= ~BIT(offset);
     92		polarity |= BIT(offset);
     93	} else if (trigger & (IRQ_TYPE_LEVEL_HIGH)) {
     94		irq_set_handler_locked(d, handle_level_irq);
     95		mode &= ~BIT(offset);
     96		polarity &= ~BIT(offset);
     97	} else if (trigger & IRQ_TYPE_EDGE_FALLING) {
     98		irq_set_handler_locked(d, handle_edge_irq);
     99		mode |= BIT(offset);
    100		polarity |= BIT(offset);
    101	} else if (trigger & IRQ_TYPE_EDGE_RISING) {
    102		irq_set_handler_locked(d, handle_edge_irq);
    103		mode |= BIT(offset);
    104		polarity &= ~BIT(offset);
    105	} else {
    106		irq_set_handler_locked(d, handle_bad_irq);
    107		pr_warn("Faraday IRQ: no supported trigger selected for line %d\n",
    108			offset);
    109	}
    110
    111	writel(mode, FT010_IRQ_MODE(f->base));
    112	writel(polarity, FT010_IRQ_POLARITY(f->base));
    113
    114	return 0;
    115}
    116
    117static struct irq_chip ft010_irq_chip = {
    118	.name		= "FTINTC010",
    119	.irq_ack	= ft010_irq_ack,
    120	.irq_mask	= ft010_irq_mask,
    121	.irq_unmask	= ft010_irq_unmask,
    122	.irq_set_type	= ft010_irq_set_type,
    123};
    124
    125/* Local static for the IRQ entry call */
    126static struct ft010_irq_data firq;
    127
    128asmlinkage void __exception_irq_entry ft010_irqchip_handle_irq(struct pt_regs *regs)
    129{
    130	struct ft010_irq_data *f = &firq;
    131	int irq;
    132	u32 status;
    133
    134	while ((status = readl(FT010_IRQ_STATUS(f->base)))) {
    135		irq = ffs(status) - 1;
    136		generic_handle_domain_irq(f->domain, irq);
    137	}
    138}
    139
    140static int ft010_irqdomain_map(struct irq_domain *d, unsigned int irq,
    141				irq_hw_number_t hwirq)
    142{
    143	struct ft010_irq_data *f = d->host_data;
    144
    145	irq_set_chip_data(irq, f);
    146	/* All IRQs should set up their type, flags as bad by default */
    147	irq_set_chip_and_handler(irq, &ft010_irq_chip, handle_bad_irq);
    148	irq_set_probe(irq);
    149
    150	return 0;
    151}
    152
    153static void ft010_irqdomain_unmap(struct irq_domain *d, unsigned int irq)
    154{
    155	irq_set_chip_and_handler(irq, NULL, NULL);
    156	irq_set_chip_data(irq, NULL);
    157}
    158
    159static const struct irq_domain_ops ft010_irqdomain_ops = {
    160	.map = ft010_irqdomain_map,
    161	.unmap = ft010_irqdomain_unmap,
    162	.xlate = irq_domain_xlate_onetwocell,
    163};
    164
    165int __init ft010_of_init_irq(struct device_node *node,
    166			      struct device_node *parent)
    167{
    168	struct ft010_irq_data *f = &firq;
    169
    170	/*
    171	 * Disable the idle handler by default since it is buggy
    172	 * For more info see arch/arm/mach-gemini/idle.c
    173	 */
    174	cpu_idle_poll_ctrl(true);
    175
    176	f->base = of_iomap(node, 0);
    177	WARN(!f->base, "unable to map gemini irq registers\n");
    178
    179	/* Disable all interrupts */
    180	writel(0, FT010_IRQ_MASK(f->base));
    181	writel(0, FT010_FIQ_MASK(f->base));
    182
    183	f->domain = irq_domain_add_simple(node, FT010_NUM_IRQS, 0,
    184					  &ft010_irqdomain_ops, f);
    185	set_handle_irq(ft010_irqchip_handle_irq);
    186
    187	return 0;
    188}
    189IRQCHIP_DECLARE(faraday, "faraday,ftintc010",
    190		ft010_of_init_irq);
    191IRQCHIP_DECLARE(gemini, "cortina,gemini-interrupt-controller",
    192		ft010_of_init_irq);
    193IRQCHIP_DECLARE(moxa, "moxa,moxart-ic",
    194		ft010_of_init_irq);