diff options
Diffstat (limited to 'target/linux/realtek/files/arch/rlx/mm/cache-rlx.c')
-rw-r--r-- | target/linux/realtek/files/arch/rlx/mm/cache-rlx.c | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/target/linux/realtek/files/arch/rlx/mm/cache-rlx.c b/target/linux/realtek/files/arch/rlx/mm/cache-rlx.c new file mode 100644 index 000000000..c183b95ee --- /dev/null +++ b/target/linux/realtek/files/arch/rlx/mm/cache-rlx.c @@ -0,0 +1,432 @@ +/* + * cache-rlx.c: RLX specific mmu/cache code. + * Realtek Semiconductor Corp. + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/mmu_context.h> +#include <asm/system.h> +#include <asm/isadep.h> +#include <asm/io.h> +#include <asm/bootinfo.h> +#include <asm/cpu.h> +#include <asm/cpu-features.h> +#include <asm/wbflush.h> + +#include <asm/rlxbsp.h> + +/* + * Determine whether CPU has CACHE OP + */ +#if defined(CONFIG_CPU_RLX4181) || defined(CONFIG_CPU_RLX5181) || \ + defined(CONFIG_CPU_RLX4281) || defined(CONFIG_CPU_RLX5281) +#define CONFIG_CPU_HAS_CACHE_OP +#else +#undef CONFIG_CPU_HAS_CACHE_OP +#endif + +/* + * DCACHE part + */ +#if defined(CONFIG_CPU_HAS_WBC) || defined(CONFIG_CPU_HAS_L2C) +static void inline rlx_dcache_flush_all(void) +{ + __asm__ __volatile__( + ".set\tpush\n" + ".set\tnoreorder\n" + "\tmtc0\t$0, $20\n" + "\tli\t$8, 0x200\n" + "\tmtc0\t$8, $20\n" + ".set\tpop\n"); +} + +__attribute__ ((section(".iram-gen"))) +static void rlx_dcache_flush_range(unsigned long start, unsigned long end) +{ +#ifdef CONFIG_CPU_HAS_CACHE_OP + unsigned long size, i, flags; + volatile unsigned char *p; + + start &= ~cpu_dcache_line_mask; + size = end - start; + if (size >= cpu_dcache_size * 2) + { + rlx_dcache_flush_all(); + return; + } + + p = (char *)start; + flags = read_c0_status(); + + /* disable interrupt */ + write_c0_status(flags & ~ST0_IEC); + + /* 0x10 = IInval */ + /* 0x11 = DInval */ + /* 0x15 = DWBInval */ + /* 0x19 = DWB */ + + for (i = 0; i < size; i += 0x080) { + asm ( +#if (cpu_dcache_line == 16) + "cache 0x15, 0x000(%0)\n\t" + "cache 0x15, 0x010(%0)\n\t" + "cache 0x15, 0x020(%0)\n\t" + "cache 0x15, 0x030(%0)\n\t" + "cache 0x15, 0x040(%0)\n\t" + "cache 0x15, 0x050(%0)\n\t" + "cache 0x15, 0x060(%0)\n\t" + "cache 0x15, 0x070(%0)\n\t" +#else + "cache 0x15, 0x000(%0)\n\t" + "cache 0x15, 0x020(%0)\n\t" + "cache 0x15, 0x040(%0)\n\t" + "cache 0x15, 0x060(%0)\n\t" +#endif + : : "r" (p) ); + p += 0x080; + } + + /* restore interrupt */ + write_c0_status(flags); +#else + rlx_dcache_flush_all(); +#endif +} + +void rlx_dcache_wb_all(void) +{ + __asm__ __volatile__( + ".set\tpush\n" + ".set\tnoreorder\n" + "\tmtc0\t$0, $20\n" + "\tli\t$8, 0x100\n" + "\tmtc0\t$8, $20\n" + ".set\tpop\n"); +} + +static void rlx_dcache_wb_range(unsigned long start, unsigned long end) +{ + #ifdef CONFIG_CPU_HAS_CACHE_OP + unsigned long size, i, flags; + volatile unsigned char *p; + + start &= ~cpu_dcache_line_mask; + size = end - start; + if (size >= cpu_dcache_size * 2) + { + rlx_dcache_wb_all(); + return; + } + + p = (char *)start; + flags = read_c0_status(); + + /* disable interrupt */ + write_c0_status(flags & ~ST0_IEC); + + /* 0x10 = IInval */ + /* 0x11 = DInval */ + /* 0x15 = DWBInval */ + /* 0x19 = DWB */ + for (i = 0; i < size; i += 0x080) { + asm ( +#if (cpu_dcache_line == 16) + "cache 0x19, 0x000(%0)\n\t" + "cache 0x19, 0x010(%0)\n\t" + "cache 0x19, 0x020(%0)\n\t" + "cache 0x19, 0x030(%0)\n\t" + "cache 0x19, 0x040(%0)\n\t" + "cache 0x19, 0x050(%0)\n\t" + "cache 0x19, 0x060(%0)\n\t" + "cache 0x19, 0x070(%0)\n\t" +#else + "cache 0x19, 0x000(%0)\n\t" + "cache 0x19, 0x020(%0)\n\t" + "cache 0x19, 0x040(%0)\n\t" + "cache 0x19, 0x060(%0)\n\t" +#endif + : : "r" (p) ); + p += 0x080; + } + + /* restore interrupt */ + write_c0_status(flags); + #else + rlx_dcache_wb_all(); + #endif +} +#else /* not CONFIG_CPU_HAS_WBC and not CONFIG_CPU_HAS_L2C */ +static void rlx_dcache_flush_all(void) +{ + __asm__ __volatile__( + ".set\tpush\n" + ".set\tnoreorder\n" + "\tmtc0\t$0, $20\n" + "\tli\t$8, 0x1\n" + "\tmtc0\t$8, $20\n" + ".set\tpop\n"); + + return; +} + +static void rlx_dcache_flush_range(unsigned long start, unsigned long end) +{ +#ifdef CONFIG_CPU_HAS_CACHE_OP + unsigned long size, i, flags; + volatile unsigned char *p; + + start &= ~cpu_dcache_line_mask; + size = end - start; + if (size >= cpu_dcache_size * 2) + { + rlx_dcache_flush_all(); + return; + } + + p = (char *)start; + flags = read_c0_status(); + + /* disable interrupt */ + write_c0_status(flags &~ ST0_IEC); + + /* 0x10 = IInval */ + /* 0x11 = DInval */ + /* 0x15 = DWBInval */ + /* 0x19 = DWB */ + for (i = 0; i < size; i += 0x080) { + asm ( +#if (cpu_dcache_line == 16) + "cache 0x11, 0x000(%0)\n\t" + "cache 0x11, 0x010(%0)\n\t" + "cache 0x11, 0x020(%0)\n\t" + "cache 0x11, 0x030(%0)\n\t" + "cache 0x11, 0x040(%0)\n\t" + "cache 0x11, 0x050(%0)\n\t" + "cache 0x11, 0x060(%0)\n\t" + "cache 0x11, 0x070(%0)\n\t" +#else + "cache 0x11, 0x000(%0)\n\t" + "cache 0x11, 0x020(%0)\n\t" + "cache 0x11, 0x040(%0)\n\t" + "cache 0x11, 0x060(%0)\n\t" +#endif + : : "r" (p) ); + p += 0x080; + } + + /* restore interrupt */ + write_c0_status(flags); +#else + rlx_dcache_flush_all(); +#endif +} + +void rlx_dcache_wb_all(void) +{ +} + +static void rlx_dcache_wb_range(unsigned long start, unsigned long end) +{ +} +#endif /* CONFIG_CPU_HAS_WBC or CONFIG_CPU_HAS_L2C */ + +/* + * ICACHE part + */ +static void rlx_icache_flush_all(void) +{ + __asm__ __volatile__( + ".set\tpush\n" + ".set\tnoreorder\n" + "\tmtc0\t$0, $20\n" + "\tli\t$8, 0x2\n" + "\tmtc0\t$8, $20\n" + ".set\tpop\n"); +} + +static void rlx_icache_flush_range(unsigned long start, unsigned long end) +{ +#if defined(CONFIG_CPU_RLX4281) || defined(CONFIG_CPU_RLX5281) + unsigned long size, i, flags; + volatile unsigned char *p; + + rlx_dcache_wb_range(start, end); + + start &= ~cpu_icache_line_mask; + size = end - start; + if (size >= cpu_icache_size * 2) + { + rlx_icache_flush_all(); + return; + } + + p = (char *)start; + flags = read_c0_status(); + + /* disable interrupt */ + write_c0_status(flags &~ ST0_IEC); + + /* 0x10 = IInval */ + /* 0x11 = DInval */ + /* 0x15 = DWBInval */ + /* 0x19 = DWB */ + for (i = 0; i < size; i += 0x080) { + asm ( +#if (cpu_icache_line == 16) + "cache 0x10, 0x000(%0)\n\t" + "cache 0x10, 0x010(%0)\n\t" + "cache 0x10, 0x020(%0)\n\t" + "cache 0x10, 0x030(%0)\n\t" + "cache 0x10, 0x040(%0)\n\t" + "cache 0x10, 0x050(%0)\n\t" + "cache 0x10, 0x060(%0)\n\t" + "cache 0x10, 0x070(%0)\n\t" +#else + "cache 0x10, 0x000(%0)\n\t" + "cache 0x10, 0x020(%0)\n\t" + "cache 0x10, 0x040(%0)\n\t" + "cache 0x10, 0x060(%0)\n\t" +#endif + : : "r" (p) ); + p += 0x080; + } + + /* restore interrupt */ + write_c0_status(flags); +#else + rlx_dcache_wb_range(start, end); + rlx_icache_flush_all(); +#endif +} + +static inline void rlx_cache_flush_all(void) +{ +} + +static inline void __rlx_cache_flush_all(void) +{ + rlx_dcache_flush_all(); + rlx_icache_flush_all(); +} + +static void rlx_cache_flush_mm(struct mm_struct *mm) +{ +} + +static void rlx_cache_flush_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ +} + +static void rlx_cache_flush_page(struct vm_area_struct *vma, + unsigned long addr, unsigned long pfn) +{ + unsigned long kaddr = KSEG0ADDR(pfn << PAGE_SHIFT); + int exec = vma->vm_flags & VM_EXEC; + struct mm_struct *mm = vma->vm_mm; + pgd_t *pgdp; + pud_t *pudp; + pmd_t *pmdp; + pte_t *ptep; + + pr_debug("cpage[%08lx,%08lx]\n", + cpu_context(smp_processor_id(), mm), addr); + + /* No ASID => no such page in the cache. */ + if (cpu_context(smp_processor_id(), mm) == 0) + return; + + pgdp = pgd_offset(mm, addr); + pudp = pud_offset(pgdp, addr); + pmdp = pmd_offset(pudp, addr); + ptep = pte_offset(pmdp, addr); + + /* Invalid => no such page in the cache. */ + if (!(pte_val(*ptep) & _PAGE_PRESENT)) + return; + + rlx_dcache_flush_range(kaddr, kaddr + PAGE_SIZE); + if (exec) + rlx_icache_flush_range(kaddr, kaddr + PAGE_SIZE); +} + +static void local_rlx_dcache_flush_page(void *addr) +{ +} + +static void rlx_dcache_flush_page(unsigned long addr) +{ +} + +static void rlx_cache_flush_sigtramp(unsigned long addr) +{ + unsigned long flags; + + pr_debug("csigtramp[%08lx]\n", addr); + + flags = read_c0_status(); + + /* disable interrupt */ + write_c0_status(flags&~ST0_IEC); + +#if defined(CONFIG_CPU_HAS_WBC) || defined(CONFIG_CPU_HAS_L2C) + #ifndef CONFIG_CPU_HAS_CACHE_OP + rlx_dcache_flush_all(); + #else + asm ( "cache\t0x19, 0x000(%0)\n\t" : : "r" (addr) ); + #endif +#endif + +#if defined(CONFIG_CPU_RLX4281) || defined(CONFIG_CPU_RLX5281) + asm ( "cache\t0x10, 0x000(%0)\n\t" : : "r" (addr) ); +#else + rlx_icache_flush_all(); +#endif + + /* restore interrupt */ + write_c0_status(flags); +} + +static void rlx_dma_cache_wback_inv(unsigned long start, unsigned long size) +{ + /* Catch bad driver code */ + BUG_ON(size == 0); + + iob(); + rlx_dcache_flush_range(start, start + size); +} + +void __cpuinit rlx_cache_init(void) +{ + extern void build_clear_page(void); + extern void build_copy_page(void); + + flush_cache_all = rlx_cache_flush_all; + __flush_cache_all = __rlx_cache_flush_all; + flush_cache_mm = rlx_cache_flush_mm; + flush_cache_range = rlx_cache_flush_range; + flush_cache_page = rlx_cache_flush_page; + flush_icache_range = rlx_icache_flush_range; + local_flush_icache_range = rlx_icache_flush_range; + local_flush_data_cache_page = local_rlx_dcache_flush_page; + flush_data_cache_page = rlx_dcache_flush_page; + flush_cache_sigtramp = rlx_cache_flush_sigtramp; + + _dma_cache_wback_inv = rlx_dma_cache_wback_inv; + _dma_cache_wback = rlx_dma_cache_wback_inv; + _dma_cache_inv = rlx_dma_cache_wback_inv; + + printk("icache: %dkB/%dB, dcache: %dkB/%dB, scache: %dkB/%dB\n", + cpu_icache_size >> 10, cpu_icache_line, + cpu_dcache_size >> 10, cpu_dcache_line, + cpu_scache_size >> 10, cpu_scache_line); + + build_clear_page(); + build_copy_page(); +} |