Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | /* * Copyright (c) 2019 Western Digital Corporation or its affiliates * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT swerv_pic /** * @brief SweRV EH1 PIC driver */ #include <zephyr/kernel.h> #include <zephyr/arch/cpu.h> #include <zephyr/init.h> #include <zephyr/sw_isr_table.h> #define SWERV_PIC_MAX_NUM CONFIG_NUM_IRQS #define SWERV_PIC_MAX_ID (SWERV_PIC_MAX_NUM + RISCV_MAX_GENERIC_IRQ) #define SWERV_PIC_MAX_PRIO 16 #define SWERV_PIC_mpiccfg 0x3000 #define SWERV_PIC_meipl(s) (0x0 + (s)*4) #define SWERV_PIC_meip(x) (0x1000 + (x)*4) #define SWERV_PIC_meie(s) (0x2000 + (s)*4) #define SWERV_PIC_meigwctrl(s) (0x4000 + (s)*4) #define SWERV_PIC_meigwclr(s) (0x5000 + (s)*4) #define SWERV_PIC_meivt "0xBC8" #define SWERV_PIC_meipt "0xBC9" #define SWERV_PIC_meicpct "0xBCA" #define SWERV_PIC_meicidpl "0xBCB" #define SWERV_PIC_meicurpl "0xBCC" #define SWERV_PIC_meihap "0xFC8" #define swerv_piccsr(csr) SWERV_PIC_##csr #define swerv_pic_readcsr(csr, value) \ volatile("csrr %0, "swerv_piccsr(csr) : "=r" (value)) #define swerv_pic_writecsr(csr, value) \ volatile("csrw "swerv_piccsr(csr)", %0" :: "rK" (value)) static int save_irq; static uint32_t swerv_pic_read(uint32_t reg) { return *(volatile uint32_t *)(DT_INST_REG_ADDR(0) + reg); } static void swerv_pic_write(uint32_t reg, uint32_t val) { *(volatile uint32_t *)(DT_INST_REG_ADDR(0) + reg) = val; } void swerv_pic_irq_enable(uint32_t irq) { uint32_t key; if ((irq >= SWERV_PIC_MAX_ID) || (irq < RISCV_MAX_GENERIC_IRQ)) { return; } key = irq_lock(); swerv_pic_write(SWERV_PIC_meie(irq - RISCV_MAX_GENERIC_IRQ), 1); irq_unlock(key); } void swerv_pic_irq_disable(uint32_t irq) { uint32_t key; if ((irq >= SWERV_PIC_MAX_ID) || (irq < RISCV_MAX_GENERIC_IRQ)) { return; } key = irq_lock(); swerv_pic_write(SWERV_PIC_meie(irq - RISCV_MAX_GENERIC_IRQ), 0); irq_unlock(key); } int swerv_pic_irq_is_enabled(uint32_t irq) { if ((irq >= SWERV_PIC_MAX_ID) || (irq < RISCV_MAX_GENERIC_IRQ)) { return -1; } return swerv_pic_read(SWERV_PIC_meie(irq - RISCV_MAX_GENERIC_IRQ)) & 0x1; } void swerv_pic_set_priority(uint32_t irq, uint32_t priority) { uint32_t key; if (irq <= RISCV_MAX_GENERIC_IRQ) { return; } if ((irq >= SWERV_PIC_MAX_ID) || (irq < RISCV_MAX_GENERIC_IRQ)) { return; } if (priority >= SWERV_PIC_MAX_PRIO) { return; } key = irq_lock(); swerv_pic_write(SWERV_PIC_meipl(irq - RISCV_MAX_GENERIC_IRQ), priority); irq_unlock(key); } int swerv_pic_get_irq(void) { return save_irq; } static void swerv_pic_irq_handler(const void *arg) { uint32_t tmp; uint32_t irq; struct _isr_table_entry *ite; /* trigger the capture of the interrupt source ID */ __asm__ swerv_pic_writecsr(meicpct, 0); __asm__ swerv_pic_readcsr(meihap, tmp); irq = (tmp >> 2) & 0xff; save_irq = irq; if (irq == 0U || irq >= 64) { z_irq_spurious(NULL); } irq += RISCV_MAX_GENERIC_IRQ; /* Call the corresponding IRQ handler in _sw_isr_table */ ite = (struct _isr_table_entry *)&_sw_isr_table[irq]; if (ite->isr) { ite->isr(ite->arg); } swerv_pic_write(SWERV_PIC_meigwclr(irq), 0); } static int swerv_pic_init(const struct device *dev) { ARG_UNUSED(dev); int i; /* Init priority order to 0, 0=lowest to 15=highest */ swerv_pic_write(SWERV_PIC_mpiccfg, 0); /* Ensure that all interrupts are disabled initially */ for (i = 1; i < SWERV_PIC_MAX_ID; i++) { swerv_pic_write(SWERV_PIC_meie(i), 0); } /* Set priority of each interrupt line to 0 initially */ for (i = 1; i < SWERV_PIC_MAX_ID; i++) { swerv_pic_write(SWERV_PIC_meipl(i), 15); } /* Set property of each interrupt line to level-triggered/high */ for (i = 1; i < SWERV_PIC_MAX_ID; i++) { swerv_pic_write(SWERV_PIC_meigwctrl(i), (0<<1)|(0<<0)); } /* clear pending of each interrupt line */ for (i = 1; i < SWERV_PIC_MAX_ID; i++) { swerv_pic_write(SWERV_PIC_meigwclr(i), 0); } /* No interrupts masked */ __asm__ swerv_pic_writecsr(meipt, 0); __asm__ swerv_pic_writecsr(meicidpl, 0); __asm__ swerv_pic_writecsr(meicurpl, 0); /* Setup IRQ handler for SweRV PIC driver */ IRQ_CONNECT(RISCV_MACHINE_EXT_IRQ, 0, swerv_pic_irq_handler, NULL, 0); /* Enable IRQ for SweRV PIC driver */ irq_enable(RISCV_MACHINE_EXT_IRQ); return 0; } void arch_irq_enable(unsigned int irq) { uint32_t mie; if (irq > RISCV_MAX_GENERIC_IRQ) { swerv_pic_irq_enable(irq); return; } /* * CSR mie register is updated using atomic instruction csrrs * (atomic read and set bits in CSR register) */ __asm__ volatile ("csrrs %0, mie, %1\n" : "=r" (mie) : "r" (1 << irq)); } void arch_irq_disable(unsigned int irq) { uint32_t mie; if (irq > RISCV_MAX_GENERIC_IRQ) { swerv_pic_irq_disable(irq); return; } /* * Use atomic instruction csrrc to disable device interrupt in mie CSR. * (atomic read and clear bits in CSR register) */ __asm__ volatile ("csrrc %0, mie, %1\n" : "=r" (mie) : "r" (1 << irq)); }; int arch_irq_is_enabled(unsigned int irq) { uint32_t mie; if (irq > RISCV_MAX_GENERIC_IRQ) return swerv_pic_irq_is_enabled(irq); __asm__ volatile ("csrr %0, mie" : "=r" (mie)); return !!(mie & (1 << irq)); } SYS_INIT(swerv_pic_init, PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY); |