| /* |
| * Copyright (c) 2019-2020 Cobham Gaisler AB |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /* |
| * This is a driver for the GRLIB IRQMP interrupt controller common in LEON |
| * systems. |
| * |
| * Interrupt level 1..15 are SPARC interrupts. Interrupt level 16..31, if |
| * implemented in the interrupt controller, are IRQMP "extended interrupts". |
| * |
| * For more information about IRQMP, see the GRLIB IP Core User's Manual. |
| */ |
| |
| #define DT_DRV_COMPAT gaisler_irqmp |
| |
| #include <zephyr/kernel.h> |
| #include <zephyr/device.h> |
| |
| /* |
| * Register description for IRQMP and IRQAMP interrupt controllers |
| * IRQMP - Multiprocessor Interrupt Controller |
| * IRQ(A)MP - Multiprocessor Interrupt Controller with extended ASMP support |
| */ |
| #define IRQMP_NCPU_MAX 16 |
| struct irqmp_regs { |
| uint32_t ilevel; /* 0x00 */ |
| uint32_t ipend; /* 0x04 */ |
| uint32_t iforce0; /* 0x08 */ |
| uint32_t iclear; /* 0x0c */ |
| uint32_t mpstat; /* 0x10 */ |
| uint32_t brdlst; /* 0x14 */ |
| uint32_t errstat; /* 0x18 */ |
| uint32_t wdogctrl; /* 0x1c */ |
| uint32_t asmpctrl; /* 0x20 */ |
| uint32_t icselr[2]; /* 0x24 */ |
| uint32_t reserved2c; /* 0x2c */ |
| uint32_t reserved30; /* 0x30 */ |
| uint32_t reserved34; /* 0x34 */ |
| uint32_t reserved38; /* 0x38 */ |
| uint32_t reserved3c; /* 0x3c */ |
| uint32_t pimask[IRQMP_NCPU_MAX]; /* 0x40 */ |
| uint32_t piforce[IRQMP_NCPU_MAX]; /* 0x80 */ |
| uint32_t pextack[IRQMP_NCPU_MAX]; /* 0xc0 */ |
| }; |
| |
| #define IRQMP_PEXTACK_EID (0x1f << 0) |
| |
| static volatile struct irqmp_regs *get_irqmp_regs(void) |
| { |
| return (struct irqmp_regs *) DT_INST_REG_ADDR(0); |
| } |
| |
| static int get_irqmp_eirq(void) |
| { |
| return DT_INST_PROP(0, eirq); |
| } |
| |
| void arch_irq_enable(unsigned int source) |
| { |
| volatile struct irqmp_regs *regs = get_irqmp_regs(); |
| volatile uint32_t *pimask = ®s->pimask[0]; |
| const uint32_t setbit = (1U << source); |
| unsigned int key; |
| |
| key = arch_irq_lock(); |
| *pimask |= setbit; |
| arch_irq_unlock(key); |
| } |
| |
| void arch_irq_disable(unsigned int source) |
| { |
| volatile struct irqmp_regs *regs = get_irqmp_regs(); |
| volatile uint32_t *pimask = ®s->pimask[0]; |
| const uint32_t keepbits = ~(1U << source); |
| unsigned int key; |
| |
| key = arch_irq_lock(); |
| *pimask &= keepbits; |
| arch_irq_unlock(key); |
| } |
| |
| int arch_irq_is_enabled(unsigned int source) |
| { |
| volatile struct irqmp_regs *regs = get_irqmp_regs(); |
| volatile uint32_t *pimask = ®s->pimask[0]; |
| |
| return !!(*pimask & (1U << source)); |
| } |
| |
| int z_sparc_int_get_source(int irl) |
| { |
| volatile struct irqmp_regs *regs = get_irqmp_regs(); |
| const int eirq = get_irqmp_eirq(); |
| int source; |
| |
| if ((eirq != 0) && (irl == eirq)) { |
| source = regs->pextack[0] & IRQMP_PEXTACK_EID; |
| if (source == 0) { |
| source = irl; |
| } |
| } else { |
| source = irl; |
| } |
| |
| return source; |
| } |
| |
| static int irqmp_init(const struct device *dev) |
| { |
| volatile struct irqmp_regs *regs = get_irqmp_regs(); |
| |
| regs->ilevel = 0; |
| regs->ipend = 0; |
| regs->iforce0 = 0; |
| regs->pimask[0] = 0; |
| regs->piforce[0] = 0xfffe0000; |
| |
| return 0; |
| } |
| |
| DEVICE_DT_INST_DEFINE(0, irqmp_init, NULL, NULL, NULL, |
| PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL); |