diff options
author | Megan Wachs <megan@sifive.com> | 2016-07-20 23:59:02 +0000 |
---|---|---|
committer | Megan Wachs <megan@sifive.com> | 2016-07-26 08:40:12 -0700 |
commit | 2887165ae2990e7f93038f3220ed74ee429b5244 (patch) | |
tree | 13c4cb83e47d6ab390e0465e883acf0973611e8e /software/shared/drivers_sifive | |
parent | a2d28c8318ab3ed40b3674aeee8b9487a3129f15 (diff) |
Initial Checkin
Diffstat (limited to 'software/shared/drivers_sifive')
-rw-r--r-- | software/shared/drivers_sifive/plic.c | 123 | ||||
-rw-r--r-- | software/shared/drivers_sifive/plic.h | 70 |
2 files changed, 193 insertions, 0 deletions
diff --git a/software/shared/drivers_sifive/plic.c b/software/shared/drivers_sifive/plic.c new file mode 100644 index 0000000..ec0c178 --- /dev/null +++ b/software/shared/drivers_sifive/plic.c @@ -0,0 +1,123 @@ +// See LICENSE for license details. + +#include "plic.h" +#include "encoding.h" +#include <string.h> + + +// Note that there are no assertions or bounds checking on these +// parameter values. + +void volatile_memzero(uint8_t * base, unsigned int size){ + + volatile uint8_t * ptr; + for (ptr = base; ptr < (base + size); ptr++){ + *ptr = 0; + } +} + +void PLIC_init ( + plic_instance_t * this_plic, + uintptr_t base_addr, + uint32_t num_sources, + uint32_t num_priorities + ){ + + this_plic->base_addr = base_addr; + this_plic->num_sources = num_sources; + this_plic->num_priorities = num_priorities; + + // Disable all interrupts (don't assume that these registers are reset). + unsigned long hart_id = read_csr(mhartid); + volatile_memzero((uint8_t*) (this_plic->base_addr + + PLIC_ENABLE_OFFSET + + (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET)), + (num_sources + 8) / 8); + + // Set all priorities to 0 (equal priority -- don't assume that these are reset). + volatile_memzero ((uint8_t *)(this_plic->base_addr + + PLIC_PRIORITY_OFFSET), + (num_sources + 1) << PLIC_PRIORITY_SHIFT_PER_SOURCE); + + // Set the threshold to 0. + volatile plic_threshold* threshold = (plic_threshold*) + (this_plic->base_addr + + PLIC_THRESHOLD_OFFSET + + (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET)); + + *threshold = 0; + +} + +void PLIC_set_threshold (plic_instance_t * this_plic, plic_threshold threshold){ + + unsigned long hart_id = read_csr(mhartid); + volatile plic_threshold* threshold_ptr = (plic_threshold*) (this_plic->base_addr + + PLIC_THRESHOLD_OFFSET + + (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET)); + + *threshold_ptr = threshold; + +} + + +void PLIC_enable_interrupt (plic_instance_t * this_plic, plic_source source){ + + unsigned long hart_id = read_csr(mhartid); + volatile uint8_t * current_ptr = (volatile uint8_t *)(this_plic->base_addr + + PLIC_ENABLE_OFFSET + + (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) + + (source >> 3)); + uint8_t current = *current_ptr; + current = current | ( 1 << (source & 0x7)); + *current_ptr = current; + +} + +void PLIC_disable_interrupt (plic_instance_t * this_plic, plic_source source){ + + unsigned long hart_id = read_csr(mhartid); + volatile uint8_t * current_ptr = (volatile uint8_t *) (this_plic->base_addr + + PLIC_ENABLE_OFFSET + + (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) + + (source >> 3)); + uint8_t current = *current_ptr; + current = current & ~(( 1 << (source & 0x7))); + *current_ptr = current; + +} + +void PLIC_set_priority (plic_instance_t * this_plic, plic_source source, plic_priority priority){ + + if (this_plic->num_priorities > 0) { + volatile plic_priority * priority_ptr = (volatile plic_priority *) + (this_plic->base_addr + + PLIC_PRIORITY_OFFSET + + (source << PLIC_PRIORITY_SHIFT_PER_SOURCE)); + *priority_ptr = priority; + } +} + +plic_source PLIC_claim_interrupt(plic_instance_t * this_plic){ + + unsigned long hart_id = read_csr(mhartid); + + volatile plic_source * claim_addr = (volatile plic_source * ) + (this_plic->base_addr + + PLIC_CLAIM_OFFSET + + (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET)); + + return *claim_addr; + +} + +void PLIC_complete_interrupt(plic_instance_t * this_plic, plic_source source){ + + unsigned long hart_id = read_csr(mhartid); + volatile plic_source * claim_addr = (volatile plic_source *) (this_plic->base_addr + + PLIC_CLAIM_OFFSET + + (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET)); + *claim_addr = source; + +} + diff --git a/software/shared/drivers_sifive/plic.h b/software/shared/drivers_sifive/plic.h new file mode 100644 index 0000000..14118a5 --- /dev/null +++ b/software/shared/drivers_sifive/plic.h @@ -0,0 +1,70 @@ +// See LICENSE for license details. + +#ifndef PLIC_H +#define PLIC_H + +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> +#include <unistd.h> + + +#include "encoding.h" + +// 32 bits per source +#define PLIC_PRIORITY_OFFSET 0x0000UL +#define PLIC_PRIORITY_SHIFT_PER_SOURCE 2 +// 1 bit per source (1 address) +#define PLIC_PENDING_OFFSET 0x1000UL +#define PLIC_PENDING_SHIFT_PER_SOURCE 0 + +//0x80 per target +#define PLIC_ENABLE_OFFSET 0x2000UL +#define PLIC_ENABLE_SHIFT_PER_TARGET 7 + + +#define PLIC_THRESHOLD_OFFSET 0x200000UL +#define PLIC_CLAIM_OFFSET 0x200004UL +#define PLIC_THRESHOLD_SHIFT_PER_TARGET 12 +#define PLIC_CLAIM_SHIFT_PER_TARGET 12 + +#define PLIC_MAX_SOURCE 1023 +#define PLIC_SOURCE_MASK 0x3FF + +#define PLIC_MAX_TARGET 15871 +#define PLIC_TARGET_MASK 0x3FFF + + +typedef struct __plic_instance_t +{ + uintptr_t base_addr; + + uint32_t num_sources; + uint32_t num_priorities; + +} plic_instance_t; + +typedef uint32_t plic_source; +typedef uint32_t plic_priority; +typedef uint32_t plic_threshold; + +void PLIC_init ( + plic_instance_t * this_plic, + uintptr_t base_addr, + uint32_t num_sources, + uint32_t num_priorities + ); + +void PLIC_enable_interrupt (plic_instance_t * this_plic, plic_source source); + +void PLIC_disable_interrupt (plic_instance_t * this_plic, plic_source source); + +void PLIC_set_priority (plic_instance_t * this_plic, plic_source source, plic_priority priority); + +plic_source PLIC_claim_interrupt(plic_instance_t * this_plic); + +void PLIC_complete_interrupt(plic_instance_t * this_plic, plic_source source); + +void PLIC_set_threshold(plic_instance_t * this_plic, plic_threshold threshold); + +#endif |