1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2017 Andes Technology Corporation
4 * Rick Chen, Andes Technology Corporation <rick@andestech.com>
5 */
6
7 #include <cpu_func.h>
8 #include <dm.h>
9 #include <asm/insn-def.h>
10 #include <linux/const.h>
11 #include <linux/errno.h>
12
13 #define CBO_INVAL(base) \
14 INSN_I(OPCODE_MISC_MEM, FUNC3(2), __RD(0), \
15 RS1(base), SIMM12(0))
16 #define CBO_CLEAN(base) \
17 INSN_I(OPCODE_MISC_MEM, FUNC3(2), __RD(0), \
18 RS1(base), SIMM12(1))
19 #define CBO_FLUSH(base) \
20 INSN_I(OPCODE_MISC_MEM, FUNC3(2), __RD(0), \
21 RS1(base), SIMM12(2))
22 enum {
23 CBO_CLEAN,
24 CBO_FLUSH,
25 CBO_INVAL
26 } riscv_cbo_ops;
27 static int zicbom_block_size;
28 extern unsigned int riscv_get_cbom_block_size(void);
do_cbo_clean(unsigned long base)29 static inline void do_cbo_clean(unsigned long base)
30 {
31 asm volatile ("add a0, %0, zero\n" CBO_CLEAN(%0) ::
32 "r"(base) : "memory");
33 }
34
do_cbo_flush(unsigned long base)35 static inline void do_cbo_flush(unsigned long base)
36 {
37 asm volatile ("add a0, %0, zero\n" CBO_FLUSH(%0) ::
38 "r"(base) : "memory");
39 }
40
do_cbo_inval(unsigned long base)41 static inline void do_cbo_inval(unsigned long base)
42 {
43 asm volatile ("add a0, %0, zero\n" CBO_INVAL(%0) ::
44 "r"(base) : "memory");
45 }
46
cbo_op(int op_type,unsigned long start,unsigned long end)47 static void cbo_op(int op_type, unsigned long start,
48 unsigned long end)
49 {
50 unsigned long op_size = end - start, size = 0;
51 void (*fn)(unsigned long base);
52
53 switch (op_type) {
54 case CBO_CLEAN:
55 fn = do_cbo_clean;
56 break;
57 case CBO_FLUSH:
58 fn = do_cbo_flush;
59 break;
60 case CBO_INVAL:
61 fn = do_cbo_inval;
62 break;
63 }
64 start &= ~(UL(zicbom_block_size - 1));
65 while (size < op_size) {
66 fn(start + size);
67 size += zicbom_block_size;
68 }
69 }
70
cbo_flush(unsigned long start,unsigned long end)71 void cbo_flush(unsigned long start, unsigned long end)
72 {
73 if (zicbom_block_size)
74 cbo_op(CBO_FLUSH, start, end);
75 }
76
cbo_inval(unsigned long start,unsigned long end)77 void cbo_inval(unsigned long start, unsigned long end)
78 {
79 if (zicbom_block_size)
80 cbo_op(CBO_INVAL, start, end);
81 }
82
invalidate_icache_all(void)83 void invalidate_icache_all(void)
84 {
85 asm volatile ("fence.i" ::: "memory");
86 }
87
flush_dcache_all(void)88 __weak void flush_dcache_all(void)
89 {
90 }
91
flush_dcache_range(unsigned long start,unsigned long end)92 __weak void flush_dcache_range(unsigned long start, unsigned long end)
93 {
94 cbo_flush(start, end);
95 }
96
invalidate_icache_range(unsigned long start,unsigned long end)97 __weak void invalidate_icache_range(unsigned long start, unsigned long end)
98 {
99 /*
100 * RISC-V does not have an instruction for invalidating parts of the
101 * instruction cache. Invalidate all of it instead.
102 */
103 invalidate_icache_all();
104 }
105
invalidate_dcache_range(unsigned long start,unsigned long end)106 __weak void invalidate_dcache_range(unsigned long start, unsigned long end)
107 {
108 cbo_inval(start, end);
109 }
110
cache_flush(void)111 void cache_flush(void)
112 {
113 invalidate_icache_all();
114 flush_dcache_all();
115 }
116
flush_cache(unsigned long addr,unsigned long size)117 void flush_cache(unsigned long addr, unsigned long size)
118 {
119 invalidate_icache_range(addr, addr + size);
120 flush_dcache_range(addr, addr + size);
121 }
122
icache_enable(void)123 __weak void icache_enable(void)
124 {
125 }
126
icache_disable(void)127 __weak void icache_disable(void)
128 {
129 }
130
icache_status(void)131 __weak int icache_status(void)
132 {
133 return 0;
134 }
135
dcache_enable(void)136 __weak void dcache_enable(void)
137 {
138 }
139
dcache_disable(void)140 __weak void dcache_disable(void)
141 {
142 }
143
dcache_status(void)144 __weak int dcache_status(void)
145 {
146 return 0;
147 }
148
enable_caches(void)149 __weak void enable_caches(void)
150 {
151 zicbom_block_size = riscv_get_cbom_block_size();
152 if (!zicbom_block_size)
153 log_debug("Zicbom not initialized.\n");
154 }
155
pgprot_set_attrs(phys_addr_t addr,size_t size,enum pgprot_attrs perm)156 int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, enum pgprot_attrs perm)
157 {
158 return -ENOSYS;
159 }
160