summaryrefslogtreecommitdiffstats
path: root/post/cpu/ppc4xx/cache.c
blob: 30d50884257ee99def1527839562130bf4367688 (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
/*
 * (C) Copyright 2007
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
 * Author: Igor Lisitsin <igor@emcraft.com>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <common.h>

/* Cache test
 *
 * This test verifies the CPU data and instruction cache using
 * several test scenarios.
 */

#ifdef CONFIG_POST

#include <post.h>

#if CONFIG_POST & CFG_POST_CACHE

#include <asm/mmu.h>
#include <watchdog.h>

#define CACHE_POST_SIZE	1024

void program_tlb(u32 phys_addr, u32 virt_addr, u32 size, u32 tlb_word2_i_value);

int cache_post_test1 (int tlb, void *p, int size);
int cache_post_test2 (int tlb, void *p, int size);
int cache_post_test3 (int tlb, void *p, int size);
int cache_post_test4 (int tlb, void *p, int size);
int cache_post_test5 (int tlb, void *p, int size);
int cache_post_test6 (int tlb, void *p, int size);

static int tlb = -1;		/* index to the victim TLB entry */

#ifdef CONFIG_440
static unsigned char testarea[CACHE_POST_SIZE]
__attribute__((__aligned__(CACHE_POST_SIZE)));
#endif

int cache_post_test (int flags)
{
	void* virt = (void*)CFG_POST_CACHE_ADDR;
	int ints;
	int res = 0;

	/*
	 * All 44x variants deal with cache management differently
	 * because they have the address translation always enabled.
	 * The 40x ppc's don't use address translation in U-Boot at all,
	 * so we have to distinguish here between 40x and 44x.
	 */
#ifdef CONFIG_440
	int word0, i;

	if (tlb < 0) {
		/*
		 * Allocate a new TLB entry, since we are going to modify
		 * the write-through and caching inhibited storage attributes.
		 */
		program_tlb((u32)testarea, (u32)virt,
			    CACHE_POST_SIZE, TLB_WORD2_I_ENABLE);

		/* Find the TLB entry */
		for (i = 0;; i++) {
			if (i >= PPC4XX_TLB_SIZE) {
				printf ("Failed to program tlb entry\n");
				return -1;
			}
			word0 = mftlb1(i);
			if (TLB_WORD0_EPN_DECODE(word0) == (u32)virt) {
				tlb = i;
				break;
			}
		}
	}
#endif
	ints = disable_interrupts ();

	WATCHDOG_RESET ();
	if (res == 0)
		res = cache_post_test1 (tlb, virt, CACHE_POST_SIZE);
	WATCHDOG_RESET ();
	if (res == 0)
		res = cache_post_test2 (tlb, virt, CACHE_POST_SIZE);
	WATCHDOG_RESET ();
	if (res == 0)
		res = cache_post_test3 (tlb, virt, CACHE_POST_SIZE);
	WATCHDOG_RESET ();
	if (res == 0)
		res = cache_post_test4 (tlb, virt, CACHE_POST_SIZE);
	WATCHDOG_RESET ();
	if (res == 0)
		res = cache_post_test5 (tlb, virt, CACHE_POST_SIZE);
	WATCHDOG_RESET ();
	if (res == 0)
		res = cache_post_test6 (tlb, virt, CACHE_POST_SIZE);

	if (ints)
		enable_interrupts ();

#ifdef CONFIG_440
	remove_tlb((u32)virt, CACHE_POST_SIZE);
#endif

	return res;
}

#endif /* CONFIG_POST & CFG_POST_CACHE */
#endif /* CONFIG_POST */