Skip to content

Commit a65cf4e

Browse files
committed
riscv: add Xuantie PLIC peripheral support
Xuantie PLIC has one extra bit allowing to control if the supervisor have access to specific PLIC fields. The `probe_{priority, threshold}_bits` returns a constant 5 for T-Head PLIC structure other than actually detecting this field. Signed-off-by: Zhouqi Jiang <[email protected]>
1 parent 5452e6a commit a65cf4e

File tree

3 files changed

+162
-0
lines changed

3 files changed

+162
-0
lines changed

Diff for: xuantie-riscv/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ targets = [
2222
[dependencies]
2323
bit_field = "0.10"
2424
bitflags = "2"
25+
plic = "0.0.2"
2526
volatile-register = "0.2.2"
2627

2728
[lib]

Diff for: xuantie-riscv/src/peripheral/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
//! XuanTie core peripherals.
22
33
pub mod clint;
4+
pub mod plic;

Diff for: xuantie-riscv/src/peripheral/plic.rs

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//! XuanTie Platform Local Interrupt Controller (PLIC).
2+
3+
use core::{
4+
num::NonZeroU32,
5+
ptr::{read_volatile, write_volatile},
6+
};
7+
use plic::{HartContext, InterruptSource};
8+
9+
const PLIC_CTRL_OFFSET: usize = 0x01F_FFFC;
10+
const PLIC_CTRL_S_PER_ENABLED: u32 = 0x1;
11+
const PLIC_CTRL_S_PER_DISABLED: u32 = 0x0;
12+
const PLIC_CTRL_S_PER_BIT: u32 = 0x1;
13+
const THEAD_PLIC_PRIORITY_BITS: u32 = 5;
14+
15+
/// Register block for XuanTie Platform Local Interrupt Controller (PLIC).
16+
#[repr(C, align(4096))]
17+
pub struct Plic {
18+
inner: plic::Plic,
19+
}
20+
21+
impl Plic {
22+
/// Enable supervisor access to all the PLIC registers.
23+
#[inline]
24+
pub fn enable_supervisor_access(&self) {
25+
let plic_ctrl =
26+
unsafe { (&self.inner as *const _ as *const u8).add(PLIC_CTRL_OFFSET) as *mut u32 };
27+
unsafe { write_volatile(plic_ctrl, PLIC_CTRL_S_PER_ENABLED) };
28+
}
29+
30+
/// Disable supervisor access to all the PLIC registers.
31+
#[inline]
32+
pub fn disable_supervisor_access(&self) {
33+
let plic_ctrl =
34+
unsafe { (&self.inner as *const _ as *const u8).add(PLIC_CTRL_OFFSET) as *mut u32 };
35+
unsafe { write_volatile(plic_ctrl, PLIC_CTRL_S_PER_DISABLED) };
36+
}
37+
38+
/// Check if supervisor access to all the PLIC registers is enabled.
39+
#[inline]
40+
pub fn is_supervisor_access_enabled(&self) -> bool {
41+
let plic_ctrl =
42+
unsafe { (&self.inner as *const _ as *const u8).add(PLIC_CTRL_OFFSET) as *const u32 };
43+
let val = unsafe { read_volatile(plic_ctrl) };
44+
val & PLIC_CTRL_S_PER_BIT != 0
45+
}
46+
}
47+
48+
impl Plic {
49+
/// Sets priority for interrupt `source` to `value`.
50+
#[inline]
51+
pub fn set_priority<S>(&self, source: S, value: u32)
52+
where
53+
S: InterruptSource,
54+
{
55+
self.inner.set_priority(source, value);
56+
}
57+
58+
/// Gets priority for interrupt `source`.
59+
#[inline]
60+
pub fn get_priority<S>(&self, source: S) -> u32
61+
where
62+
S: InterruptSource,
63+
{
64+
self.inner.get_priority(source)
65+
}
66+
67+
/// Probe maximum level of priority for interrupt `source`.
68+
#[inline]
69+
pub fn probe_priority_bits<S>(&self, _source: S) -> u32
70+
where
71+
S: InterruptSource,
72+
{
73+
THEAD_PLIC_PRIORITY_BITS
74+
}
75+
76+
/// Check if interrupt `source` is pending.
77+
#[inline]
78+
pub fn is_pending<S>(&self, source: S) -> bool
79+
where
80+
S: InterruptSource,
81+
{
82+
self.inner.is_pending(source)
83+
}
84+
85+
/// Enable interrupt `source` in `context`.
86+
#[inline]
87+
pub fn enable<S, C>(&self, source: S, context: C)
88+
where
89+
S: InterruptSource,
90+
C: HartContext,
91+
{
92+
self.inner.enable(source, context);
93+
}
94+
95+
/// Disable interrupt `source` in `context`.
96+
#[inline]
97+
pub fn disable<S, C>(&self, source: S, context: C)
98+
where
99+
S: InterruptSource,
100+
C: HartContext,
101+
{
102+
self.inner.disable(source, context);
103+
}
104+
105+
/// Check if interrupt `source` is enabled in `context`.
106+
#[inline]
107+
pub fn is_enabled<S, C>(&self, source: S, context: C) -> bool
108+
where
109+
S: InterruptSource,
110+
C: HartContext,
111+
{
112+
self.inner.is_enabled(source, context)
113+
}
114+
115+
/// Get interrupt threshold in `context`.
116+
#[inline]
117+
pub fn get_threshold<C>(&self, context: C) -> u32
118+
where
119+
C: HartContext,
120+
{
121+
self.inner.get_threshold(context)
122+
}
123+
124+
/// Set interrupt threshold for `context` to `value`.
125+
#[inline]
126+
pub fn set_threshold<C>(&self, context: C, value: u32)
127+
where
128+
C: HartContext,
129+
{
130+
self.inner.set_threshold(context, value);
131+
}
132+
133+
/// Probe maximum supported threshold value the `context` supports.
134+
#[inline]
135+
pub fn probe_threshold_bits<C>(&self, _context: C) -> u32
136+
where
137+
C: HartContext,
138+
{
139+
THEAD_PLIC_PRIORITY_BITS
140+
}
141+
142+
/// Claim an interrupt in `context`, returning its source.
143+
#[inline]
144+
pub fn claim<C>(&self, context: C) -> Option<NonZeroU32>
145+
where
146+
C: HartContext,
147+
{
148+
self.inner.claim(context)
149+
}
150+
151+
/// Mark that interrupt identified by `source` is completed in `context`.
152+
#[inline]
153+
pub fn complete<C, S>(&self, context: C, source: S)
154+
where
155+
C: HartContext,
156+
S: InterruptSource,
157+
{
158+
self.inner.complete(context, source);
159+
}
160+
}

0 commit comments

Comments
 (0)