summaryrefslogtreecommitdiff
path: root/arch/sh/cpu/sh4/cache.c
blob: 56161ee72e4bcd19d2f2b8e1de9ea04263f9a2b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// SPDX-License-Identifier: GPL-2.0+
/*
 * (C) Copyright 2016 Vladimir Zapolskiy <vz@mleia.com>
 * (C) Copyright 2007 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
 */

#include <command.h>
#include <cpu_func.h>
#include <stdio.h>
#include <asm/cache.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <linux/errno.h>

#define CACHE_VALID       1
#define CACHE_UPDATED     2

static inline void cache_wback_all(void)
{
	unsigned long addr, data, i, j;

	for (i = 0; i < CACHE_OC_NUM_ENTRIES; i++) {
		for (j = 0; j < CACHE_OC_NUM_WAYS; j++) {
			addr = CACHE_OC_ADDRESS_ARRAY
				| (j << CACHE_OC_WAY_SHIFT)
				| (i << CACHE_OC_ENTRY_SHIFT);
			data = inl(addr);
			if (data & CACHE_UPDATED) {
				data &= ~CACHE_UPDATED;
				outl(data, addr);
			}
		}
	}
}

#define CACHE_ENABLE		0
#define CACHE_DISABLE		1
#define CACHE_INVALIDATE	2

static int cache_control(unsigned int cmd)
{
	unsigned long ccr;

	jump_to_P2();
	ccr = inl(CCR);

	if (ccr & CCR_CACHE_ENABLE)
		cache_wback_all();

	if (cmd == CACHE_INVALIDATE)
		outl(CCR_CACHE_ICI | ccr, CCR);
	else if (cmd == CACHE_DISABLE)
		outl(CCR_CACHE_STOP, CCR);
	else
		outl(CCR_CACHE_INIT, CCR);
	back_to_P1();

	return 0;
}

void flush_dcache_range(unsigned long start, unsigned long end)
{
	u32 v;

	start &= ~(L1_CACHE_BYTES - 1);
	for (v = start; v < end; v += L1_CACHE_BYTES) {
		asm volatile ("ocbp     %0" :	/* no output */
			      : "m" (__m(v)));
	}
}

/*
 * Default implementation:
 * do a range flush for the entire range
 */
void flush_dcache_all(void)
{
	flush_dcache_range(0, ~0);
}

void invalidate_dcache_range(unsigned long start, unsigned long end)
{
	u32 v;

	start &= ~(L1_CACHE_BYTES - 1);
	for (v = start; v < end; v += L1_CACHE_BYTES) {
		asm volatile ("ocbi     %0" :	/* no output */
			      : "m" (__m(v)));
	}
}

void flush_cache(unsigned long addr, unsigned long size)
{
	flush_dcache_range(addr , addr + size);
}

void icache_enable(void)
{
	cache_control(CACHE_ENABLE);
}

void icache_disable(void)
{
	cache_control(CACHE_DISABLE);
}

void invalidate_icache_all(void)
{
	cache_control(CACHE_INVALIDATE);
}

int icache_status(void)
{
	return 0;
}

void dcache_enable(void)
{
}

void dcache_disable(void)
{
}

int dcache_status(void)
{
	return 0;
}

int __weak pgprot_set_attrs(phys_addr_t addr, size_t size, enum pgprot_attrs perm)
{
	return -ENOSYS;
}