1/*
2 * arch/v850/kernel/v850e2_cache.c -- Cache control for V850E2 cache
3 * 	memories
4 *
5 *  Copyright (C) 2003  NEC Electronics Corporation
6 *  Copyright (C) 2003  Miles Bader <miles@gnu.org>
7 *
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License.  See the file COPYING in the main directory of this
10 * archive for more details.
11 *
12 * Written by Miles Bader <miles@gnu.org>
13 */
14
15#include <linux/mm.h>
16
17#include <asm/v850e2_cache.h>
18
19/* Cache operations we can do.  The encoding corresponds directly to the
20   value we need to write into the COPR register.  */
21enum cache_op {
22	OP_SYNC_IF_DIRTY 	   = V850E2_CACHE_COPR_CFC(0), /* 000 */
23	OP_SYNC_IF_VALID 	   = V850E2_CACHE_COPR_CFC(1), /* 001 */
24	OP_SYNC_IF_VALID_AND_CLEAR = V850E2_CACHE_COPR_CFC(3), /* 011 */
25	OP_WAY_CLEAR 		   = V850E2_CACHE_COPR_CFC(4), /* 100 */
26	OP_FILL 		   = V850E2_CACHE_COPR_CFC(5), /* 101 */
27	OP_CLEAR 		   = V850E2_CACHE_COPR_CFC(6), /* 110 */
28	OP_CREATE_DIRTY 	   = V850E2_CACHE_COPR_CFC(7)  /* 111 */
29};
30
31/* Which cache to use.  This encoding also corresponds directly to the
32   value we need to write into the COPR register. */
33enum cache {
34	ICACHE = 0,
35	DCACHE = V850E2_CACHE_COPR_LBSL
36};
37
38/* Returns ADDR rounded down to the beginning of its cache-line.  */
39#define CACHE_LINE_ADDR(addr)  \
40   ((addr) & ~(V850E2_CACHE_LINE_SIZE - 1))
41/* Returns END_ADDR rounded up to the `limit' of its cache-line.  */
42#define CACHE_LINE_END_ADDR(end_addr)  \
43   CACHE_LINE_ADDR(end_addr + (V850E2_CACHE_LINE_SIZE - 1))
44
45
46/* Low-level cache ops.  */
47
48/* Apply cache-op OP to all entries in CACHE.  */
49static inline void cache_op_all (enum cache_op op, enum cache cache)
50{
51	int cmd = op | cache | V850E2_CACHE_COPR_WSLE | V850E2_CACHE_COPR_STRT;
52
53	if (op != OP_WAY_CLEAR) {
54		/* The WAY_CLEAR operation does the whole way, but other
55		   ops take begin-index and count params; we just indicate
56		   the entire cache.  */
57		V850E2_CACHE_CADL = 0;
58		V850E2_CACHE_CADH = 0;
59		V850E2_CACHE_CCNT = V850E2_CACHE_WAY_SIZE - 1;
60	}
61
62	V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(0); /* way 0 */
63	V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(1); /* way 1 */
64	V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(2); /* way 2 */
65	V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(3); /* way 3 */
66}
67
68/* Apply cache-op OP to all entries in CACHE covering addresses ADDR
69   through ADDR+LEN.  */
70static inline void cache_op_range (enum cache_op op, u32 addr, u32 len,
71				   enum cache cache)
72{
73	u32 start = CACHE_LINE_ADDR (addr);
74	u32 end = CACHE_LINE_END_ADDR (addr + len);
75	u32 num_lines = (end - start) >> V850E2_CACHE_LINE_SIZE_BITS;
76
77	V850E2_CACHE_CADL = start & 0xFFFF;
78	V850E2_CACHE_CADH = start >> 16;
79	V850E2_CACHE_CCNT = num_lines - 1;
80
81	V850E2_CACHE_COPR = op | cache | V850E2_CACHE_COPR_STRT;
82}
83
84
85/* High-level ops.  */
86
87static void cache_exec_after_store_all (void)
88{
89	cache_op_all (OP_SYNC_IF_DIRTY, DCACHE);
90	cache_op_all (OP_WAY_CLEAR, ICACHE);
91}
92
93static void cache_exec_after_store_range (u32 start, u32 len)
94{
95	cache_op_range (OP_SYNC_IF_DIRTY, start, len, DCACHE);
96	cache_op_range (OP_CLEAR, start, len, ICACHE);
97}
98
99
100/* Exported functions.  */
101
102void flush_icache (void)
103{
104	cache_exec_after_store_all ();
105}
106
107void flush_icache_range (unsigned long start, unsigned long end)
108{
109	cache_exec_after_store_range (start, end - start);
110}
111
112void flush_icache_page (struct vm_area_struct *vma, struct page *page)
113{
114	cache_exec_after_store_range (page_to_virt (page), PAGE_SIZE);
115}
116
117void flush_icache_user_range (struct vm_area_struct *vma, struct page *page,
118			      unsigned long addr, int len)
119{
120	cache_exec_after_store_range (addr, len);
121}
122
123void flush_cache_sigtramp (unsigned long addr)
124{
125	/* For the exact size, see signal.c, but 16 bytes should be enough.  */
126	cache_exec_after_store_range (addr, 16);
127}
128