1/*
2 * arch/sh/kernel/cpu/sh4/probe.c
3 *
4 * CPU Subtype Probing for SH-4.
5 *
6 * Copyright (C) 2001 - 2006  Paul Mundt
7 * Copyright (C) 2003  Richard Curnow
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License.  See the file "COPYING" in the main directory of this archive
11 * for more details.
12 */
13#include <linux/init.h>
14#include <linux/io.h>
15#include <linux/smp.h>
16#include <asm/processor.h>
17#include <asm/cache.h>
18
19int __init detect_cpu_and_cache_system(void)
20{
21	unsigned long pvr, prr, cvr;
22	unsigned long size;
23
24	static unsigned long sizes[16] = {
25		[1] = (1 << 12),
26		[2] = (1 << 13),
27		[4] = (1 << 14),
28		[8] = (1 << 15),
29		[9] = (1 << 16)
30	};
31
32	pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffffff;
33	prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff;
34	cvr = (ctrl_inl(CCN_CVR));
35
36	/*
37	 * Setup some sane SH-4 defaults for the icache
38	 */
39	current_cpu_data.icache.way_incr	= (1 << 13);
40	current_cpu_data.icache.entry_shift	= 5;
41	current_cpu_data.icache.sets		= 256;
42	current_cpu_data.icache.ways		= 1;
43	current_cpu_data.icache.linesz		= L1_CACHE_BYTES;
44
45	/*
46	 * And again for the dcache ..
47	 */
48	current_cpu_data.dcache.way_incr	= (1 << 14);
49	current_cpu_data.dcache.entry_shift	= 5;
50	current_cpu_data.dcache.sets		= 512;
51	current_cpu_data.dcache.ways		= 1;
52	current_cpu_data.dcache.linesz		= L1_CACHE_BYTES;
53
54	/*
55	 * Setup some generic flags we can probe
56	 * (L2 and DSP detection only work on SH-4A)
57	 */
58	if (((pvr >> 16) & 0xff) == 0x10) {
59		if ((cvr & 0x02000000) == 0)
60			current_cpu_data.flags |= CPU_HAS_L2_CACHE;
61		if ((cvr & 0x10000000) == 0)
62			current_cpu_data.flags |= CPU_HAS_DSP;
63
64		current_cpu_data.flags |= CPU_HAS_LLSC;
65	}
66
67	/* FPU detection works for everyone */
68	if ((cvr & 0x20000000) == 1)
69		current_cpu_data.flags |= CPU_HAS_FPU;
70
71	/* Mask off the upper chip ID */
72	pvr &= 0xffff;
73
74	/*
75	 * Probe the underlying processor version/revision and
76	 * adjust cpu_data setup accordingly.
77	 */
78	switch (pvr) {
79	case 0x205:
80		current_cpu_data.type = CPU_SH7750;
81		current_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
82				   CPU_HAS_PERF_COUNTER;
83		break;
84	case 0x206:
85		current_cpu_data.type = CPU_SH7750S;
86		current_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
87				   CPU_HAS_PERF_COUNTER;
88		break;
89	case 0x1100:
90		current_cpu_data.type = CPU_SH7751;
91		current_cpu_data.flags |= CPU_HAS_FPU;
92		break;
93	case 0x2000:
94		current_cpu_data.type = CPU_SH73180;
95		current_cpu_data.icache.ways = 4;
96		current_cpu_data.dcache.ways = 4;
97		current_cpu_data.flags |= CPU_HAS_LLSC;
98		break;
99	case 0x2001:
100	case 0x2004:
101		current_cpu_data.type = CPU_SH7770;
102		current_cpu_data.icache.ways = 4;
103		current_cpu_data.dcache.ways = 4;
104
105		current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_LLSC;
106		break;
107	case 0x2006:
108	case 0x200A:
109		if (prr == 0x61)
110			current_cpu_data.type = CPU_SH7781;
111		else
112			current_cpu_data.type = CPU_SH7780;
113
114		current_cpu_data.icache.ways = 4;
115		current_cpu_data.dcache.ways = 4;
116
117		current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
118				   CPU_HAS_LLSC;
119		break;
120	case 0x3000:
121	case 0x3003:
122	case 0x3009:
123		current_cpu_data.type = CPU_SH7343;
124		current_cpu_data.icache.ways = 4;
125		current_cpu_data.dcache.ways = 4;
126		current_cpu_data.flags |= CPU_HAS_LLSC;
127		break;
128	case 0x3004:
129	case 0x3007:
130		current_cpu_data.type = CPU_SH7785;
131		current_cpu_data.icache.ways = 4;
132		current_cpu_data.dcache.ways = 4;
133		current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
134					  CPU_HAS_LLSC;
135		break;
136	case 0x3008:
137		if (prr == 0xa0) {
138			current_cpu_data.type = CPU_SH7722;
139			current_cpu_data.icache.ways = 4;
140			current_cpu_data.dcache.ways = 4;
141			current_cpu_data.flags |= CPU_HAS_LLSC;
142		}
143		break;
144	case 0x8000:
145		current_cpu_data.type = CPU_ST40RA;
146		current_cpu_data.flags |= CPU_HAS_FPU;
147		break;
148	case 0x8100:
149		current_cpu_data.type = CPU_ST40GX1;
150		current_cpu_data.flags |= CPU_HAS_FPU;
151		break;
152	case 0x700:
153		current_cpu_data.type = CPU_SH4_501;
154		current_cpu_data.icache.ways = 2;
155		current_cpu_data.dcache.ways = 2;
156		break;
157	case 0x600:
158		current_cpu_data.type = CPU_SH4_202;
159		current_cpu_data.icache.ways = 2;
160		current_cpu_data.dcache.ways = 2;
161		current_cpu_data.flags |= CPU_HAS_FPU;
162		break;
163	case 0x500 ... 0x501:
164		switch (prr) {
165		case 0x10:
166			current_cpu_data.type = CPU_SH7750R;
167			break;
168		case 0x11:
169			current_cpu_data.type = CPU_SH7751R;
170			break;
171		case 0x50 ... 0x5f:
172			current_cpu_data.type = CPU_SH7760;
173			break;
174		}
175
176		current_cpu_data.icache.ways = 2;
177		current_cpu_data.dcache.ways = 2;
178
179		current_cpu_data.flags |= CPU_HAS_FPU;
180
181		break;
182	default:
183		current_cpu_data.type = CPU_SH_NONE;
184		break;
185	}
186
187#ifdef CONFIG_SH_DIRECT_MAPPED
188	current_cpu_data.icache.ways = 1;
189	current_cpu_data.dcache.ways = 1;
190#endif
191
192#ifdef CONFIG_CPU_HAS_PTEA
193	current_cpu_data.flags |= CPU_HAS_PTEA;
194#endif
195
196	/*
197	 * On anything that's not a direct-mapped cache, look to the CVR
198	 * for I/D-cache specifics.
199	 */
200	if (current_cpu_data.icache.ways > 1) {
201		size = sizes[(cvr >> 20) & 0xf];
202		current_cpu_data.icache.way_incr	= (size >> 1);
203		current_cpu_data.icache.sets		= (size >> 6);
204
205	}
206
207	/* And the rest of the D-cache */
208	if (current_cpu_data.dcache.ways > 1) {
209		size = sizes[(cvr >> 16) & 0xf];
210		current_cpu_data.dcache.way_incr	= (size >> 1);
211		current_cpu_data.dcache.sets		= (size >> 6);
212	}
213
214	/*
215	 * Setup the L2 cache desc
216	 *
217	 * SH-4A's have an optional PIPT L2.
218	 */
219	if (current_cpu_data.flags & CPU_HAS_L2_CACHE) {
220		/*
221		 * Size calculation is much more sensible
222		 * than it is for the L1.
223		 *
224		 * Sizes are 128KB, 258KB, 512KB, and 1MB.
225		 */
226		size = (cvr & 0xf) << 17;
227
228		BUG_ON(!size);
229
230		current_cpu_data.scache.way_incr	= (1 << 16);
231		current_cpu_data.scache.entry_shift	= 5;
232		current_cpu_data.scache.ways		= 4;
233		current_cpu_data.scache.linesz		= L1_CACHE_BYTES;
234
235		current_cpu_data.scache.entry_mask	=
236			(current_cpu_data.scache.way_incr -
237			 current_cpu_data.scache.linesz);
238
239		current_cpu_data.scache.sets		= size /
240			(current_cpu_data.scache.linesz *
241			 current_cpu_data.scache.ways);
242
243		current_cpu_data.scache.way_size	=
244			(current_cpu_data.scache.sets *
245			 current_cpu_data.scache.linesz);
246	}
247
248	return 0;
249}
250