1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-01-29 lizhirui first version
9 * 2021-11-05 JasonHu add C908 cache inst
10 * 2022-11-09 WangXiaoyao Support cache coherence operations;
11 * improve portability and make
12 * no assumption on undefined behavior
13 */
14
15 #include <rthw.h>
16 #include <rtdef.h>
17 #include <board.h>
18 #include <riscv.h>
19
20 #include "opcode.h"
21 #include "cache.h"
22
23 #define L1_CACHE_BYTES (64)
24
25 /**
26 * GCC version not support t-head cache flush, so we use fixed code to achieve.
27 * The following function cannot be optimized.
28 */
29 static void dcache_wb_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
30 static void dcache_inv_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
31 static void dcache_wbinv_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
32 static void icache_inv_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
33
34 #define CACHE_OP_RS1 %0
35 #define CACHE_OP_RANGE(instr) \
36 { \
37 rt_ubase_t i = start & ~(L1_CACHE_BYTES - 1); \
38 for (; i < end; i += L1_CACHE_BYTES) \
39 { \
40 __asm__ volatile(instr ::"r"(i) \
41 : "memory"); \
42 } \
43 }
44
dcache_wb_range(unsigned long start,unsigned long end)45 static void dcache_wb_range(unsigned long start, unsigned long end)
46 {
47 CACHE_OP_RANGE(OPC_DCACHE_CVA(CACHE_OP_RS1));
48 }
49
dcachel1_wb_range(unsigned long start,unsigned long end)50 static void dcachel1_wb_range(unsigned long start, unsigned long end)
51 {
52 CACHE_OP_RANGE(OPC_DCACHE_CVAL1(CACHE_OP_RS1));
53 }
54
dcache_inv_range(unsigned long start,unsigned long end)55 static void dcache_inv_range(unsigned long start, unsigned long end)
56 {
57 CACHE_OP_RANGE(OPC_DCACHE_IVA(CACHE_OP_RS1));
58 }
59
dcache_wbinv_range(unsigned long start,unsigned long end)60 static void dcache_wbinv_range(unsigned long start, unsigned long end)
61 {
62 CACHE_OP_RANGE(OPC_DCACHE_CIVA(CACHE_OP_RS1));
63 }
64
icache_inv_range(unsigned long start,unsigned long end)65 static void icache_inv_range(unsigned long start, unsigned long end)
66 {
67 CACHE_OP_RANGE(OPC_ICACHE_IVA(CACHE_OP_RS1));
68 }
69
rt_cpu_icache_line_size(void)70 rt_inline rt_uint32_t rt_cpu_icache_line_size(void)
71 {
72 return L1_CACHE_BYTES;
73 }
74
rt_cpu_dcache_line_size(void)75 rt_inline rt_uint32_t rt_cpu_dcache_line_size(void)
76 {
77 return L1_CACHE_BYTES;
78 }
79
rt_hw_cpu_icache_invalidate_local(void * addr,int size)80 void rt_hw_cpu_icache_invalidate_local(void *addr, int size)
81 {
82 icache_inv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
83 rt_hw_cpu_sync_i();
84 }
85
rt_hw_cpu_dcache_invalidate_local(void * addr,int size)86 void rt_hw_cpu_dcache_invalidate_local(void *addr, int size)
87 {
88 dcache_inv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
89 rt_hw_cpu_sync();
90 }
91
rt_hw_cpu_dcache_clean_local(void * addr,int size)92 void rt_hw_cpu_dcache_clean_local(void *addr, int size)
93 {
94 dcache_wb_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
95 rt_hw_cpu_sync();
96 }
97
rt_hw_cpu_dcache_clean_invalidate_local(void * addr,int size)98 void rt_hw_cpu_dcache_clean_invalidate_local(void *addr, int size)
99 {
100 dcache_wbinv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
101 rt_hw_cpu_sync();
102 }
103
rt_hw_cpu_dcachel1_clean_local(void * addr,int size)104 void rt_hw_cpu_dcachel1_clean_local(void *addr, int size)
105 {
106 __asm__ volatile(OPC_DCACHE_CVAL1(a0)::
107 : "memory");
108 }
109
110 /**
111 * =====================================================
112 * Architecture Independent API
113 * =====================================================
114 */
115
rt_hw_cpu_icache_ops(int ops,void * addr,int size)116 void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
117 {
118 if (ops == RT_HW_CACHE_INVALIDATE)
119 {
120 rt_hw_cpu_icache_invalidate(addr, size);
121 }
122 }
123
rt_hw_cpu_dcache_ops(int ops,void * addr,int size)124 void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
125 {
126 if (ops == RT_HW_CACHE_FLUSH)
127 {
128 rt_hw_cpu_dcache_clean(addr, size);
129 }
130 else
131 {
132 rt_hw_cpu_dcache_invalidate(addr, size);
133 }
134 }
135
rt_hw_sync_cache_local(void * addr,int size)136 void rt_hw_sync_cache_local(void *addr, int size)
137 {
138 rt_hw_cpu_dcachel1_clean_local(addr, size);
139 rt_hw_cpu_icache_invalidate_local(addr, size);
140 }
141