octeon_machdep.c revision 206721
11573Srgrimes/*-
2128004Stjr * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org>
31573Srgrimes * All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
9227753Stheraven *    notice, this list of conditions and the following disclaimer.
10227753Stheraven * 2. Redistributions in binary form must reproduce the above copyright
11227753Stheraven *    notice, this list of conditions and the following disclaimer in the
12227753Stheraven *    documentation and/or other materials provided with the distribution.
13227753Stheraven *
141573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241573Srgrimes * SUCH DAMAGE.
251573Srgrimes *
261573Srgrimes * $FreeBSD: head/sys/mips/cavium/octeon_machdep.c 206721 2010-04-17 03:08:13Z jmallett $
271573Srgrimes */
281573Srgrimes#include <sys/cdefs.h>
291573Srgrimes__FBSDID("$FreeBSD: head/sys/mips/cavium/octeon_machdep.c 206721 2010-04-17 03:08:13Z jmallett $");
301573Srgrimes
311573Srgrimes#include <sys/param.h>
321573Srgrimes#include <sys/conf.h>
331573Srgrimes#include <sys/kernel.h>
341573Srgrimes#include <sys/systm.h>
351573Srgrimes#include <sys/imgact.h>
361573Srgrimes#include <sys/bio.h>
371573Srgrimes#include <sys/buf.h>
381573Srgrimes#include <sys/bus.h>
391573Srgrimes#include <sys/cpu.h>
401573Srgrimes#include <sys/cons.h>
411573Srgrimes#include <sys/exec.h>
4292986Sobrien#include <sys/ucontext.h>
4392986Sobrien#include <sys/proc.h>
441573Srgrimes#include <sys/kdb.h>
45121845Stjr#include <sys/ptrace.h>
46105233Stjr#include <sys/reboot.h>
47121845Stjr#include <sys/signalvar.h>
481573Srgrimes#include <sys/sysent.h>
491573Srgrimes#include <sys/sysproto.h>
501573Srgrimes#include <sys/user.h>
51129179Stjr
52121845Stjr#include <vm/vm.h>
53129153Stjr#include <vm/vm_object.h>
541573Srgrimes#include <vm/vm_page.h>
55142654Sphantom#include <vm/vm_pager.h>
56142654Sphantom
57142654Sphantom#include <machine/atomic.h>
58142654Sphantom#include <machine/cache.h>
59142654Sphantom#include <machine/clock.h>
60142654Sphantom#include <machine/cpu.h>
61142654Sphantom#include <machine/cpuregs.h>
62142654Sphantom#include <machine/cpufunc.h>
63142654Sphantom#include <mips/cavium/octeon_pcmap_regs.h>
64142654Sphantom#include <machine/hwfunc.h>
65121845Stjr#include <machine/intr_machdep.h>
66172619Sache#include <machine/locore.h>
67172619Sache#include <machine/md_var.h>
68172619Sache#include <machine/pcpu.h>
69172619Sache#include <machine/pte.h>
70172619Sache#include <machine/trap.h>
711573Srgrimes#include <machine/vmparam.h>
72227753Stheraven
731573Srgrimes#if defined(__mips_n64)
74121845Stjr#define MAX_APP_DESC_ADDR     0xffffffffafffffff
75227753Stheraven#else
76227753Stheraven#define MAX_APP_DESC_ADDR     0xafffffff
77227753Stheraven#endif
78227753Stheraven
79227753Stheravenextern int	*edata;
80227753Stheravenextern int	*end;
81227753Stheraven
82227753Stheravenuint64_t ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip);
831573Srgrimesvoid ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip);
841573Srgrimes
851573Srgrimesstatic void octeon_boot_params_init(register_t ptr);
86142654Sphantomstatic uint64_t ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx);
87128004Stjrstatic uint64_t ciu_get_intr_en_reg_addr(int core_num, int intx, int enx);
88128004Stjr
89128004Stjrstatic __inline void
90128004Stjrmips_wr_ebase(u_int32_t a0)
91128004Stjr{
92128004Stjr	__asm __volatile("mtc0 %[a0], $15, 1 ;"
93128004Stjr	    :
94128004Stjr	    :     [a0] "r"(a0));
95128004Stjr
96128004Stjr	mips_barrier();
97142654Sphantom}
98121845Stjr
99121845Stjrvoid
1001573Srgrimesplatform_cpu_init()
101121845Stjr{
102121845Stjr	/* Nothing special yet */
103121845Stjr}
104121845Stjr
105121845Stjr/*
106121845Stjr * Perform a board-level soft-reset.
107121845Stjr */
108121845Stjrvoid
109121845Stjrplatform_reset(void)
110121845Stjr{
1111573Srgrimes	oct_write64(OCTEON_CIU_SOFT_RST, 1);
1121573Srgrimes}
113142654Sphantom
114121845Stjrvoid
115121845Stjrocteon_led_write_char(int char_position, char val)
1161573Srgrimes{
117121845Stjr	uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
118121845Stjr
119121845Stjr	if (!octeon_board_real())
120121845Stjr		return;
121121845Stjr
122121845Stjr	char_position &= 0x7;  /* only 8 chars */
123121845Stjr	ptr += char_position;
124121845Stjr	oct_write8_x8(ptr, val);
125121845Stjr}
126121845Stjr
1271573Srgrimesvoid
128129179Stjrocteon_led_write_char0(char val)
129142654Sphantom{
130132497Stjr	uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
131132497Stjr
132129179Stjr	if (!octeon_board_real())
133129179Stjr		return;
134129179Stjr	oct_write8_x8(ptr, val);
135129179Stjr}
136132497Stjr
137132497Stjrvoid
138132497Stjrocteon_led_write_hexchar(int char_position, char hexval)
139132497Stjr{
140129179Stjr	uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
141129179Stjr	char char1, char2;
142129179Stjr
143132497Stjr	if (!octeon_board_real())
144129179Stjr		return;
145129179Stjr
146129179Stjr	char1 = (hexval >> 4) & 0x0f; char1 = (char1 < 10)?char1+'0':char1+'7';
147129179Stjr	char2 = (hexval  & 0x0f); char2 = (char2 < 10)?char2+'0':char2+'7';
148129179Stjr	char_position &= 0x7;  /* only 8 chars */
149129179Stjr	if (char_position > 6)
150129179Stjr		char_position = 6;
151129179Stjr	ptr += char_position;
152129179Stjr	oct_write8_x8(ptr, char1);
153129179Stjr	ptr++;
154142654Sphantom	oct_write8_x8(ptr, char2);
155132497Stjr}
156132497Stjr
157129179Stjrvoid
158129179Stjrocteon_led_write_string(const char *str)
159129179Stjr{
160129179Stjr	uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
161129707Stjr	int i;
162132497Stjr
163129707Stjr	if (!octeon_board_real())
164129707Stjr		return;
165129707Stjr
166129707Stjr	for (i=0; i<8; i++, ptr++) {
167129707Stjr		if (str && *str)
168129707Stjr			oct_write8_x8(ptr, *str++);
169129707Stjr		else
170129179Stjr			oct_write8_x8(ptr, ' ');
171129179Stjr		oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
172129179Stjr	}
173132497Stjr}
174129179Stjr
175129179Stjrstatic char progress[8] = { '-', '/', '|', '\\', '-', '/', '|', '\\'};
176129179Stjr
177129179Stjrvoid
178129179Stjrocteon_led_run_wheel(int *prog_count, int led_position)
179129179Stjr{
180129179Stjr	if (!octeon_board_real())
181129179Stjr		return;
182129179Stjr	octeon_led_write_char(led_position, progress[*prog_count]);
183129179Stjr	*prog_count += 1;
184129179Stjr	*prog_count &= 0x7;
185129179Stjr}
186129179Stjr
187142654Sphantomvoid
188142654Sphantomocteon_led_write_hex(uint32_t wl)
189142654Sphantom{
190142654Sphantom	char nbuf[80];
191142654Sphantom
192142654Sphantom	sprintf(nbuf, "%X", wl);
193142654Sphantom	octeon_led_write_string(nbuf);
194142654Sphantom}
195142654Sphantom
196142654Sphantom
197142654Sphantom/*
198142654Sphantom * octeon_debug_symbol
199142654Sphantom *
200227753Stheraven * Does nothing.
201227753Stheraven * Used to mark the point for simulator to begin tracing
202227753Stheraven */
203227753Stheravenvoid
204227753Stheravenocteon_debug_symbol(void)
205227753Stheraven{
206227753Stheraven}
207227753Stheraven
208227753Stheravenvoid
209227753Stheravenocteon_ciu_stop_gtimer(int timer)
210227753Stheraven{
211227753Stheraven	oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), 0ll);
212227753Stheraven}
213227753Stheraven
214227753Stheravenvoid
215227753Stheravenocteon_ciu_start_gtimer(int timer, u_int one_shot, uint64_t time_cycles)
216227753Stheraven{
217227753Stheraven    	octeon_ciu_gentimer gentimer;
218227753Stheraven
219227753Stheraven        gentimer.word64 = 0;
220227753Stheraven        gentimer.bits.one_shot = one_shot;
221227753Stheraven        gentimer.bits.len = time_cycles - 1;
222227753Stheraven        oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), gentimer.word64);
223}
224
225/*
226 * octeon_ciu_reset
227 *
228 * Shutdown all CIU to IP2, IP3 mappings
229 */
230void
231octeon_ciu_reset(void)
232{
233
234	octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_0);
235	octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_1);
236	octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_2);
237	octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_3);
238
239	ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0);
240	ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_1);
241	ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0);
242	ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1);
243
244	ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0, 0ll);
245	ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0, 0ll);
246	ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1, 0ll);
247}
248
249/*
250 * mips_disable_interrupt_controllers
251 *
252 * Disable interrupts in the CPU controller
253 */
254void
255mips_disable_interrupt_controls(void)
256{
257	/*
258	 * Disable interrupts in CIU.
259	 */
260	octeon_ciu_reset();
261}
262
263/*
264 * ciu_get_intr_sum_reg_addr
265 */
266static uint64_t
267ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx)
268{
269	uint64_t ciu_intr_sum_reg_addr;
270
271    	if (enx == CIU_EN_0)
272            	ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_BASE_ADDR +
273		    (core_num * 0x10) + (intx * 0x8);
274	else
275            	ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_INT1_ADDR;
276
277        return (ciu_intr_sum_reg_addr);
278}
279
280
281/*
282 * ciu_get_intr_en_reg_addr
283 */
284static uint64_t
285ciu_get_intr_en_reg_addr(int core_num, int intx, int enx)
286{
287	uint64_t ciu_intr_reg_addr;
288
289    	ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR +
290	    ((enx == 0) ? 0x0 : 0x8) + (intx * 0x10) +  (core_num * 0x20);
291        return (ciu_intr_reg_addr);
292}
293
294
295
296
297/*
298 * ciu_get_intr_reg_addr
299 *
300 * 200 ---int0,en0 ip2
301 * 208 ---int0,en1 ip2 ----> this is wrong... this is watchdog
302 *
303 * 210 ---int0,en0 ip3 --
304 * 218 ---int0,en1 ip3 ----> same here.. .this is watchdog... right?
305 *
306 * 220 ---int1,en0 ip2
307 * 228 ---int1,en1 ip2
308 * 230 ---int1,en0 ip3 --
309 * 238 ---int1,en1 ip3
310 *
311 */
312uint64_t
313ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip)
314{
315	uint64_t ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR;
316
317	/* XXX kasserts? */
318	if (enx < CIU_EN_0 || enx > CIU_EN_1) {
319		printf("%s: invalid enx value %d, should be %d or %d\n",
320		    __func__, enx, CIU_EN_0, CIU_EN_1);
321		return 0;
322	}
323	if (intx < CIU_INT_0 || intx > CIU_INT_1) {
324		printf("%s: invalid intx value %d, should be %d or %d\n",
325		    __func__, enx, CIU_INT_0, CIU_INT_1);
326		return 0;
327	}
328	if (ciu_ip < CIU_MIPS_IP2 || ciu_ip > CIU_MIPS_IP3) {
329		printf("%s: invalid ciu_ip value %d, should be %d or %d\n",
330		    __func__, ciu_ip, CIU_MIPS_IP2, CIU_MIPS_IP3);
331		return 0;
332	}
333
334	ciu_intr_reg_addr += (enx    * 0x8);
335	ciu_intr_reg_addr += (ciu_ip * 0x10);
336	ciu_intr_reg_addr += (intx   * 0x20);
337	return (ciu_intr_reg_addr);
338}
339
340/*
341 * ciu_get_int_summary
342 */
343uint64_t
344ciu_get_int_summary(int core_num, int intx, int enx)
345{
346	uint64_t ciu_intr_sum_reg_addr;
347
348	if (core_num == CIU_THIS_CORE)
349        	core_num = octeon_get_core_num();
350	ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx);
351	return (oct_read64(ciu_intr_sum_reg_addr));
352}
353
354//#define DEBUG_CIU 1
355
356#ifdef DEBUG_CIU
357#define DEBUG_CIU_SUM 1
358#define DEBUG_CIU_EN 1
359#endif
360
361
362/*
363 * ciu_clear_int_summary
364 */
365void
366ciu_clear_int_summary(int core_num, int intx, int enx, uint64_t write_bits)
367{
368	uint32_t cpu_status_bits;
369	uint64_t ciu_intr_sum_reg_addr;
370
371//#define DEBUG_CIU_SUM 1
372
373#ifdef DEBUG_CIU_SUM
374	uint64_t ciu_intr_sum_bits;
375#endif
376
377
378	if (core_num == CIU_THIS_CORE) {
379        	core_num = octeon_get_core_num();
380	}
381
382#ifdef DEBUG_CIU_SUM
383        printf(" CIU: core %u clear sum IntX %u  Enx %u  Bits: 0x%llX\n",
384	    core_num, intx, enx, write_bits);
385#endif
386
387	cpu_status_bits = intr_disable();
388
389	ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx);
390
391#ifdef DEBUG_CIU_SUM
392    	ciu_intr_sum_bits =  oct_read64(ciu_intr_sum_reg_addr);	/* unneeded dummy read */
393        printf(" CIU: status: 0x%X  reg_addr: 0x%llX   Val: 0x%llX   ->  0x%llX",
394	    cpu_status_bits, ciu_intr_sum_reg_addr, ciu_intr_sum_bits,
395	    ciu_intr_sum_bits | write_bits);
396#endif
397
398	oct_write64(ciu_intr_sum_reg_addr, write_bits);
399	oct_read64(OCTEON_MIO_BOOT_BIST_STAT);	/* Bus Barrier */
400
401#ifdef DEBUG_CIU_SUM
402        printf(" Readback: 0x%llX\n\n   ", (uint64_t) oct_read64(ciu_intr_sum_reg_addr));
403#endif
404
405	intr_restore(cpu_status_bits);
406}
407
408/*
409 * ciu_disable_intr
410 */
411void
412ciu_disable_intr(int core_num, int intx, int enx)
413{
414	uint32_t cpu_status_bits;
415	uint64_t ciu_intr_reg_addr;
416
417	if (core_num == CIU_THIS_CORE)
418        	core_num = octeon_get_core_num();
419
420	cpu_status_bits = intr_disable();
421
422	ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
423
424	oct_read64(ciu_intr_reg_addr);	/* Dummy read */
425
426	oct_write64(ciu_intr_reg_addr, 0LL);
427	oct_read64(OCTEON_MIO_BOOT_BIST_STAT);	/* Bus Barrier */
428
429	intr_restore(cpu_status_bits);
430}
431
432void
433ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip)
434{
435
436	uint64_t ciu_intr_reg_addr;
437	uint64_t ciu_intr_bits;
438
439        if (core_num == CIU_THIS_CORE) {
440            	core_num = octeon_get_core_num();
441        }
442
443#ifndef OCTEON_SMP_1
444	ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
445#else
446	ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip);
447#endif
448
449        if (!ciu_intr_reg_addr) {
450            printf("Bad call to %s\n", __func__);
451            while(1);
452            return;
453        }
454
455	ciu_intr_bits =  oct_read64(ciu_intr_reg_addr);
456        printf(" CIU core %d  int: %d  en: %d  ip: %d  Add: %#llx  enabled: %#llx  SR: %x\n",
457	    core_num, intx, enx, ciu_ip, (unsigned long long)ciu_intr_reg_addr,
458	    (unsigned long long)ciu_intr_bits, mips_rd_status());
459}
460
461
462/*
463 * ciu_enable_interrupts
464 */
465void ciu_enable_interrupts(int core_num, int intx, int enx,
466    uint64_t set_these_interrupt_bits, int ciu_ip)
467{
468	uint32_t cpu_status_bits;
469	uint64_t ciu_intr_reg_addr;
470	uint64_t ciu_intr_bits;
471
472        if (core_num == CIU_THIS_CORE)
473            	core_num = octeon_get_core_num();
474
475//#define DEBUG_CIU_EN 1
476
477#ifdef DEBUG_CIU_EN
478        printf(" CIU: core %u enabling Intx %u  Enx %u IP %d  Bits: 0x%llX\n",
479	    core_num, intx, enx, ciu_ip, set_these_interrupt_bits);
480#endif
481
482	cpu_status_bits = intr_disable();
483
484#ifndef OCTEON_SMP_1
485	ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
486#else
487	ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip);
488#endif
489
490        if (!ciu_intr_reg_addr) {
491		printf("Bad call to %s\n", __func__);
492		while(1);
493		return;	/* XXX */
494        }
495
496	ciu_intr_bits =  oct_read64(ciu_intr_reg_addr);
497
498#ifdef DEBUG_CIU_EN
499        printf(" CIU: status: 0x%X  reg_addr: 0x%llX   Val: 0x%llX   ->  0x%llX",
500	    cpu_status_bits, ciu_intr_reg_addr, ciu_intr_bits, ciu_intr_bits | set_these_interrupt_bits);
501#endif
502	ciu_intr_bits |=  set_these_interrupt_bits;
503	oct_write64(ciu_intr_reg_addr, ciu_intr_bits);
504#ifdef SMP
505	mips_wbflush();
506#endif
507	oct_read64(OCTEON_MIO_BOOT_BIST_STAT);	/* Bus Barrier */
508
509#ifdef DEBUG_CIU_EN
510        printf(" Readback: 0x%llX\n\n   ",
511	    (uint64_t)oct_read64(ciu_intr_reg_addr));
512#endif
513
514	intr_restore(cpu_status_bits);
515}
516
517unsigned long
518octeon_get_clock_rate(void)
519{
520	return octeon_cpu_clock;
521}
522
523static void
524octeon_memory_init(void)
525{
526	uint32_t realmem_bytes;
527
528	if (octeon_board_real()) {
529		realmem_bytes = (octeon_dram - PAGE_SIZE);
530		realmem_bytes &= ~(PAGE_SIZE - 1);
531	} else {
532		/* Simulator we limit to 96 meg */
533		realmem_bytes = (96 << 20);
534	}
535	/* phys_avail regions are in bytes */
536	phys_avail[0] = (MIPS_KSEG0_TO_PHYS((vm_offset_t)&end) + PAGE_SIZE) & ~(PAGE_SIZE - 1);
537	if (octeon_board_real()) {
538		if (realmem_bytes > OCTEON_DRAM_FIRST_256_END)
539			phys_avail[1] = OCTEON_DRAM_FIRST_256_END;
540		else
541			phys_avail[1] = realmem_bytes;
542		realmem_bytes -= OCTEON_DRAM_FIRST_256_END;
543		realmem_bytes &= ~(PAGE_SIZE - 1);
544	} else {
545		/* Simulator gets 96Meg period. */
546		phys_avail[1] = (96 << 20);
547	}
548	/*-
549	 * Octeon Memory looks as follows:
550         *   PA
551	 * 0000 0000 to                                       0x0 0000 0000 0000
552	 * 0FFF FFFF      First 256 MB memory   Maps to       0x0 0000 0FFF FFFF
553	 *
554	 * 1000 0000 to                                       0x1 0000 1000 0000
555	 * 1FFF FFFF      Uncached Bu I/O space.converted to  0x1 0000 1FFF FFFF
556	 *
557	 * 2FFF FFFF to            Cached                     0x0 0000 2000 0000
558	 * FFFF FFFF      all dram mem above the first 512M   0x3 FFFF FFFF FFFF
559	 *
560	 */
561	physmem = btoc(phys_avail[1] - phys_avail[0]);
562	if ((octeon_board_real()) &&
563	    (realmem_bytes > OCTEON_DRAM_FIRST_256_END)) {
564		/* take out the upper non-cached 1/2 */
565		realmem_bytes -= OCTEON_DRAM_FIRST_256_END;
566		realmem_bytes &= ~(PAGE_SIZE - 1);
567		/* Now map the rest of the memory */
568		phys_avail[2] = 0x20000000;
569		phys_avail[3] = ((uint32_t) 0x20000000 + realmem_bytes);
570		physmem += btoc(phys_avail[3] - phys_avail[2]);
571	}
572	realmem = physmem;
573
574	printf("Total DRAM Size %#X\n", (uint32_t) octeon_dram);
575	printf("Bank 0 = %#08lX   ->  %#08lX\n", (long)phys_avail[0], (long)phys_avail[1]);
576	printf("Bank 1 = %#08lX   ->  %#08lX\n", (long)phys_avail[2], (long)phys_avail[3]);
577}
578
579void
580platform_start(__register_t a0, __register_t a1, __register_t a2 __unused,
581    __register_t a3)
582{
583	uint64_t platform_counter_freq;
584
585	/* Initialize pcpu stuff */
586	mips_pcpu0_init();
587	mips_timer_early_init(OCTEON_CLOCK_DEFAULT);
588	cninit();
589
590	octeon_ciu_reset();
591	octeon_boot_params_init(a3);
592	bootverbose = 1;
593
594	/*
595	 * For some reason on the cn38xx simulator ebase register is set to
596	 * 0x80001000 at bootup time.  Move it back to the default, but
597	 * when we move to having support for multiple executives, we need
598	 * to rethink this.
599	 */
600	mips_wr_ebase(0x80000000);
601
602	octeon_memory_init();
603	init_param1();
604	init_param2(physmem);
605	mips_cpu_init();
606	pmap_bootstrap();
607	mips_proc0_init();
608	mutex_init();
609	kdb_init();
610#ifdef KDB
611	if (boothowto & RB_KDB)
612		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
613#endif
614	platform_counter_freq = octeon_get_clock_rate();
615	mips_timer_init_params(platform_counter_freq, 0);
616
617#ifdef SMP
618	/*
619	 * Clear any pending IPIs and enable the IPI interrupt.
620	 */
621	oct_write64(OCTEON_CIU_MBOX_CLRX(0), 0xffffffff);
622	ciu_enable_interrupts(0, CIU_INT_1, CIU_EN_0, OCTEON_CIU_ENABLE_MBOX_INTR, CIU_MIPS_IP3);
623#endif
624}
625
626/* impSTART: This stuff should move back into the Cavium SDK */
627/*
628 ****************************************************************************************
629 *
630 * APP/BOOT  DESCRIPTOR  STUFF
631 *
632 ****************************************************************************************
633 */
634
635/* Define the struct that is initialized by the bootloader used by the
636 * startup code.
637 *
638 * Copyright (c) 2004, 2005, 2006 Cavium Networks.
639 *
640 * The authors hereby grant permission to use, copy, modify, distribute,
641 * and license this software and its documentation for any purpose, provided
642 * that existing copyright notices are retained in all copies and that this
643 * notice is included verbatim in any distributions. No written agreement,
644 * license, or royalty fee is required for any of the authorized uses.
645 * Modifications to this software may be copyrighted by their authors
646 * and need not follow the licensing terms described here, provided that
647 * the new terms are clearly indicated on the first page of each file where
648 * they apply.
649 */
650
651#define OCTEON_CURRENT_DESC_VERSION     6
652#define OCTEON_ARGV_MAX_ARGS            (64)
653#define OCTOEN_SERIAL_LEN 20
654
655
656typedef struct {
657	/* Start of block referenced by assembly code - do not change! */
658	uint32_t desc_version;
659	uint32_t desc_size;
660
661	uint64_t stack_top;
662	uint64_t heap_base;
663	uint64_t heap_end;
664	uint64_t entry_point;   /* Only used by bootloader */
665	uint64_t desc_vaddr;
666	/* End of This block referenced by assembly code - do not change! */
667
668	uint32_t exception_base_addr;
669	uint32_t stack_size;
670	uint32_t heap_size;
671	uint32_t argc;  /* Argc count for application */
672	uint32_t argv[OCTEON_ARGV_MAX_ARGS];
673	uint32_t flags;
674	uint32_t core_mask;
675	uint32_t dram_size;  /**< DRAM size in megabyes */
676	uint32_t phy_mem_desc_addr;  /**< physical address of free memory descriptor block*/
677	uint32_t debugger_flags_base_addr;  /**< used to pass flags from app to debugger */
678	uint32_t eclock_hz;  /**< CPU clock speed, in hz */
679	uint32_t dclock_hz;  /**< DRAM clock speed, in hz */
680	uint32_t spi_clock_hz;  /**< SPI4 clock in hz */
681	uint16_t board_type;
682	uint8_t board_rev_major;
683	uint8_t board_rev_minor;
684	uint16_t chip_type;
685	uint8_t chip_rev_major;
686	uint8_t chip_rev_minor;
687	char board_serial_number[OCTOEN_SERIAL_LEN];
688	uint8_t mac_addr_base[6];
689	uint8_t mac_addr_count;
690	uint64_t cvmx_desc_vaddr;
691} octeon_boot_descriptor_t;
692
693
694typedef struct {
695	uint32_t major_version;
696	uint32_t minor_version;
697
698	uint64_t stack_top;
699	uint64_t heap_base;
700	uint64_t heap_end;
701	uint64_t desc_vaddr;
702
703	uint32_t exception_base_addr;
704	uint32_t stack_size;
705	uint32_t flags;
706	uint32_t core_mask;
707	uint32_t dram_size;  /**< DRAM size in megabyes */
708	uint32_t phy_mem_desc_addr;  /**< physical address of free memory descriptor block*/
709	uint32_t debugger_flags_base_addr;  /**< used to pass flags from app to debugger */
710	uint32_t eclock_hz;  /**< CPU clock speed, in hz */
711	uint32_t dclock_hz;  /**< DRAM clock speed, in hz */
712	uint32_t spi_clock_hz;  /**< SPI4 clock in hz */
713	uint16_t board_type;
714	uint8_t board_rev_major;
715	uint8_t board_rev_minor;
716	uint16_t chip_type;
717	uint8_t chip_rev_major;
718	uint8_t chip_rev_minor;
719	char board_serial_number[OCTOEN_SERIAL_LEN];
720	uint8_t mac_addr_base[6];
721	uint8_t mac_addr_count;
722} cvmx_bootinfo_t;
723
724uint32_t octeon_cpu_clock;
725uint64_t octeon_dram;
726uint32_t octeon_bd_ver = 0, octeon_cvmx_bd_ver = 0, octeon_board_rev_major, octeon_board_rev_minor, octeon_board_type;
727uint8_t octeon_mac_addr[6] = { 0 };
728int octeon_core_mask, octeon_mac_addr_count;
729int octeon_chip_rev_major = 0, octeon_chip_rev_minor = 0, octeon_chip_type = 0;
730
731static octeon_boot_descriptor_t *app_desc_ptr;
732static cvmx_bootinfo_t *cvmx_desc_ptr;
733
734#define OCTEON_BOARD_TYPE_NONE 			0
735#define OCTEON_BOARD_TYPE_SIM  			1
736#define	OCTEON_BOARD_TYPE_CN3010_EVB_HS5	11
737
738#define OCTEON_CLOCK_MIN     (100 * 1000 * 1000)
739#define OCTEON_CLOCK_MAX     (800 * 1000 * 1000)
740#define OCTEON_DRAM_DEFAULT  (256 * 1024 * 1024)
741#define OCTEON_DRAM_MIN	     30
742#define OCTEON_DRAM_MAX	     3000
743
744
745int
746octeon_board_real(void)
747{
748	switch (octeon_board_type) {
749	case OCTEON_BOARD_TYPE_NONE:
750	case OCTEON_BOARD_TYPE_SIM:
751		return 0;
752	case OCTEON_BOARD_TYPE_CN3010_EVB_HS5:
753		/*
754		 * XXX
755		 * The CAM-0100 identifies itself as type 11, revision 0.0,
756		 * despite its being rather real.  Disable the revision check
757		 * for type 11.
758		 */
759		return 1;
760	default:
761		if (octeon_board_rev_major == 0)
762			return 0;
763		return 1;
764	}
765}
766
767static void
768octeon_process_app_desc_ver_unknown(void)
769{
770    	printf(" Unknown Boot-Descriptor: Using Defaults\n");
771
772    	octeon_cpu_clock = OCTEON_CLOCK_DEFAULT;
773        octeon_dram = OCTEON_DRAM_DEFAULT;
774        octeon_board_rev_major = octeon_board_rev_minor = octeon_board_type = 0;
775        octeon_core_mask = 1;
776        octeon_chip_type = octeon_chip_rev_major = octeon_chip_rev_minor = 0;
777        octeon_mac_addr[0] = 0x00; octeon_mac_addr[1] = 0x0f;
778        octeon_mac_addr[2] = 0xb7; octeon_mac_addr[3] = 0x10;
779        octeon_mac_addr[4] = 0x09; octeon_mac_addr[5] = 0x06;
780        octeon_mac_addr_count = 1;
781}
782
783static int
784octeon_process_app_desc_ver_6(void)
785{
786	/* XXX Why is 0x00000000ffffffffULL a bad value?  */
787	if (app_desc_ptr->cvmx_desc_vaddr == 0 ||
788	    app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) {
789            	printf ("Bad cvmx_desc_ptr %p\n", cvmx_desc_ptr);
790                return 1;
791	}
792    	cvmx_desc_ptr =
793	    (cvmx_bootinfo_t *)(intptr_t)app_desc_ptr->cvmx_desc_vaddr;
794        cvmx_desc_ptr =
795	    (cvmx_bootinfo_t *) ((intptr_t)cvmx_desc_ptr | MIPS_KSEG0_START);
796        octeon_cvmx_bd_ver = (cvmx_desc_ptr->major_version * 100) +
797	    cvmx_desc_ptr->minor_version;
798        if (cvmx_desc_ptr->major_version != 1) {
799            	panic("Incompatible CVMX descriptor from bootloader: %d.%d %p\n",
800                       (int) cvmx_desc_ptr->major_version,
801                       (int) cvmx_desc_ptr->minor_version, cvmx_desc_ptr);
802        }
803
804        octeon_core_mask = cvmx_desc_ptr->core_mask;
805        octeon_cpu_clock  = cvmx_desc_ptr->eclock_hz;
806        octeon_board_type = cvmx_desc_ptr->board_type;
807        octeon_board_rev_major = cvmx_desc_ptr->board_rev_major;
808        octeon_board_rev_minor = cvmx_desc_ptr->board_rev_minor;
809        octeon_chip_type = cvmx_desc_ptr->chip_type;
810        octeon_chip_rev_major = cvmx_desc_ptr->chip_rev_major;
811        octeon_chip_rev_minor = cvmx_desc_ptr->chip_rev_minor;
812        octeon_mac_addr[0] = cvmx_desc_ptr->mac_addr_base[0];
813        octeon_mac_addr[1] = cvmx_desc_ptr->mac_addr_base[1];
814        octeon_mac_addr[2] = cvmx_desc_ptr->mac_addr_base[2];
815        octeon_mac_addr[3] = cvmx_desc_ptr->mac_addr_base[3];
816        octeon_mac_addr[4] = cvmx_desc_ptr->mac_addr_base[4];
817        octeon_mac_addr[5] = cvmx_desc_ptr->mac_addr_base[5];
818        octeon_mac_addr_count = cvmx_desc_ptr->mac_addr_count;
819
820        if (app_desc_ptr->dram_size > 16*1024*1024)
821            	octeon_dram = (uint64_t)app_desc_ptr->dram_size;
822	else
823            	octeon_dram = (uint64_t)app_desc_ptr->dram_size << 20;
824        return 0;
825}
826
827static void
828octeon_boot_params_init(register_t ptr)
829{
830	int bad_desc = 1;
831
832    	if (ptr != 0 && ptr < MAX_APP_DESC_ADDR) {
833	        app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr;
834		octeon_bd_ver = app_desc_ptr->desc_version;
835		if (app_desc_ptr->desc_version < 6)
836			panic("Your boot code is too old to be supported.\n");
837		if (app_desc_ptr->desc_version >= 6)
838			bad_desc = octeon_process_app_desc_ver_6();
839        }
840        if (bad_desc)
841        	octeon_process_app_desc_ver_unknown();
842
843        printf("Boot Descriptor Ver: %u -> %u/%u",
844               octeon_bd_ver, octeon_cvmx_bd_ver/100, octeon_cvmx_bd_ver%100);
845        printf("  CPU clock: %uMHz  Core Mask: %#x\n", octeon_cpu_clock/1000000, octeon_core_mask);
846        printf("  Dram: %u MB", (uint32_t)(octeon_dram >> 20));
847        printf("  Board Type: %u  Revision: %u/%u\n",
848               octeon_board_type, octeon_board_rev_major, octeon_board_rev_minor);
849        printf("  Octeon Chip: %u  Rev %u/%u",
850               octeon_chip_type, octeon_chip_rev_major, octeon_chip_rev_minor);
851
852        printf("  Mac Address %02X.%02X.%02X.%02X.%02X.%02X (%d)\n",
853	    octeon_mac_addr[0], octeon_mac_addr[1], octeon_mac_addr[2],
854	    octeon_mac_addr[3], octeon_mac_addr[4], octeon_mac_addr[5],
855	    octeon_mac_addr_count);
856}
857/* impEND: This stuff should move back into the Cavium SDK */
858