| /* Copyright 2018 SiFive, Inc */ |
| /* SPDX-License-Identifier: Apache-2.0 */ |
| |
| #include <metal/machine/platform.h> |
| |
| #ifdef METAL_SIFIVE_GLOBAL_EXTERNAL_INTERRUPTS0 |
| |
| #include <metal/io.h> |
| #include <metal/shutdown.h> |
| #include <metal/drivers/sifive_global-external-interrupts0.h> |
| #include <metal/machine.h> |
| |
| void __metal_driver_sifive_global_external_interrupt_init(struct metal_interrupt *controller) |
| { |
| struct __metal_driver_sifive_global_external_interrupts0 *global0; |
| |
| global0 = (struct __metal_driver_sifive_global_external_interrupts0 *)(controller); |
| if ( !global0->init_done ) { |
| struct metal_interrupt *intc = |
| __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); |
| |
| if (intc) { |
| intc->vtable->interrupt_init(intc); |
| /* Register its interrupts with with parent controller */ |
| for (int i = 0; |
| i < __metal_driver_sifive_global_external_interrupts0_num_interrupts(controller); |
| i++) { |
| intc->vtable->interrupt_register(intc, |
| __metal_driver_sifive_global_external_interrupts0_interrupt_lines(controller, i), |
| NULL, controller); |
| } |
| global0->init_done = 1; |
| } |
| } |
| } |
| |
| int __metal_driver_sifive_global_external_interrupt_register(struct metal_interrupt *controller, |
| int id, metal_interrupt_handler_t isr, |
| void *priv) |
| { |
| int rc = -1; |
| |
| if (id != 0) { |
| struct metal_interrupt *intc = |
| __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); |
| |
| /* Enable its interrupts with parent controller */ |
| if (intc) { |
| rc = intc->vtable->interrupt_register(intc, id, isr, priv); |
| } |
| } |
| return rc; |
| } |
| |
| int __metal_driver_sifive_global_external_interrupt_enable(struct metal_interrupt *controller, int id) |
| { |
| int rc = -1; |
| |
| if (id != 0) { |
| struct metal_interrupt *intc = |
| __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); |
| |
| /* Enable its interrupts with parent controller */ |
| if (intc) { |
| rc = intc->vtable->interrupt_enable(intc, id); |
| } |
| } |
| return rc; |
| } |
| |
| int __metal_driver_sifive_global_external_interrupt_disable(struct metal_interrupt *controller, int id) |
| { |
| int rc = -1; |
| |
| if (id != 0) { |
| struct metal_interrupt *intc = |
| __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); |
| |
| /* Enable its interrupts with parent controller */ |
| if (intc) { |
| rc = intc->vtable->interrupt_disable(intc, id); |
| } |
| } |
| return rc; |
| } |
| |
| int __metal_driver_sifive_global_external_interrupt_set_threshold(struct metal_interrupt *controller, |
| unsigned int threshold) |
| { |
| struct metal_interrupt *intc = |
| __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); |
| if (intc) { |
| return intc->vtable->interrupt_set_threshold(intc, threshold); |
| } |
| return -1; |
| } |
| |
| unsigned int __metal_driver_sifive_global_external_interrupt_get_threshold(struct metal_interrupt *controller) |
| { |
| struct metal_interrupt *intc = |
| __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); |
| |
| if (intc) { |
| return intc->vtable->interrupt_get_threshold(intc); |
| } |
| return 0; |
| } |
| |
| int __metal_driver_sifive_global_external_interrupt_set_priority(struct metal_interrupt *controller, |
| int id, unsigned int priority) |
| { |
| struct metal_interrupt *intc = |
| __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); |
| if (intc) { |
| return intc->vtable->interrupt_set_priority(intc, id, priority); |
| } |
| return -1; |
| } |
| |
| unsigned int __metal_driver_sifive_global_external_interrupt_get_priority(struct metal_interrupt *controller, int id) |
| { |
| struct metal_interrupt *intc = |
| __metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller); |
| |
| if (intc) { |
| return intc->vtable->interrupt_get_priority(intc, id); |
| } |
| return 0; |
| } |
| |
| int __metal_driver_sifive_global_external_command_request (struct metal_interrupt *controller, |
| int command, void *data) |
| { |
| int idx; |
| int rc = -1; |
| |
| switch (command) { |
| case METAL_MAX_INTERRUPT_GET: |
| rc = __metal_driver_sifive_global_external_interrupts0_num_interrupts(controller); |
| break; |
| case METAL_INDEX_INTERRUPT_GET: |
| rc = 0; |
| if (data) { |
| idx = *(int *)data; |
| rc = __metal_driver_sifive_global_external_interrupts0_interrupt_lines(controller, idx); |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return rc; |
| } |
| |
| __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0) = { |
| .global0_vtable.interrupt_init = __metal_driver_sifive_global_external_interrupt_init, |
| .global0_vtable.interrupt_register = __metal_driver_sifive_global_external_interrupt_register, |
| .global0_vtable.interrupt_enable = __metal_driver_sifive_global_external_interrupt_enable, |
| .global0_vtable.interrupt_disable = __metal_driver_sifive_global_external_interrupt_disable, |
| .global0_vtable.interrupt_get_threshold = __metal_driver_sifive_global_external_interrupt_get_threshold, |
| .global0_vtable.interrupt_set_threshold = __metal_driver_sifive_global_external_interrupt_set_threshold, |
| .global0_vtable.interrupt_get_priority = __metal_driver_sifive_global_external_interrupt_get_priority, |
| .global0_vtable.interrupt_set_priority = __metal_driver_sifive_global_external_interrupt_set_priority, |
| .global0_vtable.command_request = __metal_driver_sifive_global_external_command_request, |
| }; |
| |
| #endif |
| |
| typedef int no_empty_translation_units; |