summaryrefslogtreecommitdiff
path: root/software/shared/drivers_sifive
diff options
context:
space:
mode:
authorMegan Wachs <megan@sifive.com>2016-07-20 23:59:02 +0000
committerMegan Wachs <megan@sifive.com>2016-07-26 08:40:12 -0700
commit2887165ae2990e7f93038f3220ed74ee429b5244 (patch)
tree13c4cb83e47d6ab390e0465e883acf0973611e8e /software/shared/drivers_sifive
parenta2d28c8318ab3ed40b3674aeee8b9487a3129f15 (diff)
Initial Checkin
Diffstat (limited to 'software/shared/drivers_sifive')
-rw-r--r--software/shared/drivers_sifive/plic.c123
-rw-r--r--software/shared/drivers_sifive/plic.h70
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