summaryrefslogtreecommitdiff
path: root/arch/nios2/lib/cache.c
blob: 5864d8f0f4733453f6791a16c8e0cca5d5874217 (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
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
 * Copyright (C) 2009, Wind River Systems Inc
 * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
 */

#include <common.h>
#include <cpu_func.h>
#include <asm/cache.h>
#include <asm/global_data.h>

DECLARE_GLOBAL_DATA_PTR;

static void __flush_dcache(unsigned long start, unsigned long end)
{
	unsigned long addr;

	start &= ~(gd->arch.dcache_line_size - 1);
	end += (gd->arch.dcache_line_size - 1);
	end &= ~(gd->arch.dcache_line_size - 1);

	for (addr = start; addr < end; addr += gd->arch.dcache_line_size) {
		__asm__ __volatile__ ("   flushda 0(%0)\n"
					: /* Outputs */
					: /* Inputs  */ "r"(addr)
					/* : No clobber */);
	}
}

static void __flush_dcache_all(unsigned long start, unsigned long end)
{
	unsigned long addr;

	start &= ~(gd->arch.dcache_line_size - 1);
	end += (gd->arch.dcache_line_size - 1);
	end &= ~(gd->arch.dcache_line_size - 1);

	if (end > start + gd->arch.dcache_size)
		end = start + gd->arch.dcache_size;

	for (addr = start; addr < end; addr += gd->arch.dcache_line_size) {
		__asm__ __volatile__ ("   flushd 0(%0)\n"
					: /* Outputs */
					: /* Inputs  */ "r"(addr)
					/* : No clobber */);
	}
}

static void __invalidate_dcache(unsigned long start, unsigned long end)
{
	unsigned long addr;

	start &= ~(gd->arch.dcache_line_size - 1);
	end += (gd->arch.dcache_line_size - 1);
	end &= ~(gd->arch.dcache_line_size - 1);

	for (addr = start; addr < end; addr += gd->arch.dcache_line_size) {
		__asm__ __volatile__ ("   initda 0(%0)\n"
					: /* Outputs */
					: /* Inputs  */ "r"(addr)
					/* : No clobber */);
	}
}

static void __flush_icache(unsigned long start, unsigned long end)
{
	unsigned long addr;

	start &= ~(gd->arch.icache_line_size - 1);
	end += (gd->arch.icache_line_size - 1);
	end &= ~(gd->arch.icache_line_size - 1);

	if (end > start + gd->arch.icache_size)
		end = start + gd->arch.icache_size;

	for (addr = start; addr < end; addr += gd->arch.icache_line_size) {
		__asm__ __volatile__ ("   flushi %0\n"
					: /* Outputs */
					: /* Inputs  */ "r"(addr)
					/* : No clobber */);
	}
	__asm__ __volatile(" flushp\n");
}

void flush_dcache_all(void)
{
	__flush_dcache_all(0, gd->arch.dcache_size);
	__flush_icache(0, gd->arch.icache_size);
}

void flush_dcache_range(unsigned long start, unsigned long end)
{
	if (gd->arch.has_initda)
		__flush_dcache(start, end);
	else
		__flush_dcache_all(start, end);
}

void flush_cache(unsigned long start, unsigned long size)
{
	if (gd->arch.has_initda)
		__flush_dcache(start, start + size);
	else
		__flush_dcache_all(start, start + size);
	__flush_icache(start, start + size);
}

void invalidate_dcache_range(unsigned long start, unsigned long end)
{
	if (gd->arch.has_initda)
		__invalidate_dcache(start, end);
	else
		__flush_dcache_all(start, end);
}

int dcache_status(void)
{
	return 1;
}

void dcache_enable(void)
{
	flush_dcache_all();
}

void dcache_disable(void)
{
	flush_dcache_all();
}