1/*-
2 * Copyright (c) 2004 Juli Mallett.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include <sys/param.h>
31#include <sys/kernel.h>
32#include <sys/module.h>
33#include <sys/stdint.h>
34
35#include <sys/bus.h>
36#include <sys/rman.h>
37#include <sys/sysctl.h>
38#include <sys/systm.h>
39
40#include <vm/vm.h>
41#include <vm/vm_page.h>
42
43#include <machine/cache.h>
44#include <machine/cpufunc.h>
45#include <machine/cpuinfo.h>
46#include <machine/cpuregs.h>
47#include <machine/intr_machdep.h>
48#include <machine/locore.h>
49#include <machine/pte.h>
50#include <machine/tlb.h>
51#include <machine/hwfunc.h>
52
53#if defined(CPU_CNMIPS)
54#include <contrib/octeon-sdk/cvmx.h>
55#include <contrib/octeon-sdk/octeon-model.h>
56#endif
57
58static void cpu_identify(void);
59
60struct mips_cpuinfo cpuinfo;
61
62/*
63 * Attempt to identify the MIPS CPU as much as possible.
64 *
65 * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant.
66 * XXX: For now, skip config register selections 2 and 3
67 * as we don't currently use L2/L3 cache or additional
68 * MIPS32 processor features.
69 */
70static void
71mips_get_identity(struct mips_cpuinfo *cpuinfo)
72{
73	u_int32_t prid;
74	u_int32_t cfg0;
75	u_int32_t cfg1;
76#if defined(CPU_CNMIPS)
77	u_int32_t cfg4;
78#endif
79	u_int32_t tmp;
80
81	memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
82
83	/* Read and store the PrID ID for CPU identification. */
84	prid = mips_rd_prid();
85	cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
86	cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
87	cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
88
89	/* Read config register selection 0 to learn TLB type. */
90	cfg0 = mips_rd_config();
91
92	cpuinfo->tlb_type =
93	    ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
94	cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
95
96	/* If config register selection 1 does not exist, exit. */
97	if (!(cfg0 & MIPS_CONFIG_CM))
98		return;
99
100	/* Learn TLB size and L1 cache geometry. */
101	cfg1 = mips_rd_config1();
102
103#if defined(CPU_NLM)
104	/* Account for Extended TLB entries in XLP */
105	tmp = mips_rd_config6();
106	cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1;
107#elif defined(BERI_LARGE_TLB)
108	/* Check if we support extended TLB entries and if so activate. */
109	tmp = mips_rd_config5();
110#define	BERI_CP5_LTLB_SUPPORTED	0x1
111	if (tmp & BERI_CP5_LTLB_SUPPORTED) {
112		/* See how many extra TLB entries we have. */
113		tmp = mips_rd_config6();
114		cpuinfo->tlb_nentries = (tmp >> 16) + 1;
115		/* Activate the extended entries. */
116		mips_wr_config6(tmp|0x4);
117	} else
118#endif
119#if !defined(CPU_NLM)
120	cpuinfo->tlb_nentries =
121	    ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
122#endif
123#if defined(CPU_CNMIPS)
124	/* Add extended TLB size information from config4.  */
125	cfg4 = mips_rd_config4();
126	if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT)
127		cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40;
128#endif
129
130	/* L1 instruction cache. */
131#ifdef MIPS_DISABLE_L1_CACHE
132	cpuinfo->l1.ic_linesize = 0;
133#else
134	tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
135	if (tmp != 0) {
136		cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
137		cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
138		cpuinfo->l1.ic_nsets =
139	    		1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
140	}
141#endif
142
143	/* L1 data cache. */
144#ifdef MIPS_DISABLE_L1_CACHE
145	cpuinfo->l1.dc_linesize = 0;
146#else
147#ifndef CPU_CNMIPS
148	tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
149	if (tmp != 0) {
150		cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
151		cpuinfo->l1.dc_nways =
152		    (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
153		cpuinfo->l1.dc_nsets =
154		    1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
155	}
156#else
157	/*
158	 * Some Octeon cache configuration parameters are by model family, not
159	 * config1.
160	 */
161	if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
162		/* Octeon and Octeon XL.  */
163		cpuinfo->l1.dc_nsets = 1;
164		cpuinfo->l1.dc_nways = 64;
165	} else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
166		/* Octeon Plus.  */
167		cpuinfo->l1.dc_nsets = 2;
168		cpuinfo->l1.dc_nways = 64;
169	} else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
170		/* Octeon II.  */
171		cpuinfo->l1.dc_nsets = 8;
172		cpuinfo->l1.dc_nways = 32;
173
174		cpuinfo->l1.ic_nsets = 8;
175		cpuinfo->l1.ic_nways = 37;
176	} else {
177		panic("%s: unsupported Cavium Networks CPU.", __func__);
178	}
179
180	/* All Octeon models use 128 byte line size.  */
181	cpuinfo->l1.dc_linesize = 128;
182#endif
183#endif
184
185	cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize
186	    * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
187	cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize
188	    * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
189}
190
191void
192mips_cpu_init(void)
193{
194	platform_cpu_init();
195	mips_get_identity(&cpuinfo);
196	num_tlbentries = cpuinfo.tlb_nentries;
197	mips_wr_wired(0);
198	tlb_invalidate_all();
199	mips_wr_wired(VMWIRED_ENTRIES);
200	mips_config_cache(&cpuinfo);
201	mips_vector_init();
202
203	mips_icache_sync_all();
204	mips_dcache_wbinv_all();
205	/* Print some info about CPU */
206	cpu_identify();
207}
208
209static void
210cpu_identify(void)
211{
212	uint32_t cfg0, cfg1, cfg2, cfg3;
213	printf("cpu%d: ", 0);   /* XXX per-cpu */
214	switch (cpuinfo.cpu_vendor) {
215	case MIPS_PRID_CID_MTI:
216		printf("MIPS Technologies");
217		break;
218	case MIPS_PRID_CID_BROADCOM:
219	case MIPS_PRID_CID_SIBYTE:
220		printf("Broadcom");
221		break;
222	case MIPS_PRID_CID_ALCHEMY:
223		printf("AMD");
224		break;
225	case MIPS_PRID_CID_SANDCRAFT:
226		printf("Sandcraft");
227		break;
228	case MIPS_PRID_CID_PHILIPS:
229		printf("Philips");
230		break;
231	case MIPS_PRID_CID_TOSHIBA:
232		printf("Toshiba");
233		break;
234	case MIPS_PRID_CID_LSI:
235		printf("LSI");
236		break;
237	case MIPS_PRID_CID_LEXRA:
238		printf("Lexra");
239		break;
240	case MIPS_PRID_CID_RMI:
241		printf("RMI");
242		break;
243	case MIPS_PRID_CID_CAVIUM:
244		printf("Cavium");
245		break;
246	case MIPS_PRID_CID_PREHISTORIC:
247	default:
248		printf("Unknown cid %#x", cpuinfo.cpu_vendor);
249		break;
250	}
251	printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
252
253	printf("  MMU: ");
254	if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
255		printf("none present\n");
256	} else {
257		if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
258			printf("Standard TLB");
259		} else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
260			printf("Standard BAT");
261		} else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
262			printf("Fixed mapping");
263		}
264		printf(", %d entries\n", cpuinfo.tlb_nentries);
265	}
266
267	printf("  L1 i-cache: ");
268	if (cpuinfo.l1.ic_linesize == 0) {
269		printf("disabled");
270	} else {
271		if (cpuinfo.l1.ic_nways == 1) {
272			printf("direct-mapped with");
273		} else {
274			printf ("%d ways of", cpuinfo.l1.ic_nways);
275		}
276		printf(" %d sets, %d bytes per line\n",
277		    cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
278	}
279
280	printf("  L1 d-cache: ");
281	if (cpuinfo.l1.dc_linesize == 0) {
282		printf("disabled");
283	} else {
284		if (cpuinfo.l1.dc_nways == 1) {
285			printf("direct-mapped with");
286		} else {
287			printf ("%d ways of", cpuinfo.l1.dc_nways);
288		}
289		printf(" %d sets, %d bytes per line\n",
290		    cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
291	}
292
293	cfg0 = mips_rd_config();
294	/* If config register selection 1 does not exist, exit. */
295	if (!(cfg0 & MIPS_CONFIG_CM))
296		return;
297
298	cfg1 = mips_rd_config1();
299	printf("  Config1=0x%b\n", cfg1,
300	    "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
301
302	/* If config register selection 2 does not exist, exit. */
303	if (!(cfg1 & MIPS_CONFIG_CM))
304		return;
305	cfg2 = mips_rd_config2();
306	/*
307	 * Config2 contains no useful information other then Config3
308	 * existence flag
309	 */
310
311	/* If config register selection 3 does not exist, exit. */
312	if (!(cfg2 & MIPS_CONFIG_CM))
313		return;
314	cfg3 = mips_rd_config3();
315
316	/* Print Config3 if it contains any useful info */
317	if (cfg3 & ~(0x80000000))
318		printf("  Config3=0x%b\n", cfg3, "\20\2SmartMIPS\1TraceLogic");
319}
320
321static struct rman cpu_hardirq_rman;
322
323static devclass_t cpu_devclass;
324
325/*
326 * Device methods
327 */
328static int cpu_probe(device_t);
329static int cpu_attach(device_t);
330static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
331					   u_long, u_long, u_long, u_int);
332static int cpu_setup_intr(device_t, device_t, struct resource *, int,
333			  driver_filter_t *f, driver_intr_t *, void *,
334			  void **);
335
336static device_method_t cpu_methods[] = {
337	/* Device interface */
338	DEVMETHOD(device_probe,		cpu_probe),
339	DEVMETHOD(device_attach,	cpu_attach),
340	DEVMETHOD(device_detach,	bus_generic_detach),
341	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
342
343	/* Bus interface */
344	DEVMETHOD(bus_alloc_resource,	cpu_alloc_resource),
345	DEVMETHOD(bus_setup_intr,	cpu_setup_intr),
346	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
347
348	{ 0, 0 }
349};
350
351static driver_t cpu_driver = {
352	"cpu", cpu_methods, 1
353};
354
355static int
356cpu_probe(device_t dev)
357{
358	return (0);
359}
360
361static int
362cpu_attach(device_t dev)
363{
364	int error;
365#ifdef notyet
366	device_t clock;
367#endif
368
369	cpu_hardirq_rman.rm_start = 0;
370	cpu_hardirq_rman.rm_end = 5;
371	cpu_hardirq_rman.rm_type = RMAN_ARRAY;
372	cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
373
374	error = rman_init(&cpu_hardirq_rman);
375	if (error != 0) {
376		device_printf(dev, "failed to initialize irq resources\n");
377		return (error);
378	}
379	/* XXX rman_manage_all. */
380	error = rman_manage_region(&cpu_hardirq_rman,
381				   cpu_hardirq_rman.rm_start,
382				   cpu_hardirq_rman.rm_end);
383	if (error != 0) {
384		device_printf(dev, "failed to manage irq resources\n");
385		return (error);
386	}
387
388	if (device_get_unit(dev) != 0)
389		panic("can't attach more cpus");
390	device_set_desc(dev, "MIPS32 processor");
391
392#ifdef notyet
393	clock = device_add_child(dev, "clock", device_get_unit(dev));
394	if (clock == NULL)
395		device_printf(dev, "clock failed to attach");
396#endif
397
398	return (bus_generic_attach(dev));
399}
400
401static struct resource *
402cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
403		   u_long start, u_long end, u_long count, u_int flags)
404{
405	struct resource *res;
406
407	if (type != SYS_RES_IRQ)
408		return (NULL);
409	res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
410				    child);
411	return (res);
412}
413
414static int
415cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
416	       driver_filter_t *filt, driver_intr_t *handler, void *arg,
417	       void **cookiep)
418{
419	int error;
420	int intr;
421
422	error = rman_activate_resource(res);
423	if (error != 0) {
424		device_printf(child, "could not activate irq\n");
425		return (error);
426	}
427
428	intr = rman_get_start(res);
429
430	cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg,
431	    intr, flags, cookiep);
432	device_printf(child, "established CPU interrupt %d\n", intr);
433	return (0);
434}
435
436DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);
437