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