octeon_machdep.c revision 206829
1/*-
2 * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/mips/cavium/octeon_machdep.c 206829 2010-04-19 06:01:58Z jmallett $
27 */
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/mips/cavium/octeon_machdep.c 206829 2010-04-19 06:01:58Z jmallett $");
30
31#include <sys/param.h>
32#include <sys/conf.h>
33#include <sys/kernel.h>
34#include <sys/systm.h>
35#include <sys/imgact.h>
36#include <sys/bio.h>
37#include <sys/buf.h>
38#include <sys/bus.h>
39#include <sys/cpu.h>
40#include <sys/cons.h>
41#include <sys/exec.h>
42#include <sys/ucontext.h>
43#include <sys/proc.h>
44#include <sys/kdb.h>
45#include <sys/ptrace.h>
46#include <sys/reboot.h>
47#include <sys/signalvar.h>
48#include <sys/sysent.h>
49#include <sys/sysproto.h>
50#include <sys/user.h>
51
52#include <vm/vm.h>
53#include <vm/vm_object.h>
54#include <vm/vm_page.h>
55#include <vm/vm_pager.h>
56
57#include <machine/atomic.h>
58#include <machine/cache.h>
59#include <machine/clock.h>
60#include <machine/cpu.h>
61#include <machine/cpuregs.h>
62#include <machine/cpufunc.h>
63#include <mips/cavium/octeon_pcmap_regs.h>
64#include <machine/hwfunc.h>
65#include <machine/intr_machdep.h>
66#include <machine/locore.h>
67#include <machine/md_var.h>
68#include <machine/pcpu.h>
69#include <machine/pte.h>
70#include <machine/trap.h>
71#include <machine/vmparam.h>
72
73#if defined(__mips_n64)
74#define MAX_APP_DESC_ADDR     0xffffffffafffffff
75#else
76#define MAX_APP_DESC_ADDR     0xafffffff
77#endif
78
79extern int	*edata;
80extern int	*end;
81
82uint64_t ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip);
83void ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip);
84
85static void octeon_boot_params_init(register_t ptr);
86static uint64_t ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx);
87static uint64_t ciu_get_intr_en_reg_addr(int core_num, int intx, int enx);
88
89void
90platform_cpu_init()
91{
92	/* Nothing special yet */
93}
94
95/*
96 * Perform a board-level soft-reset.
97 */
98void
99platform_reset(void)
100{
101	oct_write64(OCTEON_CIU_SOFT_RST, 1);
102}
103
104void
105octeon_led_write_char(int char_position, char val)
106{
107	uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
108
109	if (!octeon_board_real())
110		return;
111
112	char_position &= 0x7;  /* only 8 chars */
113	ptr += char_position;
114	oct_write8_x8(ptr, val);
115}
116
117void
118octeon_led_write_char0(char val)
119{
120	uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
121
122	if (!octeon_board_real())
123		return;
124	oct_write8_x8(ptr, val);
125}
126
127void
128octeon_led_write_hexchar(int char_position, char hexval)
129{
130	uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
131	char char1, char2;
132
133	if (!octeon_board_real())
134		return;
135
136	char1 = (hexval >> 4) & 0x0f; char1 = (char1 < 10)?char1+'0':char1+'7';
137	char2 = (hexval  & 0x0f); char2 = (char2 < 10)?char2+'0':char2+'7';
138	char_position &= 0x7;  /* only 8 chars */
139	if (char_position > 6)
140		char_position = 6;
141	ptr += char_position;
142	oct_write8_x8(ptr, char1);
143	ptr++;
144	oct_write8_x8(ptr, char2);
145}
146
147void
148octeon_led_write_string(const char *str)
149{
150	uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
151	int i;
152
153	if (!octeon_board_real())
154		return;
155
156	for (i=0; i<8; i++, ptr++) {
157		if (str && *str)
158			oct_write8_x8(ptr, *str++);
159		else
160			oct_write8_x8(ptr, ' ');
161		oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
162	}
163}
164
165static char progress[8] = { '-', '/', '|', '\\', '-', '/', '|', '\\'};
166
167void
168octeon_led_run_wheel(int *prog_count, int led_position)
169{
170	if (!octeon_board_real())
171		return;
172	octeon_led_write_char(led_position, progress[*prog_count]);
173	*prog_count += 1;
174	*prog_count &= 0x7;
175}
176
177void
178octeon_led_write_hex(uint32_t wl)
179{
180	char nbuf[80];
181
182	sprintf(nbuf, "%X", wl);
183	octeon_led_write_string(nbuf);
184}
185
186
187/*
188 * octeon_debug_symbol
189 *
190 * Does nothing.
191 * Used to mark the point for simulator to begin tracing
192 */
193void
194octeon_debug_symbol(void)
195{
196}
197
198void
199octeon_ciu_stop_gtimer(int timer)
200{
201	oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), 0ll);
202}
203
204void
205octeon_ciu_start_gtimer(int timer, u_int one_shot, uint64_t time_cycles)
206{
207    	octeon_ciu_gentimer gentimer;
208
209        gentimer.word64 = 0;
210        gentimer.bits.one_shot = one_shot;
211        gentimer.bits.len = time_cycles - 1;
212        oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), gentimer.word64);
213}
214
215/*
216 * octeon_ciu_reset
217 *
218 * Shutdown all CIU to IP2, IP3 mappings
219 */
220void
221octeon_ciu_reset(void)
222{
223
224	octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_0);
225	octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_1);
226	octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_2);
227	octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_3);
228
229	ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0);
230	ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_1);
231	ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0);
232	ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1);
233
234	ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0, 0ll);
235	ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0, 0ll);
236	ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1, 0ll);
237}
238
239/*
240 * mips_disable_interrupt_controllers
241 *
242 * Disable interrupts in the CPU controller
243 */
244void
245mips_disable_interrupt_controls(void)
246{
247	/*
248	 * Disable interrupts in CIU.
249	 */
250	octeon_ciu_reset();
251}
252
253/*
254 * ciu_get_intr_sum_reg_addr
255 */
256static uint64_t
257ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx)
258{
259	uint64_t ciu_intr_sum_reg_addr;
260
261    	if (enx == CIU_EN_0)
262            	ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_BASE_ADDR +
263		    (core_num * 0x10) + (intx * 0x8);
264	else
265            	ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_INT1_ADDR;
266
267        return (ciu_intr_sum_reg_addr);
268}
269
270
271/*
272 * ciu_get_intr_en_reg_addr
273 */
274static uint64_t
275ciu_get_intr_en_reg_addr(int core_num, int intx, int enx)
276{
277	uint64_t ciu_intr_reg_addr;
278
279    	ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR +
280	    ((enx == 0) ? 0x0 : 0x8) + (intx * 0x10) +  (core_num * 0x20);
281        return (ciu_intr_reg_addr);
282}
283
284
285
286
287/*
288 * ciu_get_intr_reg_addr
289 *
290 * 200 ---int0,en0 ip2
291 * 208 ---int0,en1 ip2 ----> this is wrong... this is watchdog
292 *
293 * 210 ---int0,en0 ip3 --
294 * 218 ---int0,en1 ip3 ----> same here.. .this is watchdog... right?
295 *
296 * 220 ---int1,en0 ip2
297 * 228 ---int1,en1 ip2
298 * 230 ---int1,en0 ip3 --
299 * 238 ---int1,en1 ip3
300 *
301 */
302uint64_t
303ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip)
304{
305	uint64_t ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR;
306
307	/* XXX kasserts? */
308	if (enx < CIU_EN_0 || enx > CIU_EN_1) {
309		printf("%s: invalid enx value %d, should be %d or %d\n",
310		    __func__, enx, CIU_EN_0, CIU_EN_1);
311		return 0;
312	}
313	if (intx < CIU_INT_0 || intx > CIU_INT_1) {
314		printf("%s: invalid intx value %d, should be %d or %d\n",
315		    __func__, enx, CIU_INT_0, CIU_INT_1);
316		return 0;
317	}
318	if (ciu_ip < CIU_MIPS_IP2 || ciu_ip > CIU_MIPS_IP3) {
319		printf("%s: invalid ciu_ip value %d, should be %d or %d\n",
320		    __func__, ciu_ip, CIU_MIPS_IP2, CIU_MIPS_IP3);
321		return 0;
322	}
323
324	ciu_intr_reg_addr += (enx    * 0x8);
325	ciu_intr_reg_addr += (ciu_ip * 0x10);
326	ciu_intr_reg_addr += (intx   * 0x20);
327	return (ciu_intr_reg_addr);
328}
329
330/*
331 * ciu_get_int_summary
332 */
333uint64_t
334ciu_get_int_summary(int core_num, int intx, int enx)
335{
336	uint64_t ciu_intr_sum_reg_addr;
337
338	if (core_num == CIU_THIS_CORE)
339        	core_num = octeon_get_core_num();
340	ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx);
341	return (oct_read64(ciu_intr_sum_reg_addr));
342}
343
344//#define DEBUG_CIU 1
345
346#ifdef DEBUG_CIU
347#define DEBUG_CIU_SUM 1
348#define DEBUG_CIU_EN 1
349#endif
350
351
352/*
353 * ciu_clear_int_summary
354 */
355void
356ciu_clear_int_summary(int core_num, int intx, int enx, uint64_t write_bits)
357{
358	uint32_t cpu_status_bits;
359	uint64_t ciu_intr_sum_reg_addr;
360
361//#define DEBUG_CIU_SUM 1
362
363#ifdef DEBUG_CIU_SUM
364	uint64_t ciu_intr_sum_bits;
365#endif
366
367
368	if (core_num == CIU_THIS_CORE) {
369        	core_num = octeon_get_core_num();
370	}
371
372#ifdef DEBUG_CIU_SUM
373        printf(" CIU: core %u clear sum IntX %u  Enx %u  Bits: 0x%llX\n",
374	    core_num, intx, enx, write_bits);
375#endif
376
377	cpu_status_bits = intr_disable();
378
379	ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx);
380
381#ifdef DEBUG_CIU_SUM
382    	ciu_intr_sum_bits =  oct_read64(ciu_intr_sum_reg_addr);	/* unneeded dummy read */
383        printf(" CIU: status: 0x%X  reg_addr: 0x%llX   Val: 0x%llX   ->  0x%llX",
384	    cpu_status_bits, ciu_intr_sum_reg_addr, ciu_intr_sum_bits,
385	    ciu_intr_sum_bits | write_bits);
386#endif
387
388	oct_write64(ciu_intr_sum_reg_addr, write_bits);
389	oct_read64(OCTEON_MIO_BOOT_BIST_STAT);	/* Bus Barrier */
390
391#ifdef DEBUG_CIU_SUM
392        printf(" Readback: 0x%llX\n\n   ", (uint64_t) oct_read64(ciu_intr_sum_reg_addr));
393#endif
394
395	intr_restore(cpu_status_bits);
396}
397
398/*
399 * ciu_disable_intr
400 */
401void
402ciu_disable_intr(int core_num, int intx, int enx)
403{
404	uint32_t cpu_status_bits;
405	uint64_t ciu_intr_reg_addr;
406
407	if (core_num == CIU_THIS_CORE)
408        	core_num = octeon_get_core_num();
409
410	cpu_status_bits = intr_disable();
411
412	ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
413
414	oct_read64(ciu_intr_reg_addr);	/* Dummy read */
415
416	oct_write64(ciu_intr_reg_addr, 0LL);
417	oct_read64(OCTEON_MIO_BOOT_BIST_STAT);	/* Bus Barrier */
418
419	intr_restore(cpu_status_bits);
420}
421
422void
423ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip)
424{
425
426	uint64_t ciu_intr_reg_addr;
427	uint64_t ciu_intr_bits;
428
429        if (core_num == CIU_THIS_CORE) {
430            	core_num = octeon_get_core_num();
431        }
432
433#ifndef OCTEON_SMP_1
434	ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
435#else
436	ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip);
437#endif
438
439        if (!ciu_intr_reg_addr) {
440            printf("Bad call to %s\n", __func__);
441            while(1);
442            return;
443        }
444
445	ciu_intr_bits =  oct_read64(ciu_intr_reg_addr);
446        printf(" CIU core %d  int: %d  en: %d  ip: %d  Add: %#llx  enabled: %#llx  SR: %x\n",
447	    core_num, intx, enx, ciu_ip, (unsigned long long)ciu_intr_reg_addr,
448	    (unsigned long long)ciu_intr_bits, mips_rd_status());
449}
450
451
452/*
453 * ciu_enable_interrupts
454 */
455void ciu_enable_interrupts(int core_num, int intx, int enx,
456    uint64_t set_these_interrupt_bits, int ciu_ip)
457{
458	uint32_t cpu_status_bits;
459	uint64_t ciu_intr_reg_addr;
460	uint64_t ciu_intr_bits;
461
462        if (core_num == CIU_THIS_CORE)
463            	core_num = octeon_get_core_num();
464
465//#define DEBUG_CIU_EN 1
466
467#ifdef DEBUG_CIU_EN
468        printf(" CIU: core %u enabling Intx %u  Enx %u IP %d  Bits: 0x%llX\n",
469	    core_num, intx, enx, ciu_ip, set_these_interrupt_bits);
470#endif
471
472	cpu_status_bits = intr_disable();
473
474#ifndef OCTEON_SMP_1
475	ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
476#else
477	ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip);
478#endif
479
480        if (!ciu_intr_reg_addr) {
481		printf("Bad call to %s\n", __func__);
482		while(1);
483		return;	/* XXX */
484        }
485
486	ciu_intr_bits =  oct_read64(ciu_intr_reg_addr);
487
488#ifdef DEBUG_CIU_EN
489        printf(" CIU: status: 0x%X  reg_addr: 0x%llX   Val: 0x%llX   ->  0x%llX",
490	    cpu_status_bits, ciu_intr_reg_addr, ciu_intr_bits, ciu_intr_bits | set_these_interrupt_bits);
491#endif
492	ciu_intr_bits |=  set_these_interrupt_bits;
493	oct_write64(ciu_intr_reg_addr, ciu_intr_bits);
494#ifdef SMP
495	mips_wbflush();
496#endif
497	oct_read64(OCTEON_MIO_BOOT_BIST_STAT);	/* Bus Barrier */
498
499#ifdef DEBUG_CIU_EN
500        printf(" Readback: 0x%llX\n\n   ",
501	    (uint64_t)oct_read64(ciu_intr_reg_addr));
502#endif
503
504	intr_restore(cpu_status_bits);
505}
506
507unsigned long
508octeon_get_clock_rate(void)
509{
510	return octeon_cpu_clock;
511}
512
513static void
514octeon_memory_init(void)
515{
516	uint32_t realmem_bytes;
517
518	if (octeon_board_real()) {
519		realmem_bytes = (octeon_dram - PAGE_SIZE);
520		realmem_bytes &= ~(PAGE_SIZE - 1);
521	} else {
522		/* Simulator we limit to 96 meg */
523		realmem_bytes = (96 << 20);
524	}
525	/* phys_avail regions are in bytes */
526	phys_avail[0] = (MIPS_KSEG0_TO_PHYS((vm_offset_t)&end) + PAGE_SIZE) & ~(PAGE_SIZE - 1);
527	if (octeon_board_real()) {
528		if (realmem_bytes > OCTEON_DRAM_FIRST_256_END)
529			phys_avail[1] = OCTEON_DRAM_FIRST_256_END;
530		else
531			phys_avail[1] = realmem_bytes;
532		realmem_bytes -= OCTEON_DRAM_FIRST_256_END;
533		realmem_bytes &= ~(PAGE_SIZE - 1);
534	} else {
535		/* Simulator gets 96Meg period. */
536		phys_avail[1] = (96 << 20);
537	}
538	/*-
539	 * Octeon Memory looks as follows:
540         *   PA
541	 * 0000 0000 to                                       0x0 0000 0000 0000
542	 * 0FFF FFFF      First 256 MB memory   Maps to       0x0 0000 0FFF FFFF
543	 *
544	 * 1000 0000 to                                       0x1 0000 1000 0000
545	 * 1FFF FFFF      Uncached Bu I/O space.converted to  0x1 0000 1FFF FFFF
546	 *
547	 * 2FFF FFFF to            Cached                     0x0 0000 2000 0000
548	 * FFFF FFFF      all dram mem above the first 512M   0x3 FFFF FFFF FFFF
549	 *
550	 */
551	physmem = btoc(phys_avail[1] - phys_avail[0]);
552	if ((octeon_board_real()) &&
553	    (realmem_bytes > OCTEON_DRAM_FIRST_256_END)) {
554		/* take out the upper non-cached 1/2 */
555		realmem_bytes -= OCTEON_DRAM_FIRST_256_END;
556		realmem_bytes &= ~(PAGE_SIZE - 1);
557		/* Now map the rest of the memory */
558		phys_avail[2] = 0x20000000;
559		phys_avail[3] = ((uint32_t) 0x20000000 + realmem_bytes);
560		physmem += btoc(phys_avail[3] - phys_avail[2]);
561	}
562	realmem = physmem;
563
564	printf("Total DRAM Size %#X\n", (uint32_t) octeon_dram);
565	printf("Bank 0 = %#08lX   ->  %#08lX\n", (long)phys_avail[0], (long)phys_avail[1]);
566	printf("Bank 1 = %#08lX   ->  %#08lX\n", (long)phys_avail[2], (long)phys_avail[3]);
567}
568
569void
570platform_start(__register_t a0, __register_t a1, __register_t a2 __unused,
571    __register_t a3)
572{
573	uint64_t platform_counter_freq;
574
575	/* Initialize pcpu stuff */
576	mips_pcpu0_init();
577	mips_timer_early_init(OCTEON_CLOCK_DEFAULT);
578	cninit();
579
580	octeon_ciu_reset();
581	octeon_boot_params_init(a3);
582	bootverbose = 1;
583
584	/*
585	 * For some reason on the cn38xx simulator ebase register is set to
586	 * 0x80001000 at bootup time.  Move it back to the default, but
587	 * when we move to having support for multiple executives, we need
588	 * to rethink this.
589	 */
590	mips_wr_ebase(0x80000000);
591
592	octeon_memory_init();
593	init_param1();
594	init_param2(physmem);
595	mips_cpu_init();
596	pmap_bootstrap();
597	mips_proc0_init();
598	mutex_init();
599	kdb_init();
600#ifdef KDB
601	if (boothowto & RB_KDB)
602		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
603#endif
604	platform_counter_freq = octeon_get_clock_rate();
605	mips_timer_init_params(platform_counter_freq, 0);
606
607#ifdef SMP
608	/*
609	 * Clear any pending IPIs and enable the IPI interrupt.
610	 */
611	oct_write64(OCTEON_CIU_MBOX_CLRX(0), 0xffffffff);
612	ciu_enable_interrupts(0, CIU_INT_1, CIU_EN_0, OCTEON_CIU_ENABLE_MBOX_INTR, CIU_MIPS_IP3);
613#endif
614}
615
616/* impSTART: This stuff should move back into the Cavium SDK */
617/*
618 ****************************************************************************************
619 *
620 * APP/BOOT  DESCRIPTOR  STUFF
621 *
622 ****************************************************************************************
623 */
624
625/* Define the struct that is initialized by the bootloader used by the
626 * startup code.
627 *
628 * Copyright (c) 2004, 2005, 2006 Cavium Networks.
629 *
630 * The authors hereby grant permission to use, copy, modify, distribute,
631 * and license this software and its documentation for any purpose, provided
632 * that existing copyright notices are retained in all copies and that this
633 * notice is included verbatim in any distributions. No written agreement,
634 * license, or royalty fee is required for any of the authorized uses.
635 * Modifications to this software may be copyrighted by their authors
636 * and need not follow the licensing terms described here, provided that
637 * the new terms are clearly indicated on the first page of each file where
638 * they apply.
639 */
640
641#define OCTEON_CURRENT_DESC_VERSION     6
642#define OCTEON_ARGV_MAX_ARGS            (64)
643#define OCTOEN_SERIAL_LEN 20
644
645
646typedef struct {
647	/* Start of block referenced by assembly code - do not change! */
648	uint32_t desc_version;
649	uint32_t desc_size;
650
651	uint64_t stack_top;
652	uint64_t heap_base;
653	uint64_t heap_end;
654	uint64_t entry_point;   /* Only used by bootloader */
655	uint64_t desc_vaddr;
656	/* End of This block referenced by assembly code - do not change! */
657
658	uint32_t exception_base_addr;
659	uint32_t stack_size;
660	uint32_t heap_size;
661	uint32_t argc;  /* Argc count for application */
662	uint32_t argv[OCTEON_ARGV_MAX_ARGS];
663	uint32_t flags;
664	uint32_t core_mask;
665	uint32_t dram_size;  /**< DRAM size in megabyes */
666	uint32_t phy_mem_desc_addr;  /**< physical address of free memory descriptor block*/
667	uint32_t debugger_flags_base_addr;  /**< used to pass flags from app to debugger */
668	uint32_t eclock_hz;  /**< CPU clock speed, in hz */
669	uint32_t dclock_hz;  /**< DRAM clock speed, in hz */
670	uint32_t spi_clock_hz;  /**< SPI4 clock in hz */
671	uint16_t board_type;
672	uint8_t board_rev_major;
673	uint8_t board_rev_minor;
674	uint16_t chip_type;
675	uint8_t chip_rev_major;
676	uint8_t chip_rev_minor;
677	char board_serial_number[OCTOEN_SERIAL_LEN];
678	uint8_t mac_addr_base[6];
679	uint8_t mac_addr_count;
680	uint64_t cvmx_desc_vaddr;
681} octeon_boot_descriptor_t;
682
683
684typedef struct {
685	uint32_t major_version;
686	uint32_t minor_version;
687
688	uint64_t stack_top;
689	uint64_t heap_base;
690	uint64_t heap_end;
691	uint64_t desc_vaddr;
692
693	uint32_t exception_base_addr;
694	uint32_t stack_size;
695	uint32_t flags;
696	uint32_t core_mask;
697	uint32_t dram_size;  /**< DRAM size in megabyes */
698	uint32_t phy_mem_desc_addr;  /**< physical address of free memory descriptor block*/
699	uint32_t debugger_flags_base_addr;  /**< used to pass flags from app to debugger */
700	uint32_t eclock_hz;  /**< CPU clock speed, in hz */
701	uint32_t dclock_hz;  /**< DRAM clock speed, in hz */
702	uint32_t spi_clock_hz;  /**< SPI4 clock in hz */
703	uint16_t board_type;
704	uint8_t board_rev_major;
705	uint8_t board_rev_minor;
706	uint16_t chip_type;
707	uint8_t chip_rev_major;
708	uint8_t chip_rev_minor;
709	char board_serial_number[OCTOEN_SERIAL_LEN];
710	uint8_t mac_addr_base[6];
711	uint8_t mac_addr_count;
712} cvmx_bootinfo_t;
713
714uint32_t octeon_cpu_clock;
715uint64_t octeon_dram;
716uint32_t octeon_bd_ver = 0, octeon_cvmx_bd_ver = 0, octeon_board_rev_major, octeon_board_rev_minor, octeon_board_type;
717uint8_t octeon_mac_addr[6] = { 0 };
718int octeon_core_mask, octeon_mac_addr_count;
719int octeon_chip_rev_major = 0, octeon_chip_rev_minor = 0, octeon_chip_type = 0;
720
721static octeon_boot_descriptor_t *app_desc_ptr;
722static cvmx_bootinfo_t *cvmx_desc_ptr;
723
724#define OCTEON_BOARD_TYPE_NONE 			0
725#define OCTEON_BOARD_TYPE_SIM  			1
726#define	OCTEON_BOARD_TYPE_CN3010_EVB_HS5	11
727
728#define OCTEON_CLOCK_MIN     (100 * 1000 * 1000)
729#define OCTEON_CLOCK_MAX     (800 * 1000 * 1000)
730#define OCTEON_DRAM_DEFAULT  (256 * 1024 * 1024)
731#define OCTEON_DRAM_MIN	     30
732#define OCTEON_DRAM_MAX	     3000
733
734
735int
736octeon_board_real(void)
737{
738	switch (octeon_board_type) {
739	case OCTEON_BOARD_TYPE_NONE:
740	case OCTEON_BOARD_TYPE_SIM:
741		return 0;
742	case OCTEON_BOARD_TYPE_CN3010_EVB_HS5:
743		/*
744		 * XXX
745		 * The CAM-0100 identifies itself as type 11, revision 0.0,
746		 * despite its being rather real.  Disable the revision check
747		 * for type 11.
748		 */
749		return 1;
750	default:
751		if (octeon_board_rev_major == 0)
752			return 0;
753		return 1;
754	}
755}
756
757static void
758octeon_process_app_desc_ver_unknown(void)
759{
760    	printf(" Unknown Boot-Descriptor: Using Defaults\n");
761
762    	octeon_cpu_clock = OCTEON_CLOCK_DEFAULT;
763        octeon_dram = OCTEON_DRAM_DEFAULT;
764        octeon_board_rev_major = octeon_board_rev_minor = octeon_board_type = 0;
765        octeon_core_mask = 1;
766        octeon_chip_type = octeon_chip_rev_major = octeon_chip_rev_minor = 0;
767        octeon_mac_addr[0] = 0x00; octeon_mac_addr[1] = 0x0f;
768        octeon_mac_addr[2] = 0xb7; octeon_mac_addr[3] = 0x10;
769        octeon_mac_addr[4] = 0x09; octeon_mac_addr[5] = 0x06;
770        octeon_mac_addr_count = 1;
771}
772
773static int
774octeon_process_app_desc_ver_6(void)
775{
776	/* XXX Why is 0x00000000ffffffffULL a bad value?  */
777	if (app_desc_ptr->cvmx_desc_vaddr == 0 ||
778	    app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) {
779            	printf ("Bad cvmx_desc_ptr %p\n", cvmx_desc_ptr);
780                return 1;
781	}
782    	cvmx_desc_ptr =
783	    (cvmx_bootinfo_t *)(intptr_t)app_desc_ptr->cvmx_desc_vaddr;
784        cvmx_desc_ptr =
785	    (cvmx_bootinfo_t *) ((intptr_t)cvmx_desc_ptr | MIPS_KSEG0_START);
786        octeon_cvmx_bd_ver = (cvmx_desc_ptr->major_version * 100) +
787	    cvmx_desc_ptr->minor_version;
788        if (cvmx_desc_ptr->major_version != 1) {
789            	panic("Incompatible CVMX descriptor from bootloader: %d.%d %p\n",
790                       (int) cvmx_desc_ptr->major_version,
791                       (int) cvmx_desc_ptr->minor_version, cvmx_desc_ptr);
792        }
793
794        octeon_core_mask = cvmx_desc_ptr->core_mask;
795        octeon_cpu_clock  = cvmx_desc_ptr->eclock_hz;
796        octeon_board_type = cvmx_desc_ptr->board_type;
797        octeon_board_rev_major = cvmx_desc_ptr->board_rev_major;
798        octeon_board_rev_minor = cvmx_desc_ptr->board_rev_minor;
799        octeon_chip_type = cvmx_desc_ptr->chip_type;
800        octeon_chip_rev_major = cvmx_desc_ptr->chip_rev_major;
801        octeon_chip_rev_minor = cvmx_desc_ptr->chip_rev_minor;
802        octeon_mac_addr[0] = cvmx_desc_ptr->mac_addr_base[0];
803        octeon_mac_addr[1] = cvmx_desc_ptr->mac_addr_base[1];
804        octeon_mac_addr[2] = cvmx_desc_ptr->mac_addr_base[2];
805        octeon_mac_addr[3] = cvmx_desc_ptr->mac_addr_base[3];
806        octeon_mac_addr[4] = cvmx_desc_ptr->mac_addr_base[4];
807        octeon_mac_addr[5] = cvmx_desc_ptr->mac_addr_base[5];
808        octeon_mac_addr_count = cvmx_desc_ptr->mac_addr_count;
809
810        if (app_desc_ptr->dram_size > 16*1024*1024)
811            	octeon_dram = (uint64_t)app_desc_ptr->dram_size;
812	else
813            	octeon_dram = (uint64_t)app_desc_ptr->dram_size << 20;
814        return 0;
815}
816
817static void
818octeon_boot_params_init(register_t ptr)
819{
820	int bad_desc = 1;
821
822    	if (ptr != 0 && ptr < MAX_APP_DESC_ADDR) {
823	        app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr;
824		octeon_bd_ver = app_desc_ptr->desc_version;
825		if (app_desc_ptr->desc_version < 6)
826			panic("Your boot code is too old to be supported.\n");
827		if (app_desc_ptr->desc_version >= 6)
828			bad_desc = octeon_process_app_desc_ver_6();
829        }
830        if (bad_desc)
831        	octeon_process_app_desc_ver_unknown();
832
833        printf("Boot Descriptor Ver: %u -> %u/%u",
834               octeon_bd_ver, octeon_cvmx_bd_ver/100, octeon_cvmx_bd_ver%100);
835        printf("  CPU clock: %uMHz  Core Mask: %#x\n", octeon_cpu_clock/1000000, octeon_core_mask);
836        printf("  Dram: %u MB", (uint32_t)(octeon_dram >> 20));
837        printf("  Board Type: %u  Revision: %u/%u\n",
838               octeon_board_type, octeon_board_rev_major, octeon_board_rev_minor);
839        printf("  Octeon Chip: %u  Rev %u/%u",
840               octeon_chip_type, octeon_chip_rev_major, octeon_chip_rev_minor);
841
842        printf("  Mac Address %02X.%02X.%02X.%02X.%02X.%02X (%d)\n",
843	    octeon_mac_addr[0], octeon_mac_addr[1], octeon_mac_addr[2],
844	    octeon_mac_addr[3], octeon_mac_addr[4], octeon_mac_addr[5],
845	    octeon_mac_addr_count);
846}
847/* impEND: This stuff should move back into the Cavium SDK */
848