1 #ifndef _METAG_L2CACHE_H
2 #define _METAG_L2CACHE_H
3 
4 #ifdef CONFIG_METAG_L2C
5 
6 #include <asm/global_lock.h>
7 #include <asm/io.h>
8 
9 /*
10  * Store the last known value of pfenable (we don't want prefetch enabled while
11  * L2 is off).
12  */
13 extern int l2c_pfenable;
14 
15 /* defined in arch/metag/drivers/core-sysfs.c */
16 extern struct sysdev_class cache_sysclass;
17 
18 static inline void wr_fence(void);
19 
20 /*
21  * Functions for reading of L2 cache configuration.
22  */
23 
24 /* Get raw L2 config register (CORE_CONFIG3) */
meta_l2c_config(void)25 static inline unsigned int meta_l2c_config(void)
26 {
27 	const unsigned int *corecfg3 = (const unsigned int *)METAC_CORE_CONFIG3;
28 	return *corecfg3;
29 }
30 
31 /* Get whether the L2 is present */
meta_l2c_is_present(void)32 static inline int meta_l2c_is_present(void)
33 {
34 	return meta_l2c_config() & METAC_CORECFG3_L2C_HAVE_L2C_BIT;
35 }
36 
37 /* Get whether the L2 is configured for write-back instead of write-through */
meta_l2c_is_writeback(void)38 static inline int meta_l2c_is_writeback(void)
39 {
40 	return meta_l2c_config() & METAC_CORECFG3_L2C_MODE_BIT;
41 }
42 
43 /* Get whether the L2 is unified instead of separated code/data */
meta_l2c_is_unified(void)44 static inline int meta_l2c_is_unified(void)
45 {
46 	return meta_l2c_config() & METAC_CORECFG3_L2C_UNIFIED_BIT;
47 }
48 
49 /* Get the L2 cache size in bytes */
meta_l2c_size(void)50 static inline unsigned int meta_l2c_size(void)
51 {
52 	unsigned int size_s;
53 	if (!meta_l2c_is_present())
54 		return 0;
55 	size_s = (meta_l2c_config() & METAC_CORECFG3_L2C_SIZE_BITS)
56 			>> METAC_CORECFG3_L2C_SIZE_S;
57 	/* L2CSIZE is in KiB */
58 	return 1024 << size_s;
59 }
60 
61 /* Get the number of ways in the L2 cache */
meta_l2c_ways(void)62 static inline unsigned int meta_l2c_ways(void)
63 {
64 	unsigned int ways_s;
65 	if (!meta_l2c_is_present())
66 		return 0;
67 	ways_s = (meta_l2c_config() & METAC_CORECFG3_L2C_NUM_WAYS_BITS)
68 			>> METAC_CORECFG3_L2C_NUM_WAYS_S;
69 	return 0x1 << ways_s;
70 }
71 
72 /* Get the line size of the L2 cache */
meta_l2c_linesize(void)73 static inline unsigned int meta_l2c_linesize(void)
74 {
75 	unsigned int line_size;
76 	if (!meta_l2c_is_present())
77 		return 0;
78 	line_size = (meta_l2c_config() & METAC_CORECFG3_L2C_LINE_SIZE_BITS)
79 			>> METAC_CORECFG3_L2C_LINE_SIZE_S;
80 	switch (line_size) {
81 	case METAC_CORECFG3_L2C_LINE_SIZE_64B:
82 		return 64;
83 	default:
84 		return 0;
85 	}
86 }
87 
88 /* Get the revision ID of the L2 cache */
meta_l2c_revision(void)89 static inline unsigned int meta_l2c_revision(void)
90 {
91 	return (meta_l2c_config() & METAC_CORECFG3_L2C_REV_ID_BITS)
92 			>> METAC_CORECFG3_L2C_REV_ID_S;
93 }
94 
95 
96 /*
97  * Start an initialisation of the L2 cachelines and wait for completion.
98  * This should only be done in a LOCK1 or LOCK2 critical section while the L2
99  * is disabled.
100  */
_meta_l2c_init(void)101 static inline void _meta_l2c_init(void)
102 {
103 	metag_out32(SYSC_L2C_INIT_INIT, SYSC_L2C_INIT);
104 	while (metag_in32(SYSC_L2C_INIT) == SYSC_L2C_INIT_IN_PROGRESS)
105 		/* do nothing */;
106 }
107 
108 /*
109  * Start a writeback of dirty L2 cachelines and wait for completion.
110  * This should only be done in a LOCK1 or LOCK2 critical section.
111  */
_meta_l2c_purge(void)112 static inline void _meta_l2c_purge(void)
113 {
114 	metag_out32(SYSC_L2C_PURGE_PURGE, SYSC_L2C_PURGE);
115 	while (metag_in32(SYSC_L2C_PURGE) == SYSC_L2C_PURGE_IN_PROGRESS)
116 		/* do nothing */;
117 }
118 
119 /* Set whether the L2 cache is enabled. */
_meta_l2c_enable(int enabled)120 static inline void _meta_l2c_enable(int enabled)
121 {
122 	unsigned int enable;
123 
124 	enable = metag_in32(SYSC_L2C_ENABLE);
125 	if (enabled)
126 		enable |= SYSC_L2C_ENABLE_ENABLE_BIT;
127 	else
128 		enable &= ~SYSC_L2C_ENABLE_ENABLE_BIT;
129 	metag_out32(enable, SYSC_L2C_ENABLE);
130 }
131 
132 /* Set whether the L2 cache prefetch is enabled. */
_meta_l2c_pf_enable(int pfenabled)133 static inline void _meta_l2c_pf_enable(int pfenabled)
134 {
135 	unsigned int enable;
136 
137 	enable = metag_in32(SYSC_L2C_ENABLE);
138 	if (pfenabled)
139 		enable |= SYSC_L2C_ENABLE_PFENABLE_BIT;
140 	else
141 		enable &= ~SYSC_L2C_ENABLE_PFENABLE_BIT;
142 	metag_out32(enable, SYSC_L2C_ENABLE);
143 }
144 
145 /* Return whether the L2 cache is enabled */
_meta_l2c_is_enabled(void)146 static inline int _meta_l2c_is_enabled(void)
147 {
148 	return metag_in32(SYSC_L2C_ENABLE) & SYSC_L2C_ENABLE_ENABLE_BIT;
149 }
150 
151 /* Return whether the L2 cache prefetch is enabled */
_meta_l2c_pf_is_enabled(void)152 static inline int _meta_l2c_pf_is_enabled(void)
153 {
154 	return metag_in32(SYSC_L2C_ENABLE) & SYSC_L2C_ENABLE_PFENABLE_BIT;
155 }
156 
157 
158 /* Return whether the L2 cache is enabled */
meta_l2c_is_enabled(void)159 static inline int meta_l2c_is_enabled(void)
160 {
161 	int en;
162 
163 	/*
164 	 * There is no need to lock at the moment, as the enable bit is never
165 	 * intermediately changed, so we will never see an intermediate result.
166 	 */
167 	en = _meta_l2c_is_enabled();
168 
169 	return en;
170 }
171 
172 /*
173  * Ensure the L2 cache is disabled.
174  * Return whether the L2 was previously disabled.
175  */
176 int meta_l2c_disable(void);
177 
178 /*
179  * Ensure the L2 cache is enabled.
180  * Return whether the L2 was previously enabled.
181  */
182 int meta_l2c_enable(void);
183 
184 /* Return whether the L2 cache prefetch is enabled */
meta_l2c_pf_is_enabled(void)185 static inline int meta_l2c_pf_is_enabled(void)
186 {
187 	return l2c_pfenable;
188 }
189 
190 /*
191  * Set whether the L2 cache prefetch is enabled.
192  * Return whether the L2 prefetch was previously enabled.
193  */
194 int meta_l2c_pf_enable(int pfenable);
195 
196 /*
197  * Flush the L2 cache.
198  * Return 1 if the L2 is disabled.
199  */
200 int meta_l2c_flush(void);
201 
202 /*
203  * Write back all dirty cache lines in the L2 cache.
204  * Return 1 if the L2 is disabled or there isn't any writeback.
205  */
meta_l2c_writeback(void)206 static inline int meta_l2c_writeback(void)
207 {
208 	unsigned long flags;
209 	int en;
210 
211 	/* no need to purge if it's not a writeback cache */
212 	if (!meta_l2c_is_writeback())
213 		return 1;
214 
215 	/*
216 	 * Purge only works if the L2 is enabled, and involves reading back to
217 	 * detect completion, so keep this operation atomic with other threads.
218 	 */
219 	__global_lock1(flags);
220 	en = meta_l2c_is_enabled();
221 	if (likely(en)) {
222 		wr_fence();
223 		_meta_l2c_purge();
224 	}
225 	__global_unlock1(flags);
226 
227 	return !en;
228 }
229 
230 #else /* CONFIG_METAG_L2C */
231 
232 #define meta_l2c_config()		0
233 #define meta_l2c_is_present()		0
234 #define meta_l2c_is_writeback()		0
235 #define meta_l2c_is_unified()		0
236 #define meta_l2c_size()			0
237 #define meta_l2c_ways()			0
238 #define meta_l2c_linesize()		0
239 #define meta_l2c_revision()		0
240 
241 #define meta_l2c_is_enabled()		0
242 #define _meta_l2c_pf_is_enabled()	0
243 #define meta_l2c_pf_is_enabled()	0
244 #define meta_l2c_disable()		1
245 #define meta_l2c_enable()		0
246 #define meta_l2c_pf_enable(X)		0
meta_l2c_flush(void)247 static inline int meta_l2c_flush(void)
248 {
249 	return 1;
250 }
meta_l2c_writeback(void)251 static inline int meta_l2c_writeback(void)
252 {
253 	return 1;
254 }
255 
256 #endif /* CONFIG_METAG_L2C */
257 
258 #endif /* _METAG_L2CACHE_H */
259