162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/arch/m68k/mm/cache.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Instruction cache handling
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  Copyright (C) 1995  Hamish Macdonald
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <asm/cacheflush.h>
1262306a36Sopenharmony_ci#include <asm/traps.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic unsigned long virt_to_phys_slow(unsigned long vaddr)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	if (CPU_IS_060) {
1862306a36Sopenharmony_ci		unsigned long paddr;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci		/* The PLPAR instruction causes an access error if the translation
2162306a36Sopenharmony_ci		 * is not possible. To catch this we use the same exception mechanism
2262306a36Sopenharmony_ci		 * as for user space accesses in <asm/uaccess.h>. */
2362306a36Sopenharmony_ci		asm volatile (".chip 68060\n"
2462306a36Sopenharmony_ci			      "1: plpar (%0)\n"
2562306a36Sopenharmony_ci			      ".chip 68k\n"
2662306a36Sopenharmony_ci			      "2:\n"
2762306a36Sopenharmony_ci			      ".section .fixup,\"ax\"\n"
2862306a36Sopenharmony_ci			      "   .even\n"
2962306a36Sopenharmony_ci			      "3: sub.l %0,%0\n"
3062306a36Sopenharmony_ci			      "   jra 2b\n"
3162306a36Sopenharmony_ci			      ".previous\n"
3262306a36Sopenharmony_ci			      ".section __ex_table,\"a\"\n"
3362306a36Sopenharmony_ci			      "   .align 4\n"
3462306a36Sopenharmony_ci			      "   .long 1b,3b\n"
3562306a36Sopenharmony_ci			      ".previous"
3662306a36Sopenharmony_ci			      : "=a" (paddr)
3762306a36Sopenharmony_ci			      : "0" (vaddr));
3862306a36Sopenharmony_ci		return paddr;
3962306a36Sopenharmony_ci	} else if (CPU_IS_040) {
4062306a36Sopenharmony_ci		unsigned long mmusr;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci		asm volatile (".chip 68040\n\t"
4362306a36Sopenharmony_ci			      "ptestr (%1)\n\t"
4462306a36Sopenharmony_ci			      "movec %%mmusr, %0\n\t"
4562306a36Sopenharmony_ci			      ".chip 68k"
4662306a36Sopenharmony_ci			      : "=r" (mmusr)
4762306a36Sopenharmony_ci			      : "a" (vaddr));
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci		if (mmusr & MMU_R_040)
5062306a36Sopenharmony_ci			return (mmusr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
5162306a36Sopenharmony_ci	} else {
5262306a36Sopenharmony_ci		WARN_ON_ONCE(!CPU_IS_040_OR_060);
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci	return 0;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* Push n pages at kernel virtual address and clear the icache */
5862306a36Sopenharmony_ci/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
5962306a36Sopenharmony_civoid flush_icache_user_range(unsigned long address, unsigned long endaddr)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	if (CPU_IS_COLDFIRE) {
6262306a36Sopenharmony_ci		unsigned long start, end;
6362306a36Sopenharmony_ci		start = address & ICACHE_SET_MASK;
6462306a36Sopenharmony_ci		end = endaddr & ICACHE_SET_MASK;
6562306a36Sopenharmony_ci		if (start > end) {
6662306a36Sopenharmony_ci			flush_cf_icache(0, end);
6762306a36Sopenharmony_ci			end = ICACHE_MAX_ADDR;
6862306a36Sopenharmony_ci		}
6962306a36Sopenharmony_ci		flush_cf_icache(start, end);
7062306a36Sopenharmony_ci	} else if (CPU_IS_040_OR_060) {
7162306a36Sopenharmony_ci		address &= PAGE_MASK;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		do {
7462306a36Sopenharmony_ci			asm volatile ("nop\n\t"
7562306a36Sopenharmony_ci				      ".chip 68040\n\t"
7662306a36Sopenharmony_ci				      "cpushp %%bc,(%0)\n\t"
7762306a36Sopenharmony_ci				      ".chip 68k"
7862306a36Sopenharmony_ci				      : : "a" (virt_to_phys_slow(address)));
7962306a36Sopenharmony_ci			address += PAGE_SIZE;
8062306a36Sopenharmony_ci		} while (address < endaddr);
8162306a36Sopenharmony_ci	} else {
8262306a36Sopenharmony_ci		unsigned long tmp;
8362306a36Sopenharmony_ci		asm volatile ("movec %%cacr,%0\n\t"
8462306a36Sopenharmony_ci			      "orw %1,%0\n\t"
8562306a36Sopenharmony_ci			      "movec %0,%%cacr"
8662306a36Sopenharmony_ci			      : "=&d" (tmp)
8762306a36Sopenharmony_ci			      : "di" (FLUSH_I));
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_civoid flush_icache_range(unsigned long address, unsigned long endaddr)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	set_fc(SUPER_DATA);
9462306a36Sopenharmony_ci	flush_icache_user_range(address, endaddr);
9562306a36Sopenharmony_ci	set_fc(USER_DATA);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ciEXPORT_SYMBOL(flush_icache_range);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_civoid flush_icache_user_page(struct vm_area_struct *vma, struct page *page,
10062306a36Sopenharmony_ci			     unsigned long addr, int len)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	if (CPU_IS_COLDFIRE) {
10362306a36Sopenharmony_ci		unsigned long start, end;
10462306a36Sopenharmony_ci		start = addr & ICACHE_SET_MASK;
10562306a36Sopenharmony_ci		end = (addr + len) & ICACHE_SET_MASK;
10662306a36Sopenharmony_ci		if (start > end) {
10762306a36Sopenharmony_ci			flush_cf_icache(0, end);
10862306a36Sopenharmony_ci			end = ICACHE_MAX_ADDR;
10962306a36Sopenharmony_ci		}
11062306a36Sopenharmony_ci		flush_cf_icache(start, end);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	} else if (CPU_IS_040_OR_060) {
11362306a36Sopenharmony_ci		asm volatile ("nop\n\t"
11462306a36Sopenharmony_ci			      ".chip 68040\n\t"
11562306a36Sopenharmony_ci			      "cpushp %%bc,(%0)\n\t"
11662306a36Sopenharmony_ci			      ".chip 68k"
11762306a36Sopenharmony_ci			      : : "a" (page_to_phys(page)));
11862306a36Sopenharmony_ci	} else {
11962306a36Sopenharmony_ci		unsigned long tmp;
12062306a36Sopenharmony_ci		asm volatile ("movec %%cacr,%0\n\t"
12162306a36Sopenharmony_ci			      "orw %1,%0\n\t"
12262306a36Sopenharmony_ci			      "movec %0,%%cacr"
12362306a36Sopenharmony_ci			      : "=&d" (tmp)
12462306a36Sopenharmony_ci			      : "di" (FLUSH_I));
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
128