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 c906 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 register 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
dcache_inv_range(unsigned long start,unsigned long end)50 static void dcache_inv_range(unsigned long start, unsigned long end)
51 {
52 CACHE_OP_RANGE(OPC_DCACHE_IVA(CACHE_OP_RS1));
53 }
54
dcache_wbinv_range(unsigned long start,unsigned long end)55 static void dcache_wbinv_range(unsigned long start, unsigned long end)
56 {
57 CACHE_OP_RANGE(OPC_DCACHE_CIVA(CACHE_OP_RS1));
58 }
59
icache_inv_range(unsigned long start,unsigned long end)60 static void icache_inv_range(unsigned long start, unsigned long end)
61 {
62 CACHE_OP_RANGE(OPC_ICACHE_IVA(CACHE_OP_RS1));
63 }
64
rt_cpu_icache_line_size(void)65 rt_inline rt_uint32_t rt_cpu_icache_line_size(void)
66 {
67 return L1_CACHE_BYTES;
68 }
69
rt_cpu_dcache_line_size(void)70 rt_inline rt_uint32_t rt_cpu_dcache_line_size(void)
71 {
72 return L1_CACHE_BYTES;
73 }
74
rt_hw_cpu_icache_invalidate_local(void * addr,int size)75 void rt_hw_cpu_icache_invalidate_local(void *addr, int size)
76 {
77 icache_inv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
78 rt_hw_cpu_sync_i();
79 }
80
rt_hw_cpu_dcache_invalidate_local(void * addr,int size)81 void rt_hw_cpu_dcache_invalidate_local(void *addr, int size)
82 {
83 dcache_inv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
84 rt_hw_cpu_sync();
85 }
86
rt_hw_cpu_dcache_clean_local(void * addr,int size)87 void rt_hw_cpu_dcache_clean_local(void *addr, int size)
88 {
89 dcache_wb_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
90 rt_hw_cpu_sync();
91 }
92
rt_hw_cpu_dcache_clean_and_invalidate_local(void * addr,int size)93 void rt_hw_cpu_dcache_clean_and_invalidate_local(void *addr, int size)
94 {
95 dcache_wbinv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
96 rt_hw_cpu_sync();
97 }
98
99 /**
100 * =====================================================
101 * Architecture Independent API
102 * =====================================================
103 */
104
rt_hw_cpu_icache_ops(int ops,void * addr,int size)105 void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
106 {
107 if (ops == RT_HW_CACHE_INVALIDATE)
108 {
109 rt_hw_cpu_icache_invalidate_local(addr, size);
110 }
111 }
112
rt_hw_cpu_dcache_ops(int ops,void * addr,int size)113 void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
114 {
115 if (ops == RT_HW_CACHE_FLUSH)
116 {
117 rt_hw_cpu_dcache_clean_local(addr, size);
118 }
119 else
120 {
121 rt_hw_cpu_dcache_invalidate_local(addr, size);
122 }
123 }
124
rt_hw_sync_cache_local(void * addr,int size)125 void rt_hw_sync_cache_local(void *addr, int size)
126 {
127 rt_hw_cpu_dcache_clean_local(addr, size);
128 rt_hw_cpu_icache_invalidate_local(addr, size);
129 }
130