summaryrefslogtreecommitdiff
path: root/bsp/drivers/clic/clic_driver.c
blob: 136ccee3caab53238cfe899c51a3e34119632e90 (plain)
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
// See LICENSE for license details.

#include "sifive/devices/clic.h"
#include "clic/clic_driver.h"
#include "platform.h"
#include "encoding.h"
#include <string.h>


void volatile_memzero(uint8_t * base, unsigned int size) {
  volatile uint8_t * ptr;
  for (ptr = base; ptr < (base + size); ptr++){
    *ptr = 0;
  }
}

// Note that there are no assertions or bounds checking on these
// parameter values.
void clic_init (
                clic_instance_t * this_clic,
                uintptr_t hart_addr,
                interrupt_function_ptr_t* vect_table,
                interrupt_function_ptr_t default_handler,
                uint32_t num_irq,
                uint32_t num_config_bits
                )
{
  this_clic->hart_addr=  hart_addr;
  this_clic->vect_table= vect_table;
  this_clic->num_config_bits= num_config_bits;

  //initialize vector table
  for(int i=0;i<num_irq;i++)  {
    this_clic->vect_table[i] = default_handler;
  }

  //set base vectors
  write_csr(mtvt, vect_table);


  //clear all interrupt enables and pending
  volatile_memzero((uint8_t*)(this_clic->hart_addr+CLIC_INTIE), num_irq);
  volatile_memzero((uint8_t*)(this_clic->hart_addr+CLIC_INTIP), num_irq);

  //clear nlbits and nvbits; all interrupts trap to level 15
  *(volatile uint8_t*)(this_clic->hart_addr+CLIC_CFG)=0;

}

void clic_install_handler (clic_instance_t * this_clic, uint32_t source, interrupt_function_ptr_t handler) {
    this_clic->vect_table[source] = handler;
}

void clic_enable_interrupt (clic_instance_t * this_clic, uint32_t source) {
    *(volatile uint8_t*)(this_clic->hart_addr+CLIC_INTIE+source) = 1;
}

void clic_disable_interrupt (clic_instance_t * this_clic, uint32_t source){
  *(volatile uint8_t*)(this_clic->hart_addr+CLIC_INTIE+source) = 0;
}

void clic_set_pending(clic_instance_t * this_clic, uint32_t source){
  *(volatile uint8_t*)(this_clic->hart_addr+CLIC_INTIP+source) = 1;
}

void clic_clear_pending(clic_instance_t * this_clic, uint32_t source){
  *(volatile uint8_t*)(this_clic->hart_addr+CLIC_INTIP+source) = 0;
}

void clic_set_intcfg (clic_instance_t * this_clic, uint32_t source, uint32_t intcfg){
  *(volatile uint8_t*)(this_clic->hart_addr+CLIC_INTCFG+source) = intcfg;
}

uint8_t clic_get_intcfg  (clic_instance_t * this_clic, uint32_t source){
  return *(volatile uint8_t*)(this_clic->hart_addr+CLIC_INTCFG+source);
}

void clic_set_cliccfg (clic_instance_t * this_clic, uint32_t cfg){
  *(volatile uint8_t*)(this_clic->hart_addr+CLIC_CFG) = cfg;
}

uint8_t clic_get_cliccfg  (clic_instance_t * this_clic){
  return *(volatile uint8_t*)(this_clic->hart_addr+CLIC_CFG);
}

//sets an interrupt level based encoding of nmbits, nlbits
uint8_t clic_set_int_level( clic_instance_t * this_clic, uint32_t source, uint8_t level) {
  //extract nlbits
  uint8_t nlbits = clic_get_cliccfg(this_clic);
  nlbits = (nlbits >>1) & 0x7;

  //shift level right to mask off unused bits
  level = level>>((this_clic->num_config_bits)-nlbits); //plus this_clic->nmbits which is always 0 for now.
  //shift level into correct bit position
  level = level << (8-this_clic->num_config_bits) + (this_clic->num_config_bits - nlbits);
 
  //write to clicintcfg
  uint8_t current_intcfg = clic_get_intcfg(this_clic, source);
  clic_set_intcfg(this_clic, source, (current_intcfg | level));

  return level;
}

//gets an interrupt level based encoding of nmbits, nlbits
uint8_t clic_get_int_level( clic_instance_t * this_clic, uint32_t source) {
  uint8_t level;
  level = clic_get_intcfg(this_clic, source);

  //extract nlbits
  uint8_t nlbits = clic_get_cliccfg(this_clic);
  nlbits = (nlbits >>1) & 0x7;

  //shift level
  level = level >> (8-(this_clic->num_config_bits));

  //shift level right to mask off priority bits
  level = level>>(this_clic->num_config_bits-nlbits); //this_clic->nmbits which is always 0 for now.

  return level;
}

//sets an interrupt priority based encoding of nmbits, nlbits
uint8_t clic_set_int_priority( clic_instance_t * this_clic, uint32_t source, uint8_t priority) {
  //priority bits = num_config_bits - nlbits
  //extract nlbits
  uint8_t nlbits = clic_get_cliccfg(this_clic);
  nlbits = (nlbits >>1) & 0x7;

  uint8_t priority_bits = this_clic->num_config_bits-nlbits;
  if(priority_bits = 0) {
    //no bits to set
    return 0;
  }
  //mask off unused bits
  priority = priority >> (8-priority_bits);
  //shift into the correct bit position
  priority = priority << (8-(this_clic->num_config_bits));

  //write to clicintcfg
  uint8_t current_intcfg = clic_get_intcfg(this_clic, source);
  clic_set_intcfg(this_clic, source, (current_intcfg | priority));
  return current_intcfg;
}

//gets an interrupt priority based encoding of nmbits, nlbits
uint8_t clic_get_int_priority( clic_instance_t * this_clic, uint32_t source) {
  uint8_t priority;
  priority = clic_get_intcfg(this_clic, source);

  //extract nlbits
  uint8_t nlbits = clic_get_cliccfg(this_clic);
  nlbits = (nlbits >>1) & 0x7;

  //shift left to mask off level bits
  priority = priority << nlbits;

  //shift priority
  priority = priority >> (8-((this_clic->num_config_bits)+nlbits));

 return priority;
}