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 | /* * Copyright (c) 2014 Wind River Systems, Inc. * Copyright (c) 2020 Synopsys. * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief ARCv2 Interrupt Unit device driver * * The ARCv2 interrupt unit has 16 allocated exceptions associated with * vectors 0 to 15 and 240 interrupts associated with vectors 16 to 255. * The interrupt unit is optional in the ARCv2-based processors. When * building a processor, you can configure the processor to include an * interrupt unit. The ARCv2 interrupt unit is highly programmable. */ #include <kernel.h> #include <arch/cpu.h> #include <device.h> #include <init.h> extern void *_VectorTable; #ifdef CONFIG_PM_DEVICE #include <pm/device.h> #include <kernel_structs.h> #ifdef CONFIG_ARC_SECURE_FIRMWARE #undef _ARC_V2_IRQ_VECT_BASE #define _ARC_V2_IRQ_VECT_BASE _ARC_V2_IRQ_VECT_BASE_S #endif struct arc_v2_irq_unit_ctx { uint32_t irq_ctrl; /* Interrupt Context Saving Control Register. */ uint32_t irq_vect_base; /* Interrupt Vector Base. */ /* * IRQ configuration: * - IRQ Priority:BIT(6):BIT(2) * - IRQ Trigger:BIT(1) * - IRQ Enable:BIT(0) */ uint8_t irq_config[CONFIG_NUM_IRQS - 16]; }; static struct arc_v2_irq_unit_ctx ctx; #endif /* * @brief Initialize the interrupt unit device driver * * Initializes the interrupt unit device driver and the device * itself. * * Interrupts are still locked at this point, so there is no need to protect * the window between a write to IRQ_SELECT and subsequent writes to the * selected IRQ's registers. * * @return 0 for success */ static int arc_v2_irq_unit_init(const struct device *unused) { ARG_UNUSED(unused); int irq; /* the interrupt index */ /* Interrupts from 0 to 15 are exceptions and they are ignored * by IRQ auxiliary registers. For that reason we skip those * values in this loop. */ for (irq = 16; irq < CONFIG_NUM_IRQS; irq++) { z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq); #ifdef CONFIG_ARC_SECURE_FIRMWARE z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY, (CONFIG_NUM_IRQ_PRIO_LEVELS-1) | _ARC_V2_IRQ_PRIORITY_SECURE); /* lowest priority */ #else z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY, (CONFIG_NUM_IRQ_PRIO_LEVELS-1)); /* lowest priority */ #endif z_arc_v2_aux_reg_write(_ARC_V2_IRQ_ENABLE, _ARC_V2_INT_DISABLE); z_arc_v2_aux_reg_write(_ARC_V2_IRQ_TRIGGER, _ARC_V2_INT_LEVEL); } return 0; } #ifdef CONFIG_PM_DEVICE /* * @brief Suspend the interrupt unit device driver * * Suspends the interrupt unit device driver and the device * itself. * * @return 0 for success */ static int arc_v2_irq_unit_suspend(const struct device *dev) { uint8_t irq; ARG_UNUSED(dev); /* Interrupts from 0 to 15 are exceptions and they are ignored * by IRQ auxiliary registers. For that reason we skip those * values in this loop. */ for (irq = 16U; irq < CONFIG_NUM_IRQS; irq++) { z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq); ctx.irq_config[irq - 16] = z_arc_v2_aux_reg_read(_ARC_V2_IRQ_PRIORITY) << 2; ctx.irq_config[irq - 16] |= z_arc_v2_aux_reg_read(_ARC_V2_IRQ_TRIGGER) << 1; ctx.irq_config[irq - 16] |= z_arc_v2_aux_reg_read(_ARC_V2_IRQ_ENABLE); } ctx.irq_ctrl = z_arc_v2_aux_reg_read(_ARC_V2_AUX_IRQ_CTRL); ctx.irq_vect_base = z_arc_v2_aux_reg_read(_ARC_V2_IRQ_VECT_BASE); return 0; } /* * @brief Resume the interrupt unit device driver * * Resume the interrupt unit device driver and the device * itself. * * @return 0 for success */ static int arc_v2_irq_unit_resume(const struct device *dev) { uint8_t irq; ARG_UNUSED(dev); /* Interrupts from 0 to 15 are exceptions and they are ignored * by IRQ auxiliary registers. For that reason we skip those * values in this loop. */ for (irq = 16U; irq < CONFIG_NUM_IRQS; irq++) { z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq); #ifdef CONFIG_ARC_SECURE_FIRMWARE z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY, ctx.irq_config[irq - 16] >> 2 | _ARC_V2_IRQ_PRIORITY_SECURE); #else z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY, ctx.irq_config[irq - 16] >> 2); #endif z_arc_v2_aux_reg_write(_ARC_V2_IRQ_TRIGGER, (ctx.irq_config[irq - 16] >> 1) & BIT(0)); z_arc_v2_aux_reg_write(_ARC_V2_IRQ_ENABLE, ctx.irq_config[irq - 16] & BIT(0)); } #ifdef CONFIG_ARC_NORMAL_FIRMWARE /* \todo use sjli instruction to access irq_ctrl */ #else z_arc_v2_aux_reg_write(_ARC_V2_AUX_IRQ_CTRL, ctx.irq_ctrl); #endif z_arc_v2_aux_reg_write(_ARC_V2_IRQ_VECT_BASE, ctx.irq_vect_base); return 0; } /* * @brief Implement the driver control of interrupt unit * * The operation on interrupt unit requires interrupt lock. * The *context may include IN data or/and OUT data * * @return operation result */ static int arc_v2_irq_unit_device_ctrl(const struct device *dev, enum pm_device_action action) { int ret = 0; unsigned int key = arch_irq_lock(); switch (action) { case PM_DEVICE_ACTION_SUSPEND: ret = arc_v2_irq_unit_suspend(dev); break; case PM_DEVICE_ACTION_RESUME: ret = arc_v2_irq_unit_resume(dev); break; default: ret = -ENOTSUP; break; } arch_irq_unlock(key); return ret; } SYS_DEVICE_DEFINE("arc_v2_irq_unit", arc_v2_irq_unit_init, arc_v2_irq_unit_device_ctrl, PRE_KERNEL_1, 0); #else SYS_INIT(arc_v2_irq_unit_init, PRE_KERNEL_1, 0); #endif /* CONFIG_PM_DEVICE */ |