^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2014 Stefan Kristansson <stefan.kristiansson@saunalahti.fi>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/irqchip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/of_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /* OR1K PIC implementation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) struct or1k_pic_dev {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) struct irq_chip chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) irq_flow_handler_t handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * We're a couple of cycles faster than the generic implementations with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * these 'fast' versions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static void or1k_pic_mask(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static void or1k_pic_unmask(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->hwirq));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static void or1k_pic_ack(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) mtspr(SPR_PICSR, (1UL << data->hwirq));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static void or1k_pic_mask_ack(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) mtspr(SPR_PICSR, (1UL << data->hwirq));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * There are two oddities with the OR1200 PIC implementation:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * i) LEVEL-triggered interrupts are latched and need to be cleared
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * ii) the interrupt latch is cleared by writing a 0 to the bit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * as opposed to a 1 as mandated by the spec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static void or1k_pic_or1200_ack(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static void or1k_pic_or1200_mask_ack(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static struct or1k_pic_dev or1k_pic_level = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .name = "or1k-PIC-level",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) .irq_unmask = or1k_pic_unmask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) .irq_mask = or1k_pic_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) .irq_mask_ack = or1k_pic_mask_ack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) .handle = handle_level_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) .flags = IRQ_LEVEL | IRQ_NOPROBE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static struct or1k_pic_dev or1k_pic_edge = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) .chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .name = "or1k-PIC-edge",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .irq_unmask = or1k_pic_unmask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .irq_mask = or1k_pic_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) .irq_ack = or1k_pic_ack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .irq_mask_ack = or1k_pic_mask_ack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .handle = handle_edge_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) .flags = IRQ_LEVEL | IRQ_NOPROBE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static struct or1k_pic_dev or1k_pic_or1200 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) .name = "or1200-PIC",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) .irq_unmask = or1k_pic_unmask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) .irq_mask = or1k_pic_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) .irq_ack = or1k_pic_or1200_ack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) .irq_mask_ack = or1k_pic_or1200_mask_ack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .handle = handle_level_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .flags = IRQ_LEVEL | IRQ_NOPROBE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static struct irq_domain *root_domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static inline int pic_get_irq(int first)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) int hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) hwirq = ffs(mfspr(SPR_PICSR) >> first);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (!hwirq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return NO_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) hwirq = hwirq + first - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static void or1k_pic_handle_irq(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) handle_domain_irq(root_domain, irq, regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct or1k_pic_dev *pic = d->host_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) irq_set_chip_and_handler(irq, &pic->chip, pic->handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) irq_set_status_flags(irq, pic->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static const struct irq_domain_ops or1k_irq_domain_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) .xlate = irq_domain_xlate_onecell,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) .map = or1k_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^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) * This sets up the IRQ domain for the PIC built in to the OpenRISC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * 1000 CPU. This is the "root" domain as these are the interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * that directly trigger an exception in the CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static int __init or1k_pic_init(struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct or1k_pic_dev *pic)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /* Disable all interrupts until explicitly requested */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) mtspr(SPR_PICMR, (0UL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) root_domain = irq_domain_add_linear(node, 32, &or1k_irq_domain_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) pic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) set_handle_irq(or1k_pic_handle_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return 0;
^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 int __init or1k_pic_or1200_init(struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) return or1k_pic_init(node, &or1k_pic_or1200);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) IRQCHIP_DECLARE(or1k_pic_or1200, "opencores,or1200-pic", or1k_pic_or1200_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) IRQCHIP_DECLARE(or1k_pic, "opencores,or1k-pic", or1k_pic_or1200_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static int __init or1k_pic_level_init(struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return or1k_pic_init(node, &or1k_pic_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) IRQCHIP_DECLARE(or1k_pic_level, "opencores,or1k-pic-level",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) or1k_pic_level_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static int __init or1k_pic_edge_init(struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return or1k_pic_init(node, &or1k_pic_edge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) IRQCHIP_DECLARE(or1k_pic_edge, "opencores,or1k-pic-edge", or1k_pic_edge_init);