1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * StarFive JHB100 External Interrupt Controller driver 4 * 5 * Copyright (C) 2023 StarFive Technology Co., Ltd. 6 * 7 * Author: Changhuang Liang <changhuang.liang@starfivetech.com> 8 */ 9 10 #include <linux/bitops.h> 11 #include <linux/cleanup.h> 12 #include <linux/clk.h> 13 #include <linux/interrupt.h> 14 #include <linux/irq.h> 15 #include <linux/irqchip.h> 16 #include <linux/irqchip/chained_irq.h> 17 #include <linux/irqdomain.h> 18 #include <linux/of_irq.h> 19 #include <linux/platform_device.h> 20 #include <linux/reset.h> 21 #include <linux/spinlock.h> 22 23 #define STARFIVE_INTC_SRC_TYPE(n) (0x04 + ((n) * 0x20)) 24 #define STARFIVE_INTC_SRC_CLEAR(n) (0x10 + ((n) * 0x20)) 25 #define STARFIVE_INTC_SRC_MASK(n) (0x14 + ((n) * 0x20)) 26 #define STARFIVE_INTC_SRC_INT(n) (0x1c + ((n) * 0x20)) 27 28 #define STARFIVE_INTC_TRIGGER_MASK 0x3 29 #define STARFIVE_INTC_TRIGGER_HIGH 0 30 #define STARFIVE_INTC_TRIGGER_LOW 1 31 #define STARFIVE_INTC_TRIGGER_POSEDGE 2 32 #define STARFIVE_INTC_TRIGGER_NEGEDGE 3 33 34 #define STARFIVE_INTC_NUM 2 35 #define STARFIVE_INTC_SRC_IRQ_NUM 32 36 #define STARFIVE_INTC_TYPE_NUM 16 37 38 struct starfive_irq_chip { 39 void __iomem *base; 40 struct irq_domain *domain; 41 raw_spinlock_t lock; 42 }; 43 44 static void starfive_intc_mod(struct starfive_irq_chip *irqc, u32 reg, u32 mask, u32 data) 45 { 46 u32 value; 47 48 value = ioread32(irqc->base + reg) & ~mask; 49 data &= mask; 50 data |= value; 51 iowrite32(data, irqc->base + reg); 52 } 53 54 static void starfive_intc_bit_set(struct starfive_irq_chip *irqc, 55 u32 reg, u32 bit_mask) 56 { 57 u32 value; 58 59 value = ioread32(irqc->base + reg); 60 value |= bit_mask; 61 iowrite32(value, irqc->base + reg); 62 } 63 64 static void starfive_intc_bit_clear(struct starfive_irq_chip *irqc, 65 u32 reg, u32 bit_mask) 66 { 67 u32 value; 68 69 value = ioread32(irqc->base + reg); 70 value &= ~bit_mask; 71 iowrite32(value, irqc->base + reg); 72 } 73 74 static void starfive_intc_unmask(struct irq_data *d) 75 { 76 struct starfive_irq_chip *irqc = irq_data_get_irq_chip_data(d); 77 int i, bitpos; 78 79 i = d->hwirq / STARFIVE_INTC_SRC_IRQ_NUM; 80 bitpos = d->hwirq % STARFIVE_INTC_SRC_IRQ_NUM; 81 82 guard(raw_spinlock)(&irqc->lock); 83 starfive_intc_bit_clear(irqc, STARFIVE_INTC_SRC_MASK(i), BIT(bitpos)); 84 } 85 86 static void starfive_intc_mask(struct irq_data *d) 87 { 88 struct starfive_irq_chip *irqc = irq_data_get_irq_chip_data(d); 89 int i, bitpos; 90 91 i = d->hwirq / STARFIVE_INTC_SRC_IRQ_NUM; 92 bitpos = d->hwirq % STARFIVE_INTC_SRC_IRQ_NUM; 93 94 guard(raw_spinlock)(&irqc->lock); 95 starfive_intc_bit_set(irqc, STARFIVE_INTC_SRC_MASK(i), BIT(bitpos)); 96 } 97 98 static void starfive_intc_ack(struct irq_data *d) 99 { 100 /* for handle_edge_irq, nothing to do */ 101 } 102 103 static int starfive_intc_set_type(struct irq_data *d, unsigned int type) 104 { 105 struct starfive_irq_chip *irqc = irq_data_get_irq_chip_data(d); 106 u32 i, bitpos, ty_pos, ty_shift, trigger, typeval; 107 irq_flow_handler_t handler; 108 109 i = d->hwirq / STARFIVE_INTC_SRC_IRQ_NUM; 110 bitpos = d->hwirq % STARFIVE_INTC_SRC_IRQ_NUM; 111 ty_pos = bitpos / STARFIVE_INTC_TYPE_NUM; 112 ty_shift = (bitpos % STARFIVE_INTC_TYPE_NUM) * 2; 113 114 switch (type) { 115 case IRQF_TRIGGER_LOW: 116 trigger = STARFIVE_INTC_TRIGGER_LOW; 117 handler = handle_level_irq; 118 break; 119 case IRQF_TRIGGER_HIGH: 120 trigger = STARFIVE_INTC_TRIGGER_HIGH; 121 handler = handle_level_irq; 122 break; 123 case IRQF_TRIGGER_FALLING: 124 trigger = STARFIVE_INTC_TRIGGER_NEGEDGE; 125 handler = handle_edge_irq; 126 break; 127 case IRQF_TRIGGER_RISING: 128 trigger = STARFIVE_INTC_TRIGGER_POSEDGE; 129 handler = handle_edge_irq; 130 break; 131 default: 132 return -EINVAL; 133 } 134 135 irq_set_handler_locked(d, handler); 136 typeval = trigger << ty_shift; 137 138 guard(raw_spinlock)(&irqc->lock); 139 140 starfive_intc_mod(irqc, STARFIVE_INTC_SRC_TYPE(i) + 4 * ty_pos, 141 STARFIVE_INTC_TRIGGER_MASK << ty_shift, typeval); 142 143 /* Once the type is updated, clear interrupt can help to reset the type value */ 144 starfive_intc_bit_set(irqc, STARFIVE_INTC_SRC_CLEAR(i), BIT(bitpos)); 145 starfive_intc_bit_clear(irqc, STARFIVE_INTC_SRC_CLEAR(i), BIT(bitpos)); 146 147 return 0; 148 } 149 150 static struct irq_chip intc_dev = { 151 .name = "StarFive JHB100 INTC", 152 .irq_unmask = starfive_intc_unmask, 153 .irq_mask = starfive_intc_mask, 154 .irq_ack = starfive_intc_ack, 155 .irq_set_type = starfive_intc_set_type, 156 }; 157 158 static int starfive_intc_map(struct irq_domain *d, unsigned int irq, 159 irq_hw_number_t hwirq) 160 { 161 irq_domain_set_info(d, irq, hwirq, &intc_dev, d->host_data, 162 handle_level_irq, NULL, NULL); 163 164 return 0; 165 } 166 167 static const struct irq_domain_ops starfive_intc_domain_ops = { 168 .xlate = irq_domain_xlate_onecell, 169 .map = starfive_intc_map, 170 }; 171 172 static void starfive_intc_irq_handler(struct irq_desc *desc) 173 { 174 struct starfive_irq_chip *irqc = irq_data_get_irq_handler_data(&desc->irq_data); 175 struct irq_chip *chip = irq_desc_get_chip(desc); 176 unsigned long value; 177 int hwirq; 178 179 chained_irq_enter(chip, desc); 180 181 for (int i = 0; i < STARFIVE_INTC_NUM; i++) { 182 value = ioread32(irqc->base + STARFIVE_INTC_SRC_INT(i)); 183 while (value) { 184 hwirq = ffs(value) - 1; 185 186 generic_handle_domain_irq(irqc->domain, 187 hwirq + i * STARFIVE_INTC_SRC_IRQ_NUM); 188 189 starfive_intc_bit_set(irqc, STARFIVE_INTC_SRC_CLEAR(i), BIT(hwirq)); 190 starfive_intc_bit_clear(irqc, STARFIVE_INTC_SRC_CLEAR(i), BIT(hwirq)); 191 192 __clear_bit(hwirq, &value); 193 } 194 } 195 196 chained_irq_exit(chip, desc); 197 } 198 199 static int starfive_intc_probe(struct platform_device *pdev, struct device_node *parent) 200 { 201 struct device_node *intc = pdev->dev.of_node; 202 struct reset_control *rst; 203 struct clk *clk; 204 int parent_irq; 205 206 struct starfive_irq_chip *irqc __free(kfree) = kzalloc_obj(*irqc); 207 if (!irqc) 208 return -ENOMEM; 209 210 irqc->base = devm_platform_ioremap_resource(pdev, 0); 211 if (IS_ERR(irqc->base)) 212 return dev_err_probe(&pdev->dev, PTR_ERR(irqc->base), "unable to map registers\n"); 213 214 rst = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, NULL); 215 if (IS_ERR(rst)) 216 return dev_err_probe(&pdev->dev, PTR_ERR(rst), 217 "Unable to get and deassert reset control\n"); 218 219 clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); 220 if (IS_ERR(clk)) 221 return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Unable to get and enable clock\n"); 222 223 224 raw_spin_lock_init(&irqc->lock); 225 226 irqc->domain = irq_domain_create_linear(of_fwnode_handle(intc), 227 STARFIVE_INTC_SRC_IRQ_NUM * STARFIVE_INTC_NUM, 228 &starfive_intc_domain_ops, irqc); 229 if (!irqc->domain) 230 return dev_err_probe(&pdev->dev, -EINVAL, "Unable to create IRQ domain\n"); 231 232 parent_irq = of_irq_get(intc, 0); 233 if (parent_irq < 0) { 234 irq_domain_remove(irqc->domain); 235 return dev_err_probe(&pdev->dev, parent_irq, "Failed to get main IRQ\n"); 236 } 237 238 irq_set_chained_handler_and_data(parent_irq, starfive_intc_irq_handler, 239 irqc); 240 241 dev_info(&pdev->dev, "Interrupt controller register, nr_irqs %d\n", 242 STARFIVE_INTC_SRC_IRQ_NUM * STARFIVE_INTC_NUM); 243 244 retain_and_null_ptr(irqc); 245 return 0; 246 } 247 248 IRQCHIP_PLATFORM_DRIVER_BEGIN(starfive_intc) 249 IRQCHIP_MATCH("starfive,jhb100-intc", starfive_intc_probe) 250 IRQCHIP_PLATFORM_DRIVER_END(starfive_intc) 251 252 MODULE_DESCRIPTION("StarFive JHB100 External Interrupt Controller"); 253 MODULE_LICENSE("GPL"); 254 MODULE_AUTHOR("Changhuang Liang <changhuang.liang@starfivetech.com>"); 255