^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Actions Semi Owl SoCs SIRQ interrupt controller driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2014 Actions Semi Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * David Liu <liuwei@actions-semi.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Author: Parthiban Nallathambi <pn@denx.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Author: Saravanan Sekar <sravanhome@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Author: Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/bitfield.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/irqchip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/of_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <dt-bindings/interrupt-controller/arm-gic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define NUM_SIRQ 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define INTC_EXTCTL_PENDING BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define INTC_EXTCTL_CLK_SEL BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define INTC_EXTCTL_EN BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define INTC_EXTCTL_TYPE_MASK GENMASK(7, 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define INTC_EXTCTL_TYPE_HIGH 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define INTC_EXTCTL_TYPE_LOW BIT(6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define INTC_EXTCTL_TYPE_RISING BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define INTC_EXTCTL_TYPE_FALLING (BIT(6) | BIT(7))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /* S500 & S700 SIRQ control register masks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define INTC_EXTCTL_SIRQ0_MASK GENMASK(23, 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define INTC_EXTCTL_SIRQ1_MASK GENMASK(15, 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define INTC_EXTCTL_SIRQ2_MASK GENMASK(7, 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* S900 SIRQ control register offsets, relative to controller base address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define INTC_EXTCTL0 0x0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define INTC_EXTCTL1 0x0328
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define INTC_EXTCTL2 0x032c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct owl_sirq_params {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* INTC_EXTCTL reg shared for all three SIRQ lines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) bool reg_shared;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* INTC_EXTCTL reg offsets relative to controller base address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) u16 reg_offset[NUM_SIRQ];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct owl_sirq_chip_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) const struct owl_sirq_params *params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) raw_spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) u32 ext_irqs[NUM_SIRQ];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* S500 & S700 SoCs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static const struct owl_sirq_params owl_sirq_s500_params = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .reg_shared = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) .reg_offset = { 0, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* S900 SoC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static const struct owl_sirq_params owl_sirq_s900_params = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) .reg_shared = false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .reg_offset = { INTC_EXTCTL0, INTC_EXTCTL1, INTC_EXTCTL2 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static u32 owl_field_get(u32 val, u32 index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) switch (index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return FIELD_GET(INTC_EXTCTL_SIRQ0_MASK, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return FIELD_GET(INTC_EXTCTL_SIRQ1_MASK, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return FIELD_GET(INTC_EXTCTL_SIRQ2_MASK, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static u32 owl_field_prep(u32 val, u32 index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) switch (index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return FIELD_PREP(INTC_EXTCTL_SIRQ0_MASK, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return FIELD_PREP(INTC_EXTCTL_SIRQ1_MASK, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return FIELD_PREP(INTC_EXTCTL_SIRQ2_MASK, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static u32 owl_sirq_read_extctl(struct owl_sirq_chip_data *data, u32 index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) val = readl_relaxed(data->base + data->params->reg_offset[index]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (data->params->reg_shared)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) val = owl_field_get(val, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static void owl_sirq_write_extctl(struct owl_sirq_chip_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) u32 extctl, u32 index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (data->params->reg_shared) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) val = readl_relaxed(data->base + data->params->reg_offset[index]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) val &= ~owl_field_prep(0xff, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) extctl = owl_field_prep(extctl, index) | val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) writel_relaxed(extctl, data->base + data->params->reg_offset[index]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static void owl_sirq_clear_set_extctl(struct owl_sirq_chip_data *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) u32 clear, u32 set, u32 index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) raw_spin_lock_irqsave(&d->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) val = owl_sirq_read_extctl(d, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) val &= ~clear;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) val |= set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) owl_sirq_write_extctl(d, val, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) raw_spin_unlock_irqrestore(&d->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static void owl_sirq_eoi(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) struct owl_sirq_chip_data *chip_data = irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * Software must clear external interrupt pending, when interrupt type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * is edge triggered, so we need per SIRQ based clearing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (!irqd_is_level_type(data))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) owl_sirq_clear_set_extctl(chip_data, 0, INTC_EXTCTL_PENDING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) data->hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) irq_chip_eoi_parent(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static void owl_sirq_mask(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) struct owl_sirq_chip_data *chip_data = irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) owl_sirq_clear_set_extctl(chip_data, INTC_EXTCTL_EN, 0, data->hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) irq_chip_mask_parent(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) static void owl_sirq_unmask(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) struct owl_sirq_chip_data *chip_data = irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) owl_sirq_clear_set_extctl(chip_data, 0, INTC_EXTCTL_EN, data->hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) irq_chip_unmask_parent(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * GIC does not handle falling edge or active low, hence SIRQ shall be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * programmed to convert falling edge to rising edge signal and active
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * low to active high signal.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static int owl_sirq_set_type(struct irq_data *data, unsigned int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct owl_sirq_chip_data *chip_data = irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) u32 sirq_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) case IRQ_TYPE_LEVEL_LOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) sirq_type = INTC_EXTCTL_TYPE_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) type = IRQ_TYPE_LEVEL_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) case IRQ_TYPE_LEVEL_HIGH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) sirq_type = INTC_EXTCTL_TYPE_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) case IRQ_TYPE_EDGE_FALLING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) sirq_type = INTC_EXTCTL_TYPE_FALLING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) type = IRQ_TYPE_EDGE_RISING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) case IRQ_TYPE_EDGE_RISING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) sirq_type = INTC_EXTCTL_TYPE_RISING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) owl_sirq_clear_set_extctl(chip_data, INTC_EXTCTL_TYPE_MASK, sirq_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) data->hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return irq_chip_set_type_parent(data, type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static struct irq_chip owl_sirq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .name = "owl-sirq",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) .irq_mask = owl_sirq_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .irq_unmask = owl_sirq_unmask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) .irq_eoi = owl_sirq_eoi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) .irq_set_type = owl_sirq_set_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) .irq_retrigger = irq_chip_retrigger_hierarchy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) .irq_set_affinity = irq_chip_set_affinity_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) static int owl_sirq_domain_translate(struct irq_domain *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) struct irq_fwspec *fwspec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) unsigned long *hwirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) unsigned int *type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (!is_of_node(fwspec->fwnode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (fwspec->param_count != 2 || fwspec->param[0] >= NUM_SIRQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) *hwirq = fwspec->param[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) *type = fwspec->param[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static int owl_sirq_domain_alloc(struct irq_domain *domain, unsigned int virq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) unsigned int nr_irqs, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) struct owl_sirq_chip_data *chip_data = domain->host_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) struct irq_fwspec *fwspec = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) struct irq_fwspec parent_fwspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) irq_hw_number_t hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) unsigned int type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (WARN_ON(nr_irqs != 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) ret = owl_sirq_domain_translate(domain, fwspec, &hwirq, &type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) case IRQ_TYPE_EDGE_RISING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) case IRQ_TYPE_LEVEL_HIGH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) case IRQ_TYPE_EDGE_FALLING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) type = IRQ_TYPE_EDGE_RISING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) case IRQ_TYPE_LEVEL_LOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) type = IRQ_TYPE_LEVEL_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &owl_sirq_chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) chip_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) parent_fwspec.fwnode = domain->parent->fwnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) parent_fwspec.param_count = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) parent_fwspec.param[0] = GIC_SPI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) parent_fwspec.param[1] = chip_data->ext_irqs[hwirq];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) parent_fwspec.param[2] = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static const struct irq_domain_ops owl_sirq_domain_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) .translate = owl_sirq_domain_translate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) .alloc = owl_sirq_domain_alloc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .free = irq_domain_free_irqs_common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static int __init owl_sirq_init(const struct owl_sirq_params *params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) struct irq_domain *domain, *parent_domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) struct owl_sirq_chip_data *chip_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) parent_domain = irq_find_host(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (!parent_domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) pr_err("%pOF: failed to find sirq parent domain\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) chip_data = kzalloc(sizeof(*chip_data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (!chip_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) raw_spin_lock_init(&chip_data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) chip_data->params = params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) chip_data->base = of_iomap(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (!chip_data->base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) pr_err("%pOF: failed to map sirq registers\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) for (i = 0; i < NUM_SIRQ; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) struct of_phandle_args irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) ret = of_irq_parse_one(node, i, &irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) pr_err("%pOF: failed to parse interrupt %d\n", node, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) goto out_unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (WARN_ON(irq.args_count != 3)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) goto out_unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) chip_data->ext_irqs[i] = irq.args[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) /* Set 24MHz external interrupt clock freq */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) owl_sirq_clear_set_extctl(chip_data, 0, INTC_EXTCTL_CLK_SEL, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_SIRQ, node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) &owl_sirq_domain_ops, chip_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (!domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) pr_err("%pOF: failed to add domain\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) goto out_unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) out_unmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) iounmap(chip_data->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) out_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) kfree(chip_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static int __init owl_sirq_s500_of_init(struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) return owl_sirq_init(&owl_sirq_s500_params, node, parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) IRQCHIP_DECLARE(owl_sirq_s500, "actions,s500-sirq", owl_sirq_s500_of_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) IRQCHIP_DECLARE(owl_sirq_s700, "actions,s700-sirq", owl_sirq_s500_of_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) static int __init owl_sirq_s900_of_init(struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return owl_sirq_init(&owl_sirq_s900_params, node, parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) IRQCHIP_DECLARE(owl_sirq_s900, "actions,s900-sirq", owl_sirq_s900_of_init);