xref: /openbmc/linux/arch/microblaze/kernel/cpu/cache.c (revision 061d2c1d)
18beb8503SMichal Simek /*
28beb8503SMichal Simek  * Cache control for MicroBlaze cache memories
38beb8503SMichal Simek  *
48beb8503SMichal Simek  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
58beb8503SMichal Simek  * Copyright (C) 2007-2009 PetaLogix
62ee2ff87SMichal Simek  * Copyright (C) 2007-2009 John Williams <john.williams@petalogix.com>
78beb8503SMichal Simek  *
88beb8503SMichal Simek  * This file is subject to the terms and conditions of the GNU General
98beb8503SMichal Simek  * Public License. See the file COPYING in the main directory of this
108beb8503SMichal Simek  * archive for more details.
118beb8503SMichal Simek  */
128beb8503SMichal Simek 
138beb8503SMichal Simek #include <asm/cacheflush.h>
148beb8503SMichal Simek #include <linux/cache.h>
158beb8503SMichal Simek #include <asm/cpuinfo.h>
162ee2ff87SMichal Simek #include <asm/pvr.h>
178beb8503SMichal Simek 
__enable_icache_msr(void)182ee2ff87SMichal Simek static inline void __enable_icache_msr(void)
192ee2ff87SMichal Simek {
206bd55f0bSMichal Simek 	__asm__ __volatile__ ("	 msrset	r0, %0;"	\
216bd55f0bSMichal Simek 				"nop;"			\
222ee2ff87SMichal Simek 			: : "i" (MSR_ICE) : "memory");
232ee2ff87SMichal Simek }
242ee2ff87SMichal Simek 
__disable_icache_msr(void)252ee2ff87SMichal Simek static inline void __disable_icache_msr(void)
262ee2ff87SMichal Simek {
276bd55f0bSMichal Simek 	__asm__ __volatile__ ("	 msrclr	r0, %0;"	\
286bd55f0bSMichal Simek 				"nop;"			\
292ee2ff87SMichal Simek 			: : "i" (MSR_ICE) : "memory");
302ee2ff87SMichal Simek }
312ee2ff87SMichal Simek 
__enable_dcache_msr(void)322ee2ff87SMichal Simek static inline void __enable_dcache_msr(void)
332ee2ff87SMichal Simek {
346bd55f0bSMichal Simek 	__asm__ __volatile__ ("	 msrset	r0, %0;"	\
356bd55f0bSMichal Simek 				"nop;"			\
366bd55f0bSMichal Simek 			: : "i" (MSR_DCE) : "memory");
372ee2ff87SMichal Simek }
382ee2ff87SMichal Simek 
__disable_dcache_msr(void)392ee2ff87SMichal Simek static inline void __disable_dcache_msr(void)
402ee2ff87SMichal Simek {
416bd55f0bSMichal Simek 	__asm__ __volatile__ ("	 msrclr	r0, %0;"	\
426bd55f0bSMichal Simek 				"nop; "			\
436bd55f0bSMichal Simek 			: : "i" (MSR_DCE) : "memory");
442ee2ff87SMichal Simek }
452ee2ff87SMichal Simek 
__enable_icache_nomsr(void)462ee2ff87SMichal Simek static inline void __enable_icache_nomsr(void)
472ee2ff87SMichal Simek {
486bd55f0bSMichal Simek 	__asm__ __volatile__ ("	 mfs	r12, rmsr;"	\
496bd55f0bSMichal Simek 				"nop;"			\
506bd55f0bSMichal Simek 				"ori	r12, r12, %0;"	\
516bd55f0bSMichal Simek 				"mts	rmsr, r12;"	\
526bd55f0bSMichal Simek 				"nop;"			\
536bd55f0bSMichal Simek 			: : "i" (MSR_ICE) : "memory", "r12");
548beb8503SMichal Simek }
558beb8503SMichal Simek 
__disable_icache_nomsr(void)562ee2ff87SMichal Simek static inline void __disable_icache_nomsr(void)
578beb8503SMichal Simek {
586bd55f0bSMichal Simek 	__asm__ __volatile__ ("	 mfs	r12, rmsr;"	\
596bd55f0bSMichal Simek 				"nop;"			\
606bd55f0bSMichal Simek 				"andi	r12, r12, ~%0;"	\
616bd55f0bSMichal Simek 				"mts	rmsr, r12;"	\
626bd55f0bSMichal Simek 				"nop;"			\
636bd55f0bSMichal Simek 			: : "i" (MSR_ICE) : "memory", "r12");
648beb8503SMichal Simek }
658beb8503SMichal Simek 
__enable_dcache_nomsr(void)662ee2ff87SMichal Simek static inline void __enable_dcache_nomsr(void)
678beb8503SMichal Simek {
686bd55f0bSMichal Simek 	__asm__ __volatile__ ("	 mfs	r12, rmsr;"	\
696bd55f0bSMichal Simek 				"nop;"			\
706bd55f0bSMichal Simek 				"ori	r12, r12, %0;"	\
716bd55f0bSMichal Simek 				"mts	rmsr, r12;"	\
726bd55f0bSMichal Simek 				"nop;"			\
736bd55f0bSMichal Simek 			: : "i" (MSR_DCE) : "memory", "r12");
748beb8503SMichal Simek }
758beb8503SMichal Simek 
__disable_dcache_nomsr(void)762ee2ff87SMichal Simek static inline void __disable_dcache_nomsr(void)
778beb8503SMichal Simek {
786bd55f0bSMichal Simek 	__asm__ __volatile__ ("	 mfs	r12, rmsr;"	\
796bd55f0bSMichal Simek 				"nop;"			\
806bd55f0bSMichal Simek 				"andi	r12, r12, ~%0;"	\
816bd55f0bSMichal Simek 				"mts	rmsr, r12;"	\
826bd55f0bSMichal Simek 				"nop;"			\
836bd55f0bSMichal Simek 			: : "i" (MSR_DCE) : "memory", "r12");
842ee2ff87SMichal Simek }
852ee2ff87SMichal Simek 
862ee2ff87SMichal Simek 
873274c570SMichal Simek /* Helper macro for computing the limits of cache range loops
883274c570SMichal Simek  *
893274c570SMichal Simek  * End address can be unaligned which is OK for C implementation.
903274c570SMichal Simek  * ASM implementation align it in ASM macros
913274c570SMichal Simek  */
922ee2ff87SMichal Simek #define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size)	\
932ee2ff87SMichal Simek do {									\
942ee2ff87SMichal Simek 	int align = ~(cache_line_length - 1);				\
95061d2c1dSShubhrajyoti Datta 	if (start <  UINT_MAX - cache_size)				\
962ee2ff87SMichal Simek 		end = min(start + cache_size, end);			\
972ee2ff87SMichal Simek 	start &= align;							\
986bd55f0bSMichal Simek } while (0)
992ee2ff87SMichal Simek 
1002ee2ff87SMichal Simek /*
1012ee2ff87SMichal Simek  * Helper macro to loop over the specified cache_size/line_length and
1022ee2ff87SMichal Simek  * execute 'op' on that cacheline
1032ee2ff87SMichal Simek  */
1042ee2ff87SMichal Simek #define CACHE_ALL_LOOP(cache_size, line_length, op)			\
1052ee2ff87SMichal Simek do {									\
1063274c570SMichal Simek 	unsigned int len = cache_size - line_length;			\
1072ee2ff87SMichal Simek 	int step = -line_length;					\
1083274c570SMichal Simek 	WARN_ON(step >= 0);						\
1092ee2ff87SMichal Simek 									\
1106bd55f0bSMichal Simek 	__asm__ __volatile__ (" 1:      " #op " %0, r0;"		\
1116bd55f0bSMichal Simek 					"bgtid   %0, 1b;"		\
1126bd55f0bSMichal Simek 					"addk    %0, %0, %1;"		\
1136bd55f0bSMichal Simek 					: : "r" (len), "r" (step)	\
1142ee2ff87SMichal Simek 					: "memory");			\
1156bd55f0bSMichal Simek } while (0)
1162ee2ff87SMichal Simek 
1173274c570SMichal Simek /* Used for wdc.flush/clear which can use rB for offset which is not possible
1183274c570SMichal Simek  * to use for simple wdc or wic.
1193274c570SMichal Simek  *
1203274c570SMichal Simek  * start address is cache aligned
12125985edcSLucas De Marchi  * end address is not aligned, if end is aligned then I have to subtract
1223274c570SMichal Simek  * cacheline length because I can't flush/invalidate the next cacheline.
1233274c570SMichal Simek  * If is not, I align it because I will flush/invalidate whole line.
1243274c570SMichal Simek  */
1252ee2ff87SMichal Simek #define CACHE_RANGE_LOOP_2(start, end, line_length, op)			\
1262ee2ff87SMichal Simek do {									\
1272ee2ff87SMichal Simek 	int step = -line_length;					\
1283274c570SMichal Simek 	int align = ~(line_length - 1);					\
129ddfbc935SMichal Simek 	int count;							\
1303274c570SMichal Simek 	end = ((end & align) == end) ? end - line_length : end & align;	\
131ddfbc935SMichal Simek 	count = end - start;						\
1323274c570SMichal Simek 	WARN_ON(count < 0);						\
1332ee2ff87SMichal Simek 									\
1346bd55f0bSMichal Simek 	__asm__ __volatile__ (" 1:	" #op "	%0, %1;"		\
1356bd55f0bSMichal Simek 					"bgtid	%1, 1b;"		\
1366bd55f0bSMichal Simek 					"addk	%1, %1, %2;"		\
1376bd55f0bSMichal Simek 					: : "r" (start), "r" (count),	\
1382ee2ff87SMichal Simek 					"r" (step) : "memory");		\
1396bd55f0bSMichal Simek } while (0)
1402ee2ff87SMichal Simek 
1412ee2ff87SMichal Simek /* It is used only first parameter for OP - for wic, wdc */
1422ee2ff87SMichal Simek #define CACHE_RANGE_LOOP_1(start, end, line_length, op)			\
1432ee2ff87SMichal Simek do {									\
1442558cd8cSMichal Simek 	unsigned int volatile temp = 0;						\
1452558cd8cSMichal Simek 	unsigned int align = ~(line_length - 1);					\
1463274c570SMichal Simek 	end = ((end & align) == end) ? end - line_length : end & align;	\
1472558cd8cSMichal Simek 	WARN_ON(end < start);					\
1482ee2ff87SMichal Simek 									\
1496bd55f0bSMichal Simek 	__asm__ __volatile__ (" 1:	" #op "	%1, r0;"		\
1506bd55f0bSMichal Simek 					"cmpu	%0, %1, %2;"		\
1516bd55f0bSMichal Simek 					"bgtid	%0, 1b;"		\
1526bd55f0bSMichal Simek 					"addk	%1, %1, %3;"		\
1536bd55f0bSMichal Simek 				: : "r" (temp), "r" (start), "r" (end),	\
1540d670b24SMichal Simek 					"r" (line_length) : "memory");	\
1556bd55f0bSMichal Simek } while (0)
1562ee2ff87SMichal Simek 
15722607a28SMichal Simek #define ASM_LOOP
15822607a28SMichal Simek 
__flush_icache_range_msr_irq(unsigned long start,unsigned long end)1592ee2ff87SMichal Simek static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end)
1602ee2ff87SMichal Simek {
1612ee2ff87SMichal Simek 	unsigned long flags;
16222607a28SMichal Simek #ifndef ASM_LOOP
16322607a28SMichal Simek 	int i;
16422607a28SMichal Simek #endif
1652ee2ff87SMichal Simek 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
1662ee2ff87SMichal Simek 				(unsigned int)start, (unsigned int) end);
1672ee2ff87SMichal Simek 
1682ee2ff87SMichal Simek 	CACHE_LOOP_LIMITS(start, end,
1692ee2ff87SMichal Simek 			cpuinfo.icache_line_length, cpuinfo.icache_size);
1702ee2ff87SMichal Simek 
1712ee2ff87SMichal Simek 	local_irq_save(flags);
1722ee2ff87SMichal Simek 	__disable_icache_msr();
1732ee2ff87SMichal Simek 
17422607a28SMichal Simek #ifdef ASM_LOOP
1752ee2ff87SMichal Simek 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
17622607a28SMichal Simek #else
17722607a28SMichal Simek 	for (i = start; i < end; i += cpuinfo.icache_line_length)
17822607a28SMichal Simek 		__asm__ __volatile__ ("wic	%0, r0;"	\
17922607a28SMichal Simek 				: : "r" (i));
18022607a28SMichal Simek #endif
1812ee2ff87SMichal Simek 	__enable_icache_msr();
1822ee2ff87SMichal Simek 	local_irq_restore(flags);
1832ee2ff87SMichal Simek }
1842ee2ff87SMichal Simek 
__flush_icache_range_nomsr_irq(unsigned long start,unsigned long end)1852ee2ff87SMichal Simek static void __flush_icache_range_nomsr_irq(unsigned long start,
1862ee2ff87SMichal Simek 				unsigned long end)
1872ee2ff87SMichal Simek {
1882ee2ff87SMichal Simek 	unsigned long flags;
18922607a28SMichal Simek #ifndef ASM_LOOP
19022607a28SMichal Simek 	int i;
19122607a28SMichal Simek #endif
1922ee2ff87SMichal Simek 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
1932ee2ff87SMichal Simek 				(unsigned int)start, (unsigned int) end);
1942ee2ff87SMichal Simek 
1952ee2ff87SMichal Simek 	CACHE_LOOP_LIMITS(start, end,
1962ee2ff87SMichal Simek 			cpuinfo.icache_line_length, cpuinfo.icache_size);
1972ee2ff87SMichal Simek 
1982ee2ff87SMichal Simek 	local_irq_save(flags);
1992ee2ff87SMichal Simek 	__disable_icache_nomsr();
2002ee2ff87SMichal Simek 
20122607a28SMichal Simek #ifdef ASM_LOOP
2022ee2ff87SMichal Simek 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
20322607a28SMichal Simek #else
20422607a28SMichal Simek 	for (i = start; i < end; i += cpuinfo.icache_line_length)
20522607a28SMichal Simek 		__asm__ __volatile__ ("wic	%0, r0;"	\
20622607a28SMichal Simek 				: : "r" (i));
20722607a28SMichal Simek #endif
2082ee2ff87SMichal Simek 
2092ee2ff87SMichal Simek 	__enable_icache_nomsr();
2102ee2ff87SMichal Simek 	local_irq_restore(flags);
2112ee2ff87SMichal Simek }
2122ee2ff87SMichal Simek 
__flush_icache_range_noirq(unsigned long start,unsigned long end)2132ee2ff87SMichal Simek static void __flush_icache_range_noirq(unsigned long start,
2142ee2ff87SMichal Simek 				unsigned long end)
2152ee2ff87SMichal Simek {
21622607a28SMichal Simek #ifndef ASM_LOOP
21722607a28SMichal Simek 	int i;
21822607a28SMichal Simek #endif
2192ee2ff87SMichal Simek 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
2202ee2ff87SMichal Simek 				(unsigned int)start, (unsigned int) end);
2212ee2ff87SMichal Simek 
2222ee2ff87SMichal Simek 	CACHE_LOOP_LIMITS(start, end,
2232ee2ff87SMichal Simek 			cpuinfo.icache_line_length, cpuinfo.icache_size);
22422607a28SMichal Simek #ifdef ASM_LOOP
2252ee2ff87SMichal Simek 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
22622607a28SMichal Simek #else
22722607a28SMichal Simek 	for (i = start; i < end; i += cpuinfo.icache_line_length)
22822607a28SMichal Simek 		__asm__ __volatile__ ("wic	%0, r0;"	\
22922607a28SMichal Simek 				: : "r" (i));
23022607a28SMichal Simek #endif
2312ee2ff87SMichal Simek }
2322ee2ff87SMichal Simek 
__flush_icache_all_msr_irq(void)2332ee2ff87SMichal Simek static void __flush_icache_all_msr_irq(void)
2342ee2ff87SMichal Simek {
2352ee2ff87SMichal Simek 	unsigned long flags;
23622607a28SMichal Simek #ifndef ASM_LOOP
23722607a28SMichal Simek 	int i;
23822607a28SMichal Simek #endif
2392ee2ff87SMichal Simek 	pr_debug("%s\n", __func__);
2402ee2ff87SMichal Simek 
2412ee2ff87SMichal Simek 	local_irq_save(flags);
2422ee2ff87SMichal Simek 	__disable_icache_msr();
24322607a28SMichal Simek #ifdef ASM_LOOP
2442ee2ff87SMichal Simek 	CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
24522607a28SMichal Simek #else
24622607a28SMichal Simek 	for (i = 0; i < cpuinfo.icache_size;
24722607a28SMichal Simek 		 i += cpuinfo.icache_line_length)
24822607a28SMichal Simek 			__asm__ __volatile__ ("wic	%0, r0;" \
24922607a28SMichal Simek 					: : "r" (i));
25022607a28SMichal Simek #endif
2512ee2ff87SMichal Simek 	__enable_icache_msr();
2522ee2ff87SMichal Simek 	local_irq_restore(flags);
2532ee2ff87SMichal Simek }
2542ee2ff87SMichal Simek 
__flush_icache_all_nomsr_irq(void)2552ee2ff87SMichal Simek static void __flush_icache_all_nomsr_irq(void)
2562ee2ff87SMichal Simek {
2572ee2ff87SMichal Simek 	unsigned long flags;
25822607a28SMichal Simek #ifndef ASM_LOOP
25922607a28SMichal Simek 	int i;
26022607a28SMichal Simek #endif
2612ee2ff87SMichal Simek 	pr_debug("%s\n", __func__);
2622ee2ff87SMichal Simek 
2632ee2ff87SMichal Simek 	local_irq_save(flags);
2642ee2ff87SMichal Simek 	__disable_icache_nomsr();
26522607a28SMichal Simek #ifdef ASM_LOOP
2662ee2ff87SMichal Simek 	CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
26722607a28SMichal Simek #else
26822607a28SMichal Simek 	for (i = 0; i < cpuinfo.icache_size;
26922607a28SMichal Simek 		 i += cpuinfo.icache_line_length)
27022607a28SMichal Simek 			__asm__ __volatile__ ("wic	%0, r0;" \
27122607a28SMichal Simek 					: : "r" (i));
27222607a28SMichal Simek #endif
2732ee2ff87SMichal Simek 	__enable_icache_nomsr();
2742ee2ff87SMichal Simek 	local_irq_restore(flags);
2752ee2ff87SMichal Simek }
2762ee2ff87SMichal Simek 
__flush_icache_all_noirq(void)2772ee2ff87SMichal Simek static void __flush_icache_all_noirq(void)
2782ee2ff87SMichal Simek {
27922607a28SMichal Simek #ifndef ASM_LOOP
28022607a28SMichal Simek 	int i;
28122607a28SMichal Simek #endif
2822ee2ff87SMichal Simek 	pr_debug("%s\n", __func__);
28322607a28SMichal Simek #ifdef ASM_LOOP
2842ee2ff87SMichal Simek 	CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
28522607a28SMichal Simek #else
28622607a28SMichal Simek 	for (i = 0; i < cpuinfo.icache_size;
28722607a28SMichal Simek 		 i += cpuinfo.icache_line_length)
28822607a28SMichal Simek 			__asm__ __volatile__ ("wic	%0, r0;" \
28922607a28SMichal Simek 					: : "r" (i));
29022607a28SMichal Simek #endif
2912ee2ff87SMichal Simek }
2922ee2ff87SMichal Simek 
__invalidate_dcache_all_msr_irq(void)2932ee2ff87SMichal Simek static void __invalidate_dcache_all_msr_irq(void)
2942ee2ff87SMichal Simek {
2952ee2ff87SMichal Simek 	unsigned long flags;
29622607a28SMichal Simek #ifndef ASM_LOOP
29722607a28SMichal Simek 	int i;
29822607a28SMichal Simek #endif
2992ee2ff87SMichal Simek 	pr_debug("%s\n", __func__);
3002ee2ff87SMichal Simek 
3012ee2ff87SMichal Simek 	local_irq_save(flags);
3022ee2ff87SMichal Simek 	__disable_dcache_msr();
30322607a28SMichal Simek #ifdef ASM_LOOP
3042ee2ff87SMichal Simek 	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
30522607a28SMichal Simek #else
30622607a28SMichal Simek 	for (i = 0; i < cpuinfo.dcache_size;
30722607a28SMichal Simek 		 i += cpuinfo.dcache_line_length)
30822607a28SMichal Simek 			__asm__ __volatile__ ("wdc	%0, r0;" \
30922607a28SMichal Simek 					: : "r" (i));
31022607a28SMichal Simek #endif
3112ee2ff87SMichal Simek 	__enable_dcache_msr();
3122ee2ff87SMichal Simek 	local_irq_restore(flags);
3132ee2ff87SMichal Simek }
3142ee2ff87SMichal Simek 
__invalidate_dcache_all_nomsr_irq(void)3152ee2ff87SMichal Simek static void __invalidate_dcache_all_nomsr_irq(void)
3162ee2ff87SMichal Simek {
3172ee2ff87SMichal Simek 	unsigned long flags;
31822607a28SMichal Simek #ifndef ASM_LOOP
31922607a28SMichal Simek 	int i;
32022607a28SMichal Simek #endif
3212ee2ff87SMichal Simek 	pr_debug("%s\n", __func__);
3222ee2ff87SMichal Simek 
3232ee2ff87SMichal Simek 	local_irq_save(flags);
3242ee2ff87SMichal Simek 	__disable_dcache_nomsr();
32522607a28SMichal Simek #ifdef ASM_LOOP
3262ee2ff87SMichal Simek 	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
32722607a28SMichal Simek #else
32822607a28SMichal Simek 	for (i = 0; i < cpuinfo.dcache_size;
32922607a28SMichal Simek 		 i += cpuinfo.dcache_line_length)
33022607a28SMichal Simek 			__asm__ __volatile__ ("wdc	%0, r0;" \
33122607a28SMichal Simek 					: : "r" (i));
33222607a28SMichal Simek #endif
3332ee2ff87SMichal Simek 	__enable_dcache_nomsr();
3342ee2ff87SMichal Simek 	local_irq_restore(flags);
3352ee2ff87SMichal Simek }
3362ee2ff87SMichal Simek 
__invalidate_dcache_all_noirq_wt(void)3372ee2ff87SMichal Simek static void __invalidate_dcache_all_noirq_wt(void)
3382ee2ff87SMichal Simek {
33922607a28SMichal Simek #ifndef ASM_LOOP
34022607a28SMichal Simek 	int i;
34122607a28SMichal Simek #endif
3422ee2ff87SMichal Simek 	pr_debug("%s\n", __func__);
34322607a28SMichal Simek #ifdef ASM_LOOP
3446bd55f0bSMichal Simek 	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
34522607a28SMichal Simek #else
34622607a28SMichal Simek 	for (i = 0; i < cpuinfo.dcache_size;
34722607a28SMichal Simek 		 i += cpuinfo.dcache_line_length)
34822607a28SMichal Simek 			__asm__ __volatile__ ("wdc	%0, r0;" \
34922607a28SMichal Simek 					: : "r" (i));
35022607a28SMichal Simek #endif
3512ee2ff87SMichal Simek }
3522ee2ff87SMichal Simek 
3536bd55f0bSMichal Simek /*
3546bd55f0bSMichal Simek  * FIXME It is blindly invalidation as is expected
3553274c570SMichal Simek  * but can't be called on noMMU in microblaze_cache_init below
3563274c570SMichal Simek  *
3573274c570SMichal Simek  * MS: noMMU kernel won't boot if simple wdc is used
3583274c570SMichal Simek  * The reason should be that there are discared data which kernel needs
3593274c570SMichal Simek  */
__invalidate_dcache_all_wb(void)3602ee2ff87SMichal Simek static void __invalidate_dcache_all_wb(void)
3612ee2ff87SMichal Simek {
36222607a28SMichal Simek #ifndef ASM_LOOP
36322607a28SMichal Simek 	int i;
36422607a28SMichal Simek #endif
3652ee2ff87SMichal Simek 	pr_debug("%s\n", __func__);
36622607a28SMichal Simek #ifdef ASM_LOOP
3673274c570SMichal Simek 	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
3686bd55f0bSMichal Simek 					wdc);
36922607a28SMichal Simek #else
37022607a28SMichal Simek 	for (i = 0; i < cpuinfo.dcache_size;
37122607a28SMichal Simek 		 i += cpuinfo.dcache_line_length)
3723274c570SMichal Simek 			__asm__ __volatile__ ("wdc	%0, r0;" \
37322607a28SMichal Simek 					: : "r" (i));
37422607a28SMichal Simek #endif
3758beb8503SMichal Simek }
3768beb8503SMichal Simek 
__invalidate_dcache_range_wb(unsigned long start,unsigned long end)3772ee2ff87SMichal Simek static void __invalidate_dcache_range_wb(unsigned long start,
3782ee2ff87SMichal Simek 						unsigned long end)
3798beb8503SMichal Simek {
38022607a28SMichal Simek #ifndef ASM_LOOP
38122607a28SMichal Simek 	int i;
38222607a28SMichal Simek #endif
3832ee2ff87SMichal Simek 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
3842ee2ff87SMichal Simek 				(unsigned int)start, (unsigned int) end);
3852ee2ff87SMichal Simek 
3862ee2ff87SMichal Simek 	CACHE_LOOP_LIMITS(start, end,
3872ee2ff87SMichal Simek 			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
38822607a28SMichal Simek #ifdef ASM_LOOP
3892ee2ff87SMichal Simek 	CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear);
39022607a28SMichal Simek #else
391c17e1a1cSMichal Simek 	for (i = start; i < end; i += cpuinfo.dcache_line_length)
39222607a28SMichal Simek 		__asm__ __volatile__ ("wdc.clear	%0, r0;"	\
39322607a28SMichal Simek 				: : "r" (i));
39422607a28SMichal Simek #endif
3958beb8503SMichal Simek }
3968beb8503SMichal Simek 
__invalidate_dcache_range_nomsr_wt(unsigned long start,unsigned long end)3972ee2ff87SMichal Simek static void __invalidate_dcache_range_nomsr_wt(unsigned long start,
3982ee2ff87SMichal Simek 							unsigned long end)
3998beb8503SMichal Simek {
40022607a28SMichal Simek #ifndef ASM_LOOP
40122607a28SMichal Simek 	int i;
40222607a28SMichal Simek #endif
4032ee2ff87SMichal Simek 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
4042ee2ff87SMichal Simek 				(unsigned int)start, (unsigned int) end);
4052ee2ff87SMichal Simek 	CACHE_LOOP_LIMITS(start, end,
4062ee2ff87SMichal Simek 			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
4078beb8503SMichal Simek 
40822607a28SMichal Simek #ifdef ASM_LOOP
4092ee2ff87SMichal Simek 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
41022607a28SMichal Simek #else
411c17e1a1cSMichal Simek 	for (i = start; i < end; i += cpuinfo.dcache_line_length)
41222607a28SMichal Simek 		__asm__ __volatile__ ("wdc	%0, r0;"	\
41322607a28SMichal Simek 				: : "r" (i));
41422607a28SMichal Simek #endif
4158beb8503SMichal Simek }
4168beb8503SMichal Simek 
__invalidate_dcache_range_msr_irq_wt(unsigned long start,unsigned long end)4172ee2ff87SMichal Simek static void __invalidate_dcache_range_msr_irq_wt(unsigned long start,
4182ee2ff87SMichal Simek 							unsigned long end)
4198beb8503SMichal Simek {
4202ee2ff87SMichal Simek 	unsigned long flags;
42122607a28SMichal Simek #ifndef ASM_LOOP
42222607a28SMichal Simek 	int i;
42322607a28SMichal Simek #endif
4242ee2ff87SMichal Simek 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
4252ee2ff87SMichal Simek 				(unsigned int)start, (unsigned int) end);
4262ee2ff87SMichal Simek 	CACHE_LOOP_LIMITS(start, end,
4272ee2ff87SMichal Simek 			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
4288beb8503SMichal Simek 
4298beb8503SMichal Simek 	local_irq_save(flags);
4302ee2ff87SMichal Simek 	__disable_dcache_msr();
4318beb8503SMichal Simek 
43222607a28SMichal Simek #ifdef ASM_LOOP
4332ee2ff87SMichal Simek 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
43422607a28SMichal Simek #else
435c17e1a1cSMichal Simek 	for (i = start; i < end; i += cpuinfo.dcache_line_length)
43622607a28SMichal Simek 		__asm__ __volatile__ ("wdc	%0, r0;"	\
43722607a28SMichal Simek 				: : "r" (i));
43822607a28SMichal Simek #endif
4398beb8503SMichal Simek 
4402ee2ff87SMichal Simek 	__enable_dcache_msr();
4418beb8503SMichal Simek 	local_irq_restore(flags);
4428beb8503SMichal Simek }
4438beb8503SMichal Simek 
__invalidate_dcache_range_nomsr_irq(unsigned long start,unsigned long end)4442ee2ff87SMichal Simek static void __invalidate_dcache_range_nomsr_irq(unsigned long start,
4452ee2ff87SMichal Simek 							unsigned long end)
4468beb8503SMichal Simek {
4472ee2ff87SMichal Simek 	unsigned long flags;
44822607a28SMichal Simek #ifndef ASM_LOOP
44922607a28SMichal Simek 	int i;
45022607a28SMichal Simek #endif
4512ee2ff87SMichal Simek 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
4522ee2ff87SMichal Simek 				(unsigned int)start, (unsigned int) end);
4538beb8503SMichal Simek 
4542ee2ff87SMichal Simek 	CACHE_LOOP_LIMITS(start, end,
4552ee2ff87SMichal Simek 			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
4568beb8503SMichal Simek 
4578beb8503SMichal Simek 	local_irq_save(flags);
4582ee2ff87SMichal Simek 	__disable_dcache_nomsr();
4598beb8503SMichal Simek 
46022607a28SMichal Simek #ifdef ASM_LOOP
4612ee2ff87SMichal Simek 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
46222607a28SMichal Simek #else
463c17e1a1cSMichal Simek 	for (i = start; i < end; i += cpuinfo.dcache_line_length)
46422607a28SMichal Simek 		__asm__ __volatile__ ("wdc	%0, r0;"	\
46522607a28SMichal Simek 				: : "r" (i));
46622607a28SMichal Simek #endif
4678beb8503SMichal Simek 
4682ee2ff87SMichal Simek 	__enable_dcache_nomsr();
4698beb8503SMichal Simek 	local_irq_restore(flags);
4708beb8503SMichal Simek }
4718beb8503SMichal Simek 
__flush_dcache_all_wb(void)4722ee2ff87SMichal Simek static void __flush_dcache_all_wb(void)
4738beb8503SMichal Simek {
47422607a28SMichal Simek #ifndef ASM_LOOP
47522607a28SMichal Simek 	int i;
47622607a28SMichal Simek #endif
4772ee2ff87SMichal Simek 	pr_debug("%s\n", __func__);
47822607a28SMichal Simek #ifdef ASM_LOOP
4792ee2ff87SMichal Simek 	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
4802ee2ff87SMichal Simek 				wdc.flush);
48122607a28SMichal Simek #else
48222607a28SMichal Simek 	for (i = 0; i < cpuinfo.dcache_size;
48322607a28SMichal Simek 		 i += cpuinfo.dcache_line_length)
48422607a28SMichal Simek 			__asm__ __volatile__ ("wdc.flush	%0, r0;" \
48522607a28SMichal Simek 					: : "r" (i));
48622607a28SMichal Simek #endif
4878beb8503SMichal Simek }
4888beb8503SMichal Simek 
__flush_dcache_range_wb(unsigned long start,unsigned long end)4892ee2ff87SMichal Simek static void __flush_dcache_range_wb(unsigned long start, unsigned long end)
4908beb8503SMichal Simek {
49122607a28SMichal Simek #ifndef ASM_LOOP
49222607a28SMichal Simek 	int i;
49322607a28SMichal Simek #endif
4942ee2ff87SMichal Simek 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
4952ee2ff87SMichal Simek 				(unsigned int)start, (unsigned int) end);
4962ee2ff87SMichal Simek 
4972ee2ff87SMichal Simek 	CACHE_LOOP_LIMITS(start, end,
4982ee2ff87SMichal Simek 			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
49922607a28SMichal Simek #ifdef ASM_LOOP
5002ee2ff87SMichal Simek 	CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush);
50122607a28SMichal Simek #else
502c17e1a1cSMichal Simek 	for (i = start; i < end; i += cpuinfo.dcache_line_length)
50322607a28SMichal Simek 		__asm__ __volatile__ ("wdc.flush	%0, r0;"	\
50422607a28SMichal Simek 				: : "r" (i));
50522607a28SMichal Simek #endif
5068beb8503SMichal Simek }
5078beb8503SMichal Simek 
5082ee2ff87SMichal Simek /* struct for wb caches and for wt caches */
5092ee2ff87SMichal Simek struct scache *mbc;
5102ee2ff87SMichal Simek 
5112ee2ff87SMichal Simek /* new wb cache model */
512954e8b95SMichal Simek static const struct scache wb_msr = {
5132ee2ff87SMichal Simek 	.ie = __enable_icache_msr,
5142ee2ff87SMichal Simek 	.id = __disable_icache_msr,
5152ee2ff87SMichal Simek 	.ifl = __flush_icache_all_noirq,
5162ee2ff87SMichal Simek 	.iflr = __flush_icache_range_noirq,
5172ee2ff87SMichal Simek 	.iin = __flush_icache_all_noirq,
5182ee2ff87SMichal Simek 	.iinr = __flush_icache_range_noirq,
5192ee2ff87SMichal Simek 	.de = __enable_dcache_msr,
5202ee2ff87SMichal Simek 	.dd = __disable_dcache_msr,
5212ee2ff87SMichal Simek 	.dfl = __flush_dcache_all_wb,
5222ee2ff87SMichal Simek 	.dflr = __flush_dcache_range_wb,
5232ee2ff87SMichal Simek 	.din = __invalidate_dcache_all_wb,
5242ee2ff87SMichal Simek 	.dinr = __invalidate_dcache_range_wb,
5252ee2ff87SMichal Simek };
5262ee2ff87SMichal Simek 
5272ee2ff87SMichal Simek /* There is only difference in ie, id, de, dd functions */
528954e8b95SMichal Simek static const struct scache wb_nomsr = {
5292ee2ff87SMichal Simek 	.ie = __enable_icache_nomsr,
5302ee2ff87SMichal Simek 	.id = __disable_icache_nomsr,
5312ee2ff87SMichal Simek 	.ifl = __flush_icache_all_noirq,
5322ee2ff87SMichal Simek 	.iflr = __flush_icache_range_noirq,
5332ee2ff87SMichal Simek 	.iin = __flush_icache_all_noirq,
5342ee2ff87SMichal Simek 	.iinr = __flush_icache_range_noirq,
5352ee2ff87SMichal Simek 	.de = __enable_dcache_nomsr,
5362ee2ff87SMichal Simek 	.dd = __disable_dcache_nomsr,
5372ee2ff87SMichal Simek 	.dfl = __flush_dcache_all_wb,
5382ee2ff87SMichal Simek 	.dflr = __flush_dcache_range_wb,
5392ee2ff87SMichal Simek 	.din = __invalidate_dcache_all_wb,
5402ee2ff87SMichal Simek 	.dinr = __invalidate_dcache_range_wb,
5412ee2ff87SMichal Simek };
5422ee2ff87SMichal Simek 
5432ee2ff87SMichal Simek /* Old wt cache model with disabling irq and turn off cache */
544954e8b95SMichal Simek static const struct scache wt_msr = {
5452ee2ff87SMichal Simek 	.ie = __enable_icache_msr,
5462ee2ff87SMichal Simek 	.id = __disable_icache_msr,
5472ee2ff87SMichal Simek 	.ifl = __flush_icache_all_msr_irq,
5482ee2ff87SMichal Simek 	.iflr = __flush_icache_range_msr_irq,
5492ee2ff87SMichal Simek 	.iin = __flush_icache_all_msr_irq,
5502ee2ff87SMichal Simek 	.iinr = __flush_icache_range_msr_irq,
5512ee2ff87SMichal Simek 	.de = __enable_dcache_msr,
5522ee2ff87SMichal Simek 	.dd = __disable_dcache_msr,
5532ee2ff87SMichal Simek 	.dfl = __invalidate_dcache_all_msr_irq,
5542ee2ff87SMichal Simek 	.dflr = __invalidate_dcache_range_msr_irq_wt,
5552ee2ff87SMichal Simek 	.din = __invalidate_dcache_all_msr_irq,
5562ee2ff87SMichal Simek 	.dinr = __invalidate_dcache_range_msr_irq_wt,
5572ee2ff87SMichal Simek };
5582ee2ff87SMichal Simek 
559954e8b95SMichal Simek static const struct scache wt_nomsr = {
5602ee2ff87SMichal Simek 	.ie = __enable_icache_nomsr,
5612ee2ff87SMichal Simek 	.id = __disable_icache_nomsr,
5622ee2ff87SMichal Simek 	.ifl = __flush_icache_all_nomsr_irq,
5632ee2ff87SMichal Simek 	.iflr = __flush_icache_range_nomsr_irq,
5642ee2ff87SMichal Simek 	.iin = __flush_icache_all_nomsr_irq,
5652ee2ff87SMichal Simek 	.iinr = __flush_icache_range_nomsr_irq,
5662ee2ff87SMichal Simek 	.de = __enable_dcache_nomsr,
5672ee2ff87SMichal Simek 	.dd = __disable_dcache_nomsr,
5682ee2ff87SMichal Simek 	.dfl = __invalidate_dcache_all_nomsr_irq,
5692ee2ff87SMichal Simek 	.dflr = __invalidate_dcache_range_nomsr_irq,
5702ee2ff87SMichal Simek 	.din = __invalidate_dcache_all_nomsr_irq,
5712ee2ff87SMichal Simek 	.dinr = __invalidate_dcache_range_nomsr_irq,
5722ee2ff87SMichal Simek };
5732ee2ff87SMichal Simek 
5742ee2ff87SMichal Simek /* New wt cache model for newer Microblaze versions */
575954e8b95SMichal Simek static const struct scache wt_msr_noirq = {
5762ee2ff87SMichal Simek 	.ie = __enable_icache_msr,
5772ee2ff87SMichal Simek 	.id = __disable_icache_msr,
5782ee2ff87SMichal Simek 	.ifl = __flush_icache_all_noirq,
5792ee2ff87SMichal Simek 	.iflr = __flush_icache_range_noirq,
5802ee2ff87SMichal Simek 	.iin = __flush_icache_all_noirq,
5812ee2ff87SMichal Simek 	.iinr = __flush_icache_range_noirq,
5822ee2ff87SMichal Simek 	.de = __enable_dcache_msr,
5832ee2ff87SMichal Simek 	.dd = __disable_dcache_msr,
5842ee2ff87SMichal Simek 	.dfl = __invalidate_dcache_all_noirq_wt,
5852ee2ff87SMichal Simek 	.dflr = __invalidate_dcache_range_nomsr_wt,
5862ee2ff87SMichal Simek 	.din = __invalidate_dcache_all_noirq_wt,
5872ee2ff87SMichal Simek 	.dinr = __invalidate_dcache_range_nomsr_wt,
5882ee2ff87SMichal Simek };
5892ee2ff87SMichal Simek 
590954e8b95SMichal Simek static const struct scache wt_nomsr_noirq = {
5912ee2ff87SMichal Simek 	.ie = __enable_icache_nomsr,
5922ee2ff87SMichal Simek 	.id = __disable_icache_nomsr,
5932ee2ff87SMichal Simek 	.ifl = __flush_icache_all_noirq,
5942ee2ff87SMichal Simek 	.iflr = __flush_icache_range_noirq,
5952ee2ff87SMichal Simek 	.iin = __flush_icache_all_noirq,
5962ee2ff87SMichal Simek 	.iinr = __flush_icache_range_noirq,
5972ee2ff87SMichal Simek 	.de = __enable_dcache_nomsr,
5982ee2ff87SMichal Simek 	.dd = __disable_dcache_nomsr,
5992ee2ff87SMichal Simek 	.dfl = __invalidate_dcache_all_noirq_wt,
6002ee2ff87SMichal Simek 	.dflr = __invalidate_dcache_range_nomsr_wt,
6012ee2ff87SMichal Simek 	.din = __invalidate_dcache_all_noirq_wt,
6022ee2ff87SMichal Simek 	.dinr = __invalidate_dcache_range_nomsr_wt,
6032ee2ff87SMichal Simek };
6042ee2ff87SMichal Simek 
6052ee2ff87SMichal Simek /* CPU version code for 7.20.c - see arch/microblaze/kernel/cpu/cpuinfo.c */
6062ee2ff87SMichal Simek #define CPUVER_7_20_A	0x0c
6072ee2ff87SMichal Simek #define CPUVER_7_20_D	0x0f
6082ee2ff87SMichal Simek 
microblaze_cache_init(void)6092ee2ff87SMichal Simek void microblaze_cache_init(void)
6108beb8503SMichal Simek {
6112ee2ff87SMichal Simek 	if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) {
6122ee2ff87SMichal Simek 		if (cpuinfo.dcache_wb) {
6136bd55f0bSMichal Simek 			pr_info("wb_msr\n");
6142ee2ff87SMichal Simek 			mbc = (struct scache *)&wb_msr;
615b9dc9e77SMichal Simek 			if (cpuinfo.ver_code <= CPUVER_7_20_D) {
6162ee2ff87SMichal Simek 				/* MS: problem with signal handling - hw bug */
6176bd55f0bSMichal Simek 				pr_info("WB won't work properly\n");
6182ee2ff87SMichal Simek 			}
6192ee2ff87SMichal Simek 		} else {
6202ee2ff87SMichal Simek 			if (cpuinfo.ver_code >= CPUVER_7_20_A) {
6216bd55f0bSMichal Simek 				pr_info("wt_msr_noirq\n");
6222ee2ff87SMichal Simek 				mbc = (struct scache *)&wt_msr_noirq;
6232ee2ff87SMichal Simek 			} else {
6246bd55f0bSMichal Simek 				pr_info("wt_msr\n");
6252ee2ff87SMichal Simek 				mbc = (struct scache *)&wt_msr;
6262ee2ff87SMichal Simek 			}
6272ee2ff87SMichal Simek 		}
6282ee2ff87SMichal Simek 	} else {
6292ee2ff87SMichal Simek 		if (cpuinfo.dcache_wb) {
6306bd55f0bSMichal Simek 			pr_info("wb_nomsr\n");
6312ee2ff87SMichal Simek 			mbc = (struct scache *)&wb_nomsr;
632b9dc9e77SMichal Simek 			if (cpuinfo.ver_code <= CPUVER_7_20_D) {
6332ee2ff87SMichal Simek 				/* MS: problem with signal handling - hw bug */
6346bd55f0bSMichal Simek 				pr_info("WB won't work properly\n");
6352ee2ff87SMichal Simek 			}
6362ee2ff87SMichal Simek 		} else {
6372ee2ff87SMichal Simek 			if (cpuinfo.ver_code >= CPUVER_7_20_A) {
6386bd55f0bSMichal Simek 				pr_info("wt_nomsr_noirq\n");
6392ee2ff87SMichal Simek 				mbc = (struct scache *)&wt_nomsr_noirq;
6402ee2ff87SMichal Simek 			} else {
6416bd55f0bSMichal Simek 				pr_info("wt_nomsr\n");
6422ee2ff87SMichal Simek 				mbc = (struct scache *)&wt_nomsr;
6432ee2ff87SMichal Simek 			}
6442ee2ff87SMichal Simek 		}
6452ee2ff87SMichal Simek 	}
6466bd55f0bSMichal Simek 	/*
6476bd55f0bSMichal Simek 	 * FIXME Invalidation is done in U-BOOT
6483274c570SMichal Simek 	 * WT cache: Data is already written to main memory
6493274c570SMichal Simek 	 * WB cache: Discard data on noMMU which caused that kernel doesn't boot
6503274c570SMichal Simek 	 */
6513274c570SMichal Simek 	/* invalidate_dcache(); */
652407c1da0SMichal Simek 	enable_dcache();
653407c1da0SMichal Simek 
654407c1da0SMichal Simek 	invalidate_icache();
655407c1da0SMichal Simek 	enable_icache();
6568beb8503SMichal Simek }
657