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); \
95*061d2c1dSShubhrajyoti 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