1use cctl_cmds::L1D_VA_LOCK;
4
5use crate::register;
6use crate::riscv;
7
8pub mod cctl_cmds {
10 pub const L1D_VA_INVAL: u8 = 0;
11 pub const L1D_VA_WB: u8 = 1;
12 pub const L1D_VA_WBINVAL: u8 = 2;
13 pub const L1D_VA_LOCK: u8 = 3;
14 pub const L1D_VA_UNLOCK: u8 = 4;
15 pub const L1D_WBINVAL_ALL: u8 = 6;
16 pub const L1D_WB_ALL: u8 = 7;
17
18 pub const L1I_VA_INVAL: u8 = 8;
19 pub const L1I_VA_LOCK: u8 = 11;
20 pub const L1I_VA_UNLOCK: u8 = 12;
21
22 pub const L1D_IX_INVAL: u8 = 16;
23 pub const L1D_IX_WB: u8 = 17;
24 pub const L1D_IX_WBINVAL: u8 = 18;
25
26 pub const L1D_IX_RTAG: u8 = 19;
27 pub const L1D_IX_RDATA: u8 = 20;
28 pub const L1D_IX_WTAG: u8 = 21;
29 pub const L1D_IX_WDATA: u8 = 22;
30
31 pub const L1D_INVAL_ALL: u8 = 23;
32
33 pub const L1I_IX_INVAL: u8 = 24;
34 pub const L1I_IX_RTAG: u8 = 27;
35 pub const L1I_IX_RDATA: u8 = 28;
36 pub const L1I_IX_WTAG: u8 = 29;
37 pub const L1I_IX_WDATA: u8 = 30;
38}
39
40#[inline(always)]
41pub fn dc_is_enabled() -> bool {
42 register::mcache_ctl().read().dc_en()
43}
44
45#[inline(always)]
46pub fn ic_is_enabled() -> bool {
47 register::mcache_ctl().read().ic_en()
48}
49
50#[inline(always)]
51pub unsafe fn dc_enable() {
52 if !dc_is_enabled() {
53 register::mcache_ctl().modify(|w| w.set_dc_warnd(0b11));
54 register::mcache_ctl().modify(|w| {
55 w.set_dpref_en(true);
57 w.set_dc_en(true);
58 });
59 }
60}
61
62#[inline(always)]
63pub unsafe fn dc_disable() {
64 if dc_is_enabled() {
65 register::mcache_ctl().modify(|w| w.set_dc_en(false));
66 }
67}
68
69#[inline(always)]
70pub unsafe fn ic_enable() {
71 if !ic_is_enabled() {
72 register::mcache_ctl().modify(|w| {
73 w.set_ic_en(true);
74 w.set_ipref_en(true);
75 w.set_cctl_suen(true);
76 });
77 }
78}
79
80#[inline(always)]
81pub unsafe fn ic_disable() {
82 if ic_is_enabled() {
83 register::mcache_ctl().modify(|w| w.set_ic_en(false));
84 }
85}
86
87#[inline(always)]
88pub unsafe fn dc_invalidate_all() {
89 register::mcctlcommand().write_value(cctl_cmds::L1D_INVAL_ALL as u32);
90}
91
92#[inline(always)]
93pub unsafe fn dc_writeback_all() {
94 register::mcctlcommand().write_value(cctl_cmds::L1D_WB_ALL as u32);
95}
96
97#[inline(always)]
98pub unsafe fn dc_flush_all() {
99 register::mcctlcommand().write_value(cctl_cmds::L1D_WBINVAL_ALL as u32);
100}
101
102#[inline(always)]
103fn cctl_get_address() -> u32 {
104 register::mcctlbeginaddr().read()
105}
106
107fn cacheline_size() -> u32 {
109 let dsz = register::mdcm_cfg().read().dsz();
110 match dsz {
111 0 => 0,
112 1 => 8,
113 2 => 16,
114 3 => 32,
115 4 => 64,
116 5 => 128,
117 _ => 0,
118 }
119}
120
121pub unsafe fn l1c_op(opcode: u8, address: u32, size: u32) {
122 let mstatus = riscv::register::mstatus::read();
123 if mstatus.mie() {
124 riscv::register::mstatus::clear_mie();
125 }
126
127 let ver = register::mmsc_cfg().read().vcctl();
128
129 if ver != 0 {
130 register::mcctlbeginaddr().write_value(address);
131 let mut next_address = address;
132
133 while next_address < address + size && next_address >= address {
134 register::mcctlcommand().write_value(opcode as u32);
135 next_address = cctl_get_address();
136 }
137 } else {
138 let cl_size = cacheline_size();
139 if cl_size == 0 {
140 return;
141 }
142 let mut i = 0;
143 while i < size {
144 register::mcctlbeginaddr().write_value(address + i);
145 register::mcctlcommand().write_value(opcode as u32);
146 i += cl_size;
147 }
148 }
149
150 if mstatus.mie() {
151 riscv::register::mstatus::set_mie();
152 }
153}
154
155fn check_addr_size(address: u32, size: u32) {
156 let cl_sz = cacheline_size();
157
158 assert!(
159 address % cl_sz == 0,
160 "address must be aligned to cacheline size"
161 );
162 assert!(size % cl_sz == 0, "size must be multiple of cacheline size");
163}
164
165pub unsafe fn dc_fill_lock(address: u32, size: u32) {
166 check_addr_size(address, size);
167 l1c_op(L1D_VA_LOCK, address, size);
168}
169
170pub unsafe fn dc_invalidate(address: u32, size: u32) {
171 check_addr_size(address, size);
172 l1c_op(cctl_cmds::L1D_VA_INVAL, address, size);
173}
174
175pub unsafe fn dc_writeback(address: u32, size: u32) {
176 check_addr_size(address, size);
177 l1c_op(cctl_cmds::L1D_VA_WB, address, size);
178}
179
180pub unsafe fn dc_flush(address: u32, size: u32) {
181 check_addr_size(address, size);
182 l1c_op(cctl_cmds::L1D_VA_WBINVAL, address, size);
183}
184
185pub unsafe fn ic_invalidate(address: u32, size: u32) {
186 check_addr_size(address, size);
187 l1c_op(cctl_cmds::L1I_VA_INVAL, address, size);
188}
189
190pub unsafe fn ic_fill_lock(address: u32, size: u32) {
191 check_addr_size(address, size);
192 l1c_op(cctl_cmds::L1I_VA_LOCK, address, size);
193}
194
195#[inline]
196pub fn cacheline_align_down(addr: u32) -> u32 {
197 addr & !(cacheline_size() - 1)
198}
199
200#[inline]
201pub fn cacheline_align_up(addr: u32) -> u32 {
202 cacheline_align_down(addr + cacheline_size() - 1)
203}