18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
58c2ecf20Sopenharmony_ci#include <asm/cache.h>
68c2ecf20Sopenharmony_ci#include <abi/reg_ops.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci/* for L1-cache */
98c2ecf20Sopenharmony_ci#define INS_CACHE		(1 << 0)
108c2ecf20Sopenharmony_ci#define DATA_CACHE		(1 << 1)
118c2ecf20Sopenharmony_ci#define CACHE_INV		(1 << 4)
128c2ecf20Sopenharmony_ci#define CACHE_CLR		(1 << 5)
138c2ecf20Sopenharmony_ci#define CACHE_OMS		(1 << 6)
148c2ecf20Sopenharmony_ci#define CACHE_ITS		(1 << 7)
158c2ecf20Sopenharmony_ci#define CACHE_LICF		(1 << 31)
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* for L2-cache */
188c2ecf20Sopenharmony_ci#define CR22_LEVEL_SHIFT	(1)
198c2ecf20Sopenharmony_ci#define CR22_SET_SHIFT		(7)
208c2ecf20Sopenharmony_ci#define CR22_WAY_SHIFT		(30)
218c2ecf20Sopenharmony_ci#define CR22_WAY_SHIFT_L2	(29)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(cache_lock);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic inline void cache_op_line(unsigned long i, unsigned int val)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	mtcr("cr22", i);
288c2ecf20Sopenharmony_ci	mtcr("cr17", val);
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define CCR2_L2E (1 << 3)
328c2ecf20Sopenharmony_cistatic void cache_op_all(unsigned int value, unsigned int l2)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	mtcr("cr17", value | CACHE_CLR);
358c2ecf20Sopenharmony_ci	mb();
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (l2 && (mfcr_ccr2() & CCR2_L2E)) {
388c2ecf20Sopenharmony_ci		mtcr("cr24", value | CACHE_CLR);
398c2ecf20Sopenharmony_ci		mb();
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic void cache_op_range(
448c2ecf20Sopenharmony_ci	unsigned int start,
458c2ecf20Sopenharmony_ci	unsigned int end,
468c2ecf20Sopenharmony_ci	unsigned int value,
478c2ecf20Sopenharmony_ci	unsigned int l2)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	unsigned long i, flags;
508c2ecf20Sopenharmony_ci	unsigned int val = value | CACHE_CLR | CACHE_OMS;
518c2ecf20Sopenharmony_ci	bool l2_sync;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (unlikely((end - start) >= PAGE_SIZE) ||
548c2ecf20Sopenharmony_ci	    unlikely(start < PAGE_OFFSET) ||
558c2ecf20Sopenharmony_ci	    unlikely(start >= PAGE_OFFSET + LOWMEM_LIMIT)) {
568c2ecf20Sopenharmony_ci		cache_op_all(value, l2);
578c2ecf20Sopenharmony_ci		return;
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if ((mfcr_ccr2() & CCR2_L2E) && l2)
618c2ecf20Sopenharmony_ci		l2_sync = 1;
628c2ecf20Sopenharmony_ci	else
638c2ecf20Sopenharmony_ci		l2_sync = 0;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	spin_lock_irqsave(&cache_lock, flags);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	i = start & ~(L1_CACHE_BYTES - 1);
688c2ecf20Sopenharmony_ci	for (; i < end; i += L1_CACHE_BYTES) {
698c2ecf20Sopenharmony_ci		cache_op_line(i, val);
708c2ecf20Sopenharmony_ci		if (l2_sync) {
718c2ecf20Sopenharmony_ci			mb();
728c2ecf20Sopenharmony_ci			mtcr("cr24", val);
738c2ecf20Sopenharmony_ci		}
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&cache_lock, flags);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	mb();
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_civoid dcache_wb_line(unsigned long start)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	asm volatile("idly4\n":::"memory");
838c2ecf20Sopenharmony_ci	cache_op_line(start, DATA_CACHE|CACHE_CLR);
848c2ecf20Sopenharmony_ci	mb();
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_civoid icache_inv_range(unsigned long start, unsigned long end)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	cache_op_range(start, end, INS_CACHE|CACHE_INV, 0);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_civoid icache_inv_all(void)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	cache_op_all(INS_CACHE|CACHE_INV, 0);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_civoid local_icache_inv_all(void *priv)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	cache_op_all(INS_CACHE|CACHE_INV, 0);
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_civoid dcache_wb_range(unsigned long start, unsigned long end)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	cache_op_range(start, end, DATA_CACHE|CACHE_CLR, 0);
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_civoid dcache_wbinv_all(void)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	cache_op_all(DATA_CACHE|CACHE_CLR|CACHE_INV, 0);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_civoid cache_wbinv_range(unsigned long start, unsigned long end)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	cache_op_range(start, end, INS_CACHE|DATA_CACHE|CACHE_CLR|CACHE_INV, 0);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cache_wbinv_range);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_civoid cache_wbinv_all(void)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	cache_op_all(INS_CACHE|DATA_CACHE|CACHE_CLR|CACHE_INV, 0);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_civoid dma_wbinv_range(unsigned long start, unsigned long end)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_civoid dma_inv_range(unsigned long start, unsigned long end)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_civoid dma_wb_range(unsigned long start, unsigned long end)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1);
1368c2ecf20Sopenharmony_ci}
137