1/*-
2 * Copyright 2003-2011 Netlogic Microsystems (Netlogic). All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in
13 *    the documentation and/or other materials provided with the
14 *    distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY Netlogic Microsystems ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * NETLOGIC_BSD */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD$");
32
33#include "opt_ddb.h"
34
35#include <sys/param.h>
36#include <sys/bus.h>
37#include <sys/conf.h>
38#include <sys/rtprio.h>
39#include <sys/systm.h>
40#include <sys/interrupt.h>
41#include <sys/limits.h>
42#include <sys/lock.h>
43#include <sys/malloc.h>
44#include <sys/mutex.h>
45#include <sys/random.h>
46
47#include <sys/cons.h>		/* cinit() */
48#include <sys/kdb.h>
49#include <sys/reboot.h>
50#include <sys/queue.h>
51#include <sys/smp.h>
52#include <sys/timetc.h>
53
54#include <vm/vm.h>
55#include <vm/vm_page.h>
56
57#include <machine/cpu.h>
58#include <machine/cpufunc.h>
59#include <machine/cpuinfo.h>
60#include <machine/tlb.h>
61#include <machine/cpuregs.h>
62#include <machine/frame.h>
63#include <machine/hwfunc.h>
64#include <machine/md_var.h>
65#include <machine/asm.h>
66#include <machine/pmap.h>
67#include <machine/trap.h>
68#include <machine/clock.h>
69#include <machine/fls64.h>
70#include <machine/intr_machdep.h>
71#include <machine/smp.h>
72
73#include <mips/nlm/hal/mips-extns.h>
74#include <mips/nlm/hal/haldefs.h>
75#include <mips/nlm/hal/iomap.h>
76#include <mips/nlm/hal/sys.h>
77#include <mips/nlm/hal/pic.h>
78#include <mips/nlm/hal/uart.h>
79#include <mips/nlm/hal/mmu.h>
80#include <mips/nlm/hal/bridge.h>
81#include <mips/nlm/hal/cpucontrol.h>
82
83#include <mips/nlm/clock.h>
84#include <mips/nlm/interrupt.h>
85#include <mips/nlm/board.h>
86#include <mips/nlm/xlp.h>
87
88/* 4KB static data aread to keep a copy of the bootload env until
89   the dynamic kenv is setup */
90char boot1_env[4096];
91int xlp_argc;
92char **xlp_argv, **xlp_envp;
93
94uint64_t xlp_cpu_frequency;
95uint64_t xlp_io_base = MIPS_PHYS_TO_KSEG1(XLP_DEFAULT_IO_BASE);
96
97int xlp_ncores;
98int xlp_threads_per_core;
99uint32_t xlp_hw_thread_mask;
100int xlp_cpuid_to_hwtid[MAXCPU];
101int xlp_hwtid_to_cpuid[MAXCPU];
102uint64_t xlp_pic_base;
103
104static int xlp_mmuval;
105
106extern uint32_t _end;
107extern char XLPResetEntry[], XLPResetEntryEnd[];
108
109static void
110xlp_setup_core(void)
111{
112	uint64_t reg;
113
114	reg = nlm_mfcr(LSU_DEFEATURE);
115	/* Enable Unaligned and L2HPE */
116	reg |= (1 << 30) | (1 << 23);
117	/*
118	 * Experimental : Enable SUE
119	 * Speculative Unmap Enable. Enable speculative L2 cache request for
120	 * unmapped access.
121	 */
122	reg |= (1ull << 31);
123	/* Clear S1RCM  - A0 errata */
124	reg &= ~0xeull;
125	nlm_mtcr(LSU_DEFEATURE, reg);
126
127	reg = nlm_mfcr(SCHED_DEFEATURE);
128	/* Experimental: Disable BRU accepting ALU ops - A0 errata */
129	reg |= (1 << 24);
130	nlm_mtcr(SCHED_DEFEATURE, reg);
131}
132
133static void
134xlp_setup_mmu(void)
135{
136
137	nlm_setup_extended_pagemask(0); /* pagemask = 0 for 4K pages */
138	nlm_large_variable_tlb_en(0);
139	nlm_extended_tlb_en(1);
140	nlm_mmu_setup(0, 0, 0);
141}
142
143static void
144xlp_parse_mmu_options(void)
145{
146	int i, j, k;
147	uint32_t cpu_map = xlp_hw_thread_mask;
148	uint32_t core0_thr_mask, core_thr_mask;
149
150#ifndef SMP /* Uniprocessor! */
151	if (cpu_map != 0x1) {
152		printf("WARNING: Starting uniprocessor kernel on cpumask [0x%lx]!\n"
153		    "WARNING: Other CPUs will be unused.\n", (u_long)cpu_map);
154		cpu_map = 0x1;
155	}
156#endif
157
158	xlp_ncores = 1;
159	core0_thr_mask = cpu_map & 0xf;
160	switch (core0_thr_mask) {
161	case 1:
162		xlp_threads_per_core = 1;
163		xlp_mmuval = 0;
164	       	break;
165	case 3:
166		xlp_threads_per_core = 2;
167		xlp_mmuval = 2;
168	       	break;
169	case 0xf:
170		xlp_threads_per_core = 4;
171		xlp_mmuval = 3;
172	       	break;
173	default:
174		goto unsupp;
175	}
176
177	/* Verify other cores CPU masks */
178	for (i = 1; i < XLP_MAX_CORES; i++) {
179		core_thr_mask = (cpu_map >> (i*4)) & 0xf;
180		if (core_thr_mask) {
181			if (core_thr_mask != core0_thr_mask)
182				goto unsupp;
183			xlp_ncores++;
184		}
185	}
186
187	xlp_hw_thread_mask = cpu_map;
188	/* setup hardware processor id to cpu id mapping */
189	for (i = 0; i< MAXCPU; i++)
190		xlp_cpuid_to_hwtid[i] =
191		    xlp_hwtid_to_cpuid [i] = -1;
192	for (i = 0, k = 0; i < XLP_MAX_CORES; i++) {
193		if (((cpu_map >> (i*4)) & 0xf) == 0)
194			continue;
195		for (j = 0; j < xlp_threads_per_core; j++) {
196			xlp_cpuid_to_hwtid[k] = i*4 + j;
197			xlp_hwtid_to_cpuid[i*4 + j] = k;
198			k++;
199		}
200	}
201
202#ifdef SMP
203	/*
204	 * We will enable the other threads in core 0 here
205	 * so that the TLB and cache info is correct when
206	 * mips_init runs
207	 */
208	xlp_enable_threads(xlp_mmuval);
209#endif
210	/* setup for the startup core */
211	xlp_setup_mmu();
212	return;
213
214unsupp:
215	printf("ERROR : Unsupported CPU mask [use 1,2 or 4 threads per core].\n"
216	    "\tcore0 thread mask [%lx], boot cpu mask [%lx].\n",
217	    (u_long)core0_thr_mask, (u_long)cpu_map);
218	panic("Invalid CPU mask - halting.\n");
219	return;
220}
221
222static void
223xlp_set_boot_flags(void)
224{
225	char *p;
226
227	p = getenv("bootflags");
228	if (p == NULL)
229		return;
230
231	for (; p && *p != '\0'; p++) {
232		switch (*p) {
233		case 'd':
234		case 'D':
235			boothowto |= RB_KDB;
236			break;
237		case 'g':
238		case 'G':
239			boothowto |= RB_GDB;
240			break;
241		case 'v':
242		case 'V':
243			boothowto |= RB_VERBOSE;
244			break;
245
246		case 's':	/* single-user (default, supported for sanity) */
247		case 'S':
248			boothowto |= RB_SINGLE;
249			break;
250
251		default:
252			printf("Unrecognized boot flag '%c'.\n", *p);
253			break;
254		}
255	}
256
257	freeenv(p);
258	return;
259}
260
261static void
262mips_init(void)
263{
264	init_param1();
265	init_param2(physmem);
266
267	mips_cpu_init();
268	cpuinfo.cache_coherent_dma = TRUE;
269	pmap_bootstrap();
270#ifdef DDB
271	kdb_init();
272	if (boothowto & RB_KDB) {
273		kdb_enter("Boot flags requested debugger", NULL);
274	}
275#endif
276	mips_proc0_init();
277	mutex_init();
278}
279
280unsigned int
281platform_get_timecount(struct timecounter *tc __unused)
282{
283	uint64_t count = nlm_pic_read_timer(xlp_pic_base, PIC_CLOCK_TIMER);
284
285	return (unsigned int)~count;
286}
287
288static void
289xlp_pic_init(void)
290{
291	struct timecounter pic_timecounter = {
292		platform_get_timecount, /* get_timecount */
293		0,                      /* no poll_pps */
294		~0U,                    /* counter_mask */
295		XLP_IO_CLK,            /* frequency */
296		"XLRPIC",               /* name */
297		2000,                   /* quality (adjusted in code) */
298	};
299        int i;
300
301	xlp_pic_base = nlm_get_pic_regbase(0);  /* TOOD: Add other nodes */
302        printf("Initializing PIC...@%jx\n", (uintmax_t)xlp_pic_base);
303	/* Bind all PIC irqs to cpu 0 */
304        for(i = 0; i < PIC_NUM_IRTS; i++) {
305                nlm_pic_write_irt(xlp_pic_base, i, 0, 0, 1, 0,
306		    1, 0, 0x1);
307        }
308
309	nlm_pic_set_timer(xlp_pic_base, PIC_CLOCK_TIMER, ~0ULL, 0, 0);
310	platform_timecounter = &pic_timecounter;
311}
312
313#if defined(__mips_n32) || defined(__mips_n64) /* PHYSADDR_64_BIT */
314#ifdef XLP_SIM
315#define	XLP_MEM_LIM	0x200000000ULL
316#else
317#define	XLP_MEM_LIM	0x10000000000ULL
318#endif
319#else
320#define	XLP_MEM_LIM	0xfffff000UL
321#endif
322static void
323xlp_mem_init(void)
324{
325	uint64_t bridgebase = nlm_get_bridge_regbase(0);  /* TOOD: Add other nodes */
326	vm_size_t physsz = 0;
327        uint64_t base, lim, val;
328	int i, j;
329
330        for (i = 0, j = 0; i < 8; i++) {
331		val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_BAR(i));
332		base = ((val >>  12) & 0xfffff) << 20;
333		val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_LIMIT(i));
334                lim = ((val >>  12) & 0xfffff) << 20;
335
336		/* BAR not enabled */
337		if (lim == 0)
338			continue;
339
340		/* first bar, start a bit after end */
341		if (base == 0) {
342			base = (vm_paddr_t)MIPS_KSEG0_TO_PHYS(&_end) + 0x20000;
343			lim  = 0x0c000000;  /* TODO : hack to avoid uboot packet mem */
344		}
345		if (base >= XLP_MEM_LIM) {
346			printf("Mem [%d]: Ignore %#jx - %#jx\n", i,
347			   (intmax_t)base, (intmax_t)lim);
348			continue;
349		}
350		if (lim > XLP_MEM_LIM) {
351			printf("Mem [%d]: Restrict %#jx -> %#jx\n", i,
352			    (intmax_t)lim, (intmax_t)XLP_MEM_LIM);
353			lim = XLP_MEM_LIM;
354		}
355		if (lim <= base) {
356			printf("Mem[%d]: Malformed %#jx -> %#jx\n", i,
357			    (intmax_t)base, (intmax_t)lim);
358			continue;
359		}
360
361		/*
362		 * Exclude reset entry memory range 0x1fc00000 - 0x20000000
363		 * from free memory
364		 */
365		if (base <= 0x1fc00000 && (base + lim) > 0x1fc00000) {
366			uint64_t base0, lim0, base1, lim1;
367
368			base0 = base;
369			lim0 = 0x1fc00000;
370			base1 = 0x20000000;
371			lim1 = lim;
372
373			if (lim0 > base0) {
374				phys_avail[j++] = (vm_paddr_t)base0;
375				phys_avail[j++] = (vm_paddr_t)lim0;
376				physsz += lim0 - base0;
377				printf("Mem[%d]: %#jx - %#jx (excl reset)\n", i,
378				    (intmax_t)base0, (intmax_t)lim0);
379			}
380			if (lim1 > base1) {
381				phys_avail[j++] = (vm_paddr_t)base1;
382				phys_avail[j++] = (vm_paddr_t)lim1;
383				physsz += lim1 - base1;
384				printf("Mem[%d]: %#jx - %#jx (excl reset)\n", i,
385				    (intmax_t)base1, (intmax_t)lim1);
386			}
387		} else {
388			phys_avail[j++] = (vm_paddr_t)base;
389			phys_avail[j++] = (vm_paddr_t)lim;
390			physsz += lim - base;
391			printf("Mem[%d]: %#jx - %#jx\n", i,
392			    (intmax_t)base, (intmax_t)lim);
393		}
394
395        }
396
397	/* setup final entry with 0 */
398	phys_avail[j] = phys_avail[j + 1] = 0;
399
400	/* copy phys_avail to dump_avail */
401	for(i = 0; i <= j + 1; i++)
402		dump_avail[i] = phys_avail[i];
403
404	realmem = physmem = btoc(physsz);
405}
406
407static uint32_t
408xlp_get_cpu_frequency(void)
409{
410	uint64_t  sysbase = nlm_get_sys_regbase(0);
411	unsigned int pll_divf, pll_divr, dfs_div, num, denom;
412	uint32_t val;
413
414	val = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG);
415	pll_divf = (val >> 10) & 0x7f;
416	pll_divr = (val >> 8)  & 0x3;
417	dfs_div  = (val >> 17) & 0x3;
418
419	num = pll_divf + 1;
420	denom = 3 * (pll_divr + 1) * (1<< (dfs_div + 1));
421	val = 800000000ULL * num / denom;
422	return (val);
423}
424
425void
426platform_start(__register_t a0 __unused,
427    __register_t a1 __unused,
428    __register_t a2 __unused,
429    __register_t a3 __unused)
430{
431	int i;
432
433	xlp_argc = 1;
434	/*
435	 * argv and envp are passed in array of 32bit pointers
436	 */
437	xlp_argv = NULL;
438	xlp_envp = NULL;
439
440	/* Initialize pcpu stuff */
441	mips_pcpu0_init();
442
443	/* initialize console so that we have printf */
444	boothowto |= (RB_SERIAL | RB_MULTIPLE);	/* Use multiple consoles */
445
446	/* For now */
447	boothowto |= RB_VERBOSE;
448	boothowto |= RB_SINGLE;
449	bootverbose++;
450
451	/* clockrate used by delay, so initialize it here */
452	xlp_cpu_frequency = xlp_get_cpu_frequency();
453	cpu_clock = xlp_cpu_frequency / 1000000;
454	mips_timer_early_init(xlp_cpu_frequency);
455
456	/* Init console please */
457	cninit();
458
459	/* Environment */
460	printf("Args %#jx %#jx %#jx %#jx:\n", (intmax_t)a0,
461	    (intmax_t)a1, (intmax_t)a2, (intmax_t)a3);
462	xlp_hw_thread_mask = a0;
463	init_static_kenv(boot1_env, sizeof(boot1_env));
464	printf("Environment (from %d args):\n", xlp_argc - 1);
465	if (xlp_argc == 1)
466		printf("\tNone\n");
467	for (i = 1; i < xlp_argc; i++) {
468		char *n, *arg;
469
470		arg = (char *)(intptr_t)xlp_argv[i];
471		printf("\t%s\n", arg);
472		n = strsep(&arg, "=");
473		if (arg == NULL)
474			setenv(n, "1");
475		else
476			setenv(n, arg);
477	}
478
479	/* Early core init and fixes for errata */
480	xlp_setup_core();
481
482	xlp_set_boot_flags();
483	xlp_parse_mmu_options();
484
485	xlp_mem_init();
486
487	bcopy(XLPResetEntry, (void *)MIPS_RESET_EXC_VEC,
488              XLPResetEntryEnd - XLPResetEntry);
489
490	/*
491	 * MIPS generic init
492	 */
493	mips_init();
494	/*
495	 * XLP specific post initialization
496 	 * initialize other on chip stuff
497	 */
498	nlm_board_info_setup();
499	xlp_pic_init();
500
501	mips_timer_init_params(xlp_cpu_frequency, 0);
502}
503
504void
505platform_cpu_init()
506{
507}
508
509void
510platform_identify(void)
511{
512
513	printf("XLP Eval Board\n");
514}
515
516/*
517 * XXX Maybe return the state of the watchdog in enter, and pass it to
518 * exit?  Like spl().
519 */
520void
521platform_trap_enter(void)
522{
523}
524
525void
526platform_reset(void)
527{
528	uint64_t sysbase = nlm_get_sys_regbase(0);
529
530	nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1);
531	for(;;)
532		__asm __volatile("wait");
533}
534
535void
536platform_trap_exit(void)
537{
538}
539
540#ifdef SMP
541/*
542 * XLP threads are started simultaneously when we enable threads, this will
543 * ensure that the threads are blocked in platform_init_ap, until they are
544 * ready to proceed to smp_init_secondary()
545 */
546static volatile int thr_unblock[4];
547
548int
549platform_start_ap(int cpuid)
550{
551	uint32_t coremask, val;
552	uint64_t sysbase = nlm_get_sys_regbase(0);
553	int hwtid = xlp_cpuid_to_hwtid[cpuid];
554	int core, thr;
555
556	core = hwtid / 4;
557	thr = hwtid % 4;
558	if (thr == 0) {
559		/* First thread in core, do core wake up */
560		coremask = 1u << core;
561
562		/* Enable core clock */
563		val = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL);
564		val &= ~coremask;
565		nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, val);
566
567		/* Remove CPU Reset */
568		val = nlm_read_sys_reg(sysbase, SYS_CPU_RESET);
569		val &=  ~coremask & 0xff;
570		nlm_write_sys_reg(sysbase, SYS_CPU_RESET, val);
571
572		if (bootverbose)
573			printf("Waking up core %d ...", core);
574
575		/* Poll for CPU to mark itself coherent */
576		do {
577			val = nlm_read_sys_reg(sysbase, SYS_CPU_NONCOHERENT_MODE);
578       		} while ((val & coremask) != 0);
579		if (bootverbose)
580			printf("Done\n");
581        } else {
582		/* otherwise release the threads stuck in platform_init_ap */
583		thr_unblock[thr] = 1;
584	}
585
586	return (0);
587}
588
589void
590platform_init_ap(int cpuid)
591{
592	uint32_t stat;
593	int thr;
594
595	/* The first thread has to setup the MMU and enable other threads */
596	thr = nlm_threadid();
597	if (thr == 0) {
598		xlp_setup_core();
599		xlp_enable_threads(xlp_mmuval);
600		xlp_setup_mmu();
601	} else {
602		/*
603		 * FIXME busy wait here eats too many cycles, especially
604		 * in the core 0 while bootup
605		 */
606		while (thr_unblock[thr] == 0)
607			__asm__ __volatile__ ("nop;nop;nop;nop");
608		thr_unblock[thr] = 0;
609	}
610
611	stat = mips_rd_status();
612	KASSERT((stat & MIPS_SR_INT_IE) == 0,
613	    ("Interrupts enabled in %s!", __func__));
614	stat |= MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT;
615	mips_wr_status(stat);
616
617	nlm_write_c0_eimr(0ull);
618	xlp_enable_irq(IRQ_IPI);
619	xlp_enable_irq(IRQ_TIMER);
620	xlp_enable_irq(IRQ_MSGRING);
621
622	return;
623}
624
625int
626platform_ipi_intrnum(void)
627{
628
629	return (IRQ_IPI);
630}
631
632void
633platform_ipi_send(int cpuid)
634{
635
636	nlm_pic_send_ipi(xlp_pic_base, xlp_cpuid_to_hwtid[cpuid],
637	    platform_ipi_intrnum(), 0);
638}
639
640void
641platform_ipi_clear(void)
642{
643}
644
645int
646platform_processor_id(void)
647{
648
649	return (xlp_hwtid_to_cpuid[nlm_cpuid()]);
650}
651
652void
653platform_cpu_mask(cpuset_t *mask)
654{
655	int i, s;
656
657	CPU_ZERO(mask);
658	s = xlp_ncores * xlp_threads_per_core;
659	for (i = 0; i < s; i++)
660		CPU_SET(i, mask);
661}
662
663struct cpu_group *
664platform_smp_topo()
665{
666
667	return (smp_topo_2level(CG_SHARE_L2, xlp_ncores, CG_SHARE_L1,
668		xlp_threads_per_core, CG_FLAG_THREAD));
669}
670#endif
671