octeon_machdep.c revision 194140
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: projects/mips/sys/mips/mips4k/octeon32/octeon_machdep.c 194140 2009-06-14 02:46:07Z imp $
27 */
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: projects/mips/sys/mips/mips4k/octeon32/octeon_machdep.c 194140 2009-06-14 02:46:07Z imp $");
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <machine/cpuregs.h>
34#include <machine/cpufunc.h>
35#include <mips/mips4k/octeon32/octeonreg.h>
36#include <machine/atomic.h>
37#include <machine/pcpu.h>
38
39#if defined(__mips_n64)
40      #define MAX_APP_DESC_ADDR     0xffffffffafffffff
41#else
42      #define MAX_APP_DESC_ADDR     0xafffffff
43#endif
44
45
46/*
47 * Perform a board-level soft-reset.
48 * Note that this is not emulated by gxemul.
49 */
50void octeon_reset (void)
51{
52    void (*reset_func)(void) =  (void (*)(void) )0x1fc00000;
53    reset_func();
54}
55
56
57static inline uint32_t octeon_disable_interrupts (void)
58{
59    uint32_t status_bits;
60
61    status_bits = mips_rd_status();
62    mips_wr_status(status_bits & ~MIPS_SR_INT_IE);
63    return (status_bits);
64}
65
66
67static inline void octeon_set_interrupts (uint32_t status_bits)
68{
69    mips_wr_status(status_bits);
70}
71
72
73void octeon_led_write_char (int char_position, char val)
74{
75    uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
76
77    if (!octeon_board_real()) return;
78
79    char_position &= 0x7;  /* only 8 chars */
80    ptr += char_position;
81    oct_write8_x8(ptr, val);
82}
83
84void octeon_led_write_char0 (char val)
85{
86    uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
87
88    if (!octeon_board_real()) return;
89
90    oct_write8_x8(ptr, val);
91}
92
93void octeon_led_write_hexchar (int char_position, char hexval)
94{
95    uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
96    char char1, char2;
97
98    if (!octeon_board_real()) return;
99
100    char1 = (hexval >> 4) & 0x0f; char1 = (char1 < 10)?char1+'0':char1+'7';
101    char2 = (hexval  & 0x0f); char2 = (char2 < 10)?char2+'0':char2+'7';
102    char_position &= 0x7;  /* only 8 chars */
103    if (char_position > 6) char_position = 6;
104    ptr += char_position;
105    oct_write8_x8(ptr, char1);
106    ptr++;
107    oct_write8_x8(ptr, char2);
108}
109
110void octeon_led_write_string (const char *str)
111{
112    uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
113    int i;
114
115    if (!octeon_board_real()) return;
116
117    for (i=0; i<8; i++, ptr++) {
118        if (str && *str) {
119            oct_write8_x8(ptr, *str++);
120        } else {
121            oct_write8_x8(ptr, ' ');
122        }
123        oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
124    }
125}
126
127static char progress[8] = { '-', '/', '|', '\\', '-', '/', '|', '\\'};
128
129void octeon_led_run_wheel (/*int count, */int *prog_count, int led_position)
130{
131    if (!octeon_board_real()) return;
132
133    octeon_led_write_char(led_position, progress[*prog_count]);
134    *prog_count += 1;
135    *prog_count &= 0x7;
136}
137
138#define LSR_DATAREADY        0x01    /* Data ready */
139#define LSR_THRE             0x20    /* Transmit holding register empty */
140#define LSR_TEMT	     0x40    /* Transmitter Empty. THR, TSR & FIFO */
141#define USR_TXFIFO_NOTFULL   0x02    /* Uart TX FIFO Not full */
142
143/*
144 * octeon_uart_write_byte
145 *
146 * Put out a single byte off of uart port.
147 */
148
149void octeon_uart_write_byte (int uart_index, uint8_t ch)
150{
151    uint64_t val, val2;
152    if ((uart_index < 0) || (uart_index > 1)) {
153        return;
154    }
155
156    while (1) {
157        val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400));
158        val2 = oct_read64(OCTEON_MIO_UART0_USR + (uart_index * 0x400));
159        if ((((uint8_t) val) & LSR_THRE) ||
160            (((uint8_t) val2) & USR_TXFIFO_NOTFULL)) {
161            break;
162        }
163    }
164
165    /* Write the byte */
166    oct_write8(OCTEON_MIO_UART0_THR + (uart_index * 0x400), (uint64_t) ch);
167
168    /* Force Flush the IOBus */
169    oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
170}
171
172
173void octeon_uart_write_byte0 (uint8_t ch)
174{
175    uint64_t val, val2;
176
177    while (1) {
178        val = oct_read64(OCTEON_MIO_UART0_LSR);
179        val2 = oct_read64(OCTEON_MIO_UART0_USR);
180        if ((((uint8_t) val) & LSR_THRE) ||
181            (((uint8_t) val2) & USR_TXFIFO_NOTFULL)) {
182            break;
183        }
184    }
185
186    /* Write the byte */
187    oct_write8(OCTEON_MIO_UART0_THR, (uint64_t) ch);
188
189    /* Force Flush the IOBus */
190    oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
191}
192
193/*
194 * octeon_uart_write_string
195 *
196 */
197void octeon_uart_write_string (int uart_index, const char *str)
198{
199     /* Just loop writing one byte at a time */
200
201    while (*str)
202    {
203        octeon_uart_write_byte(uart_index, *str);
204        if (*str == '\n') {
205            octeon_uart_write_byte(uart_index, '\r');
206        }
207        str++;
208    }
209 }
210
211static char wstr[30];
212
213void octeon_led_write_hex (uint32_t wl)
214{
215    char nbuf[80];
216
217    sprintf(nbuf, "%X", wl);
218    octeon_led_write_string(nbuf);
219}
220
221
222void octeon_uart_write_hex2 (uint32_t wl, uint32_t wh)
223{
224    sprintf(wstr, "0x%X-0x%X  ", wh, wl);
225    octeon_uart_write_string(0, wstr);
226}
227
228void octeon_uart_write_hex (uint32_t wl)
229{
230    sprintf(wstr, " 0x%X  ", wl);
231    octeon_uart_write_string(0, wstr);
232}
233
234
235#define OCT_CONS_BUFLEN	200
236static char console_str_buff0[OCT_CONS_BUFLEN + 1];
237#include <machine/stdarg.h>
238
239
240//#define USE_KERN_SUBR_PRINTF
241
242#ifndef USE_KERN_SUBR_PRINTF
243static int oct_printf (const char *fmt, va_list ap);
244#endif
245
246int kern_cons_printf (const char *fmt, ...)
247{
248	va_list ap;
249
250	va_start(ap, fmt);
251#ifndef USE_KERN_SUBR_PRINTF
252        oct_printf(fmt, ap);
253#else
254        ker_printf(fmt, ap);
255#endif
256        va_end(ap);
257        return (0);
258}
259
260#ifndef USE_KERN_SUBR_PRINTF
261static int oct_printf (const char *fmt, va_list ap)
262{
263        snprintf(console_str_buff0, OCT_CONS_BUFLEN, fmt, ap);
264        octeon_uart_write_string(0, console_str_buff0);
265        return (0);
266}
267#endif
268
269
270int console_printf (const char *fmt, ...)
271{
272	va_list ap;
273
274	va_start(ap, fmt);
275        sprintf(console_str_buff0, fmt, ap);
276        va_end(ap);
277        octeon_uart_write_string(0, console_str_buff0);
278        return (0);
279}
280
281
282
283
284/*
285 * octeon_wait_uart_flush
286 */
287void octeon_wait_uart_flush (int uart_index, uint8_t ch)
288{
289    uint64_t val;
290    int64_t val3;
291    uint32_t cpu_status_bits;
292
293    if ((uart_index < 0) || (uart_index > 1)) {
294        return;
295    }
296
297    cpu_status_bits = octeon_disable_interrupts();
298    /* Force Flush the IOBus */
299    oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
300    for (val3 = 0xfffffffff; val3 > 0; val3--) {
301        val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400));
302        if (((uint8_t) val) & LSR_TEMT) {
303            break;
304        }
305    }
306    octeon_set_interrupts(cpu_status_bits);
307}
308
309
310/*
311 * octeon_debug_symbol
312 *
313 * Does nothing.
314 * Used to mark the point for simulator to begin tracing
315 */
316void octeon_debug_symbol (void)
317{
318}
319
320void octeon_ciu_stop_gtimer (int timer)
321{
322    oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), 0ll);
323}
324
325void octeon_ciu_start_gtimer (int timer, u_int one_shot, uint64_t time_cycles)
326{
327    	octeon_ciu_gentimer gentimer;
328
329        gentimer.word64 = 0;
330        gentimer.bits.one_shot = one_shot;
331        gentimer.bits.len = time_cycles - 1;
332        oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), gentimer.word64);
333}
334
335/*
336 * octeon_ciu_reset
337 *
338 * Shutdown all CIU to IP2, IP3 mappings
339 */
340void octeon_ciu_reset (void)
341{
342
343    octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_0);
344    octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_1);
345    octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_2);
346    octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_3);
347
348    ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0);
349    ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_1);
350    ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0);
351    ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1);
352
353    ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0, 0ll);
354    ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0, 0ll);
355    ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1, 0ll);
356}
357
358/*
359 * mips_disable_interrupt_controllers
360 *
361 * Disable interrupts in the CPU controller
362 */
363void mips_disable_interrupt_controls (void)
364{
365    /*
366     * Disable interrupts in CIU.
367     */
368    octeon_ciu_reset();
369}
370
371static uint64_t ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx);
372
373/*
374 * ciu_get_intr_sum_reg_addr
375 */
376static uint64_t ciu_get_intr_sum_reg_addr (int core_num, int intx, int enx)
377{
378    uint64_t ciu_intr_sum_reg_addr;
379
380    	if (enx == CIU_EN_0) {
381            	ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_BASE_ADDR + (core_num * 0x10) +
382                                        (intx * 0x8);
383        } else {
384            	ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_INT1_ADDR;
385        }
386
387        return (ciu_intr_sum_reg_addr);
388}
389
390
391static uint64_t ciu_get_intr_en_reg_addr(int core_num, int intx, int enx);
392
393/*
394 * ciu_get_intr_en_reg_addr
395 */
396static uint64_t ciu_get_intr_en_reg_addr (int core_num, int intx, int enx)
397{
398    uint64_t ciu_intr_reg_addr;
399
400
401    	ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR + ((enx == 0) ? 0x0 : 0x8) +
402                            (intx * 0x10) +  (core_num * 0x20);
403
404        return (ciu_intr_reg_addr);
405}
406
407
408
409
410uint64_t ciu_get_en_reg_addr_new (int corenum, int intx, int enx, int ciu_ip);
411
412/*
413 * ciu_get_intr_reg_addr
414 *
415 * 200 ---int0,en0 ip2
416 * 208 ---int0,en1 ip2 ----> this is wrong... this is watchdog
417 *
418 * 210 ---int0,en0 ip3 --
419 * 218 ---int0,en1 ip3 ----> same here.. .this is watchdog... right?
420 *
421 * 220 ---int1,en0 ip2
422 * 228 ---int1,en1 ip2
423 * 230 ---int1,en0 ip3 --
424 * 238 ---int1,en1 ip3
425 *
426 */
427uint64_t ciu_get_en_reg_addr_new (int corenum, int intx, int enx, int ciu_ip)
428{
429    uint64_t ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR;
430
431    if (enx < CIU_EN_0 || enx > CIU_EN_1) {
432        printf("%s: invalid enx value %d, should be %d or %d\n",
433               __FUNCTION__, enx, CIU_EN_0, CIU_EN_1);
434        return 0;
435    }
436    if (intx < CIU_INT_0 || intx > CIU_INT_1) {
437        printf("%s: invalid intx value %d, should be %d or %d\n",
438               __FUNCTION__, enx, CIU_INT_0, CIU_INT_1);
439        return 0;
440    }
441    if (ciu_ip < CIU_MIPS_IP2 || ciu_ip > CIU_MIPS_IP3) {
442        printf("%s: invalid ciu_ip value %d, should be %d or %d\n",
443               __FUNCTION__, ciu_ip, CIU_MIPS_IP2, CIU_MIPS_IP3);
444        return 0;
445    }
446
447    ciu_intr_reg_addr += (enx    * 0x8);
448    ciu_intr_reg_addr += (ciu_ip * 0x10);
449    ciu_intr_reg_addr += (intx   * 0x20);
450
451    return (ciu_intr_reg_addr);
452}
453
454/*
455 * ciu_get_int_summary
456 */
457uint64_t ciu_get_int_summary (int core_num, int intx, int enx)
458{
459    uint64_t ciu_intr_sum_reg_addr;
460
461    if (core_num == CIU_THIS_CORE) {
462        	core_num = octeon_get_core_num();
463    }
464    ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx);
465    return (oct_read64(ciu_intr_sum_reg_addr));
466}
467
468//#define DEBUG_CIU 1
469
470#ifdef DEBUG_CIU
471#define DEBUG_CIU_SUM 1
472#define DEBUG_CIU_EN 1
473#endif
474
475
476/*
477 * ciu_clear_int_summary
478 */
479void ciu_clear_int_summary (int core_num, int intx, int enx, uint64_t write_bits)
480{
481    uint32_t cpu_status_bits;
482    uint64_t ciu_intr_sum_reg_addr;
483
484//#define DEBUG_CIU_SUM 1
485
486#ifdef DEBUG_CIU_SUM
487    uint64_t ciu_intr_sum_bits;
488#endif
489
490
491    if (core_num == CIU_THIS_CORE) {
492        	core_num = octeon_get_core_num();
493    }
494
495#ifdef DEBUG_CIU_SUM
496        printf(" CIU: core %u clear sum IntX %u  Enx %u  Bits: 0x%llX\n",
497               core_num, intx, enx, write_bits);
498#endif
499
500    cpu_status_bits = octeon_disable_interrupts();
501
502    ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx);
503
504#ifdef DEBUG_CIU_SUM
505    	ciu_intr_sum_bits =  oct_read64(ciu_intr_sum_reg_addr);	/* unneeded dummy read */
506        printf(" CIU: status: 0x%X  reg_addr: 0x%llX   Val: 0x%llX   ->  0x%llX",
507               cpu_status_bits, ciu_intr_sum_reg_addr, ciu_intr_sum_bits,
508               ciu_intr_sum_bits | write_bits);
509#endif
510
511    oct_write64(ciu_intr_sum_reg_addr, write_bits);
512    oct_read64(OCTEON_MIO_BOOT_BIST_STAT);	/* Bus Barrier */
513
514#ifdef DEBUG_CIU_SUM
515        printf(" Readback: 0x%llX\n\n   ", (uint64_t) oct_read64(ciu_intr_sum_reg_addr));
516#endif
517
518    octeon_set_interrupts(cpu_status_bits);
519}
520
521/*
522 * ciu_disable_intr
523 */
524void ciu_disable_intr (int core_num, int intx, int enx)
525{
526    uint32_t cpu_status_bits;
527    uint64_t ciu_intr_reg_addr;
528
529    if (core_num == CIU_THIS_CORE) {
530        	core_num = octeon_get_core_num();
531    }
532
533    cpu_status_bits = octeon_disable_interrupts();
534
535    ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
536
537    oct_read64(ciu_intr_reg_addr);	/* Dummy read */
538
539    oct_write64(ciu_intr_reg_addr, 0LL);
540    oct_read64(OCTEON_MIO_BOOT_BIST_STAT);	/* Bus Barrier */
541
542    octeon_set_interrupts(cpu_status_bits);
543}
544
545void ciu_dump_interrutps_enabled (int core_num, int intx, int enx, int ciu_ip);
546void ciu_dump_interrutps_enabled (int core_num, int intx, int enx, int ciu_ip)
547{
548
549	uint64_t ciu_intr_reg_addr;
550	uint64_t ciu_intr_bits;
551
552        if (core_num == CIU_THIS_CORE) {
553            	core_num = octeon_get_core_num();
554        }
555
556#ifndef OCTEON_SMP_1
557	ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
558#else
559	ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip);
560#endif
561
562        if (!ciu_intr_reg_addr) {
563            printf("Bad call to %s\n", __FUNCTION__);
564            while(1);
565            return;
566        }
567
568	ciu_intr_bits =  oct_read64(ciu_intr_reg_addr);
569        printf(" CIU core %d  int: %d  en: %d  ip: %d  Add: 0x%llX  enabled: 0x%llX   SR: %X\n",
570               core_num, intx, enx, ciu_ip, ciu_intr_reg_addr, ciu_intr_bits, mips_rd_status());
571}
572
573
574/*
575 * ciu_enable_interrupts
576 */
577void ciu_enable_interrupts (int core_num, int intx, int enx, uint64_t set_these_interrupt_bits,
578                            int ciu_ip)
579{
580
581	uint32_t cpu_status_bits;
582	uint64_t ciu_intr_reg_addr;
583	uint64_t ciu_intr_bits;
584
585        if (core_num == CIU_THIS_CORE) {
586            	core_num = octeon_get_core_num();
587        }
588
589//#define DEBUG_CIU_EN 1
590
591#ifdef DEBUG_CIU_EN
592        printf(" CIU: core %u enabling Intx %u  Enx %u IP %d  Bits: 0x%llX\n",
593               core_num, intx, enx, ciu_ip, set_these_interrupt_bits);
594#endif
595
596	cpu_status_bits = octeon_disable_interrupts();
597
598#ifndef OCTEON_SMP_1
599	ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
600#else
601	ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip);
602#endif
603
604        if (!ciu_intr_reg_addr) {
605            printf("Bad call to %s\n", __FUNCTION__);
606            while(1);
607            return;
608        }
609
610	ciu_intr_bits =  oct_read64(ciu_intr_reg_addr);
611
612#ifdef DEBUG_CIU_EN
613        printf(" CIU: status: 0x%X  reg_addr: 0x%llX   Val: 0x%llX   ->  0x%llX",
614               cpu_status_bits, ciu_intr_reg_addr, ciu_intr_bits, ciu_intr_bits | set_these_interrupt_bits);
615#endif
616	ciu_intr_bits |=  set_these_interrupt_bits;
617	oct_write64(ciu_intr_reg_addr, ciu_intr_bits);
618#ifdef OCTEON_SMP
619	mips_wbflush();
620#endif
621	oct_read64(OCTEON_MIO_BOOT_BIST_STAT);	/* Bus Barrier */
622
623#ifdef DEBUG_CIU_EN
624        printf(" Readback: 0x%llX\n\n   ", (uint64_t) oct_read64(ciu_intr_reg_addr));
625#endif
626
627	octeon_set_interrupts(cpu_status_bits);
628}
629
630
631extern void mips_platform_init(void);
632
633void mips_platform_init (void)
634{
635        octeon_ciu_reset();
636    	octeon_uart_write_string(0, "\nPlatform Starting");
637}
638
639
640
641/*
642 ****************************************************************************************
643 *
644 * APP/BOOT  DESCRIPTOR  STUFF
645 *
646 ****************************************************************************************
647 */
648
649/* Define the struct that is initialized by the bootloader used by the
650 * startup code.
651 *
652 * Copyright (c) 2004, 2005, 2006 Cavium Networks.
653 *
654 * The authors hereby grant permission to use, copy, modify, distribute,
655 * and license this software and its documentation for any purpose, provided
656 * that existing copyright notices are retained in all copies and that this
657 * notice is included verbatim in any distributions. No written agreement,
658 * license, or royalty fee is required for any of the authorized uses.
659 * Modifications to this software may be copyrighted by their authors
660 * and need not follow the licensing terms described here, provided that
661 * the new terms are clearly indicated on the first page of each file where
662 * they apply.
663 */
664
665#define OCTEON_CURRENT_DESC_VERSION     6
666#define OCTEON_ARGV_MAX_ARGS            (64)
667#define OCTOEN_SERIAL_LEN 20
668
669
670typedef struct {
671    /* Start of block referenced by assembly code - do not change! */
672    uint32_t desc_version;
673    uint32_t desc_size;
674
675    uint64_t stack_top;
676    uint64_t heap_base;
677    uint64_t heap_end;
678    uint64_t entry_point;   /* Only used by bootloader */
679    uint64_t desc_vaddr;
680    /* End of This block referenced by assembly code - do not change! */
681
682    uint32_t exception_base_addr;
683    uint32_t stack_size;
684    uint32_t heap_size;
685    uint32_t argc;  /* Argc count for application */
686    uint32_t argv[OCTEON_ARGV_MAX_ARGS];
687    uint32_t flags;
688    uint32_t core_mask;
689    uint32_t dram_size;  /**< DRAM size in megabyes */
690    uint32_t phy_mem_desc_addr;  /**< physical address of free memory descriptor block*/
691    uint32_t debugger_flags_base_addr;  /**< used to pass flags from app to debugger */
692    uint32_t eclock_hz;  /**< CPU clock speed, in hz */
693    uint32_t dclock_hz;  /**< DRAM clock speed, in hz */
694    uint32_t spi_clock_hz;  /**< SPI4 clock in hz */
695    uint16_t board_type;
696    uint8_t board_rev_major;
697    uint8_t board_rev_minor;
698    uint16_t chip_type;
699    uint8_t chip_rev_major;
700    uint8_t chip_rev_minor;
701    char board_serial_number[OCTOEN_SERIAL_LEN];
702    uint8_t mac_addr_base[6];
703    uint8_t mac_addr_count;
704    uint64_t cvmx_desc_vaddr;
705
706} octeon_boot_descriptor_t;
707
708
709typedef struct {
710    uint32_t major_version;
711    uint32_t minor_version;
712
713    uint64_t stack_top;
714    uint64_t heap_base;
715    uint64_t heap_end;
716    uint64_t desc_vaddr;
717
718    uint32_t exception_base_addr;
719    uint32_t stack_size;
720    uint32_t flags;
721    uint32_t core_mask;
722    uint32_t dram_size;  /**< DRAM size in megabyes */
723    uint32_t phy_mem_desc_addr;  /**< physical address of free memory descriptor block*/
724    uint32_t debugger_flags_base_addr;  /**< used to pass flags from app to debugger */
725    uint32_t eclock_hz;  /**< CPU clock speed, in hz */
726    uint32_t dclock_hz;  /**< DRAM clock speed, in hz */
727    uint32_t spi_clock_hz;  /**< SPI4 clock in hz */
728    uint16_t board_type;
729    uint8_t board_rev_major;
730    uint8_t board_rev_minor;
731    uint16_t chip_type;
732    uint8_t chip_rev_major;
733    uint8_t chip_rev_minor;
734    char board_serial_number[OCTOEN_SERIAL_LEN];
735    uint8_t mac_addr_base[6];
736    uint8_t mac_addr_count;
737
738} cvmx_bootinfo_t;
739
740uint32_t octeon_cpu_clock;
741uint64_t octeon_dram;
742uint32_t octeon_bd_ver = 0, octeon_cvmx_bd_ver = 0, octeon_board_rev_major, octeon_board_rev_minor, octeon_board_type;
743uint8_t octeon_mac_addr[6] = { 0 };
744int octeon_core_mask, octeon_mac_addr_count;
745int octeon_chip_rev_major = 0, octeon_chip_rev_minor = 0, octeon_chip_type = 0;
746
747#if defined(__mips_n64)
748extern uint64_t app_descriptor_addr;
749#else
750extern uint32_t app_descriptor_addr;
751#endif
752static octeon_boot_descriptor_t *app_desc_ptr;
753static cvmx_bootinfo_t *cvmx_desc_ptr;
754
755#define OCTEON_BOARD_TYPE_NONE 0
756#define OCTEON_BOARD_TYPE_SIM  1
757
758#define OCTEON_CLOCK_MIN     (100 * 1000 * 1000)
759#define OCTEON_CLOCK_MAX     (800 * 1000 * 1000)
760#define OCTEON_DRAM_DEFAULT  (256 * 1024 * 1024)
761#define OCTEON_DRAM_MIN	     30
762#define OCTEON_DRAM_MAX	     3000
763
764
765int octeon_board_real (void)
766{
767     if ((octeon_board_type == OCTEON_BOARD_TYPE_NONE) ||
768        (octeon_board_type == OCTEON_BOARD_TYPE_SIM) ||
769        !octeon_board_rev_major) {
770        return 0;
771     }
772     return 1;
773}
774
775static void octeon_process_app_desc_ver_unknown (void)
776{
777    	printf(" Unknown Boot-Descriptor: Using Defaults\n");
778
779    	octeon_cpu_clock = OCTEON_CLOCK_DEFAULT;
780        octeon_dram = OCTEON_DRAM_DEFAULT;
781        octeon_board_rev_major = octeon_board_rev_minor = octeon_board_type = 0;
782
783        octeon_core_mask = 1;
784        octeon_cpu_clock  = OCTEON_CLOCK_DEFAULT;
785        octeon_chip_type = octeon_chip_rev_major = octeon_chip_rev_minor = 0;
786
787        octeon_mac_addr[0] = 0x00; octeon_mac_addr[1] = 0x0f;
788        octeon_mac_addr[2] = 0xb7; octeon_mac_addr[3] = 0x10;
789        octeon_mac_addr[4] = 0x09; octeon_mac_addr[5] = 0x06;
790        octeon_mac_addr_count = 1;
791}
792
793static int octeon_process_app_desc_ver_6 (void)
794{
795    	cvmx_desc_ptr = (cvmx_bootinfo_t *) ((long) app_desc_ptr->cvmx_desc_vaddr);
796
797        if ((cvmx_desc_ptr == NULL) || (cvmx_desc_ptr == (cvmx_bootinfo_t *)0xffffffff)) {
798            	printf ("Bad cvmx_desc_ptr  0x%X\n", cvmx_desc_ptr);
799                return 1;
800        }
801
802        cvmx_desc_ptr = (cvmx_bootinfo_t *) (((long) cvmx_desc_ptr) | MIPS_KSEG0_START);
803        octeon_cvmx_bd_ver = (cvmx_desc_ptr->major_version * 100) +
804                             cvmx_desc_ptr->minor_version;
805
806        if (cvmx_desc_ptr->major_version != 1) {
807            	printf("Incompatible CVMX descriptor from bootloader: %d.%d  0x%X\n",
808                       (int) cvmx_desc_ptr->major_version,
809                       (int) cvmx_desc_ptr->minor_version, cvmx_desc_ptr);
810                while (1);	/*  Never return */
811                return 1;	/*  Satisfy the compiler */
812        }
813
814        octeon_core_mask = cvmx_desc_ptr->core_mask;
815        octeon_cpu_clock  = cvmx_desc_ptr->eclock_hz;
816        octeon_board_type = cvmx_desc_ptr->board_type;
817        octeon_board_rev_major = cvmx_desc_ptr->board_rev_major;
818        octeon_board_rev_minor = cvmx_desc_ptr->board_rev_minor;
819        octeon_chip_type = cvmx_desc_ptr->chip_type;
820        octeon_chip_rev_major = cvmx_desc_ptr->chip_rev_major;
821        octeon_chip_rev_minor = cvmx_desc_ptr->chip_rev_minor;
822        octeon_mac_addr[0] = cvmx_desc_ptr->mac_addr_base[0];
823        octeon_mac_addr[1] = cvmx_desc_ptr->mac_addr_base[1];
824        octeon_mac_addr[2] = cvmx_desc_ptr->mac_addr_base[2];
825        octeon_mac_addr[3] = cvmx_desc_ptr->mac_addr_base[3];
826        octeon_mac_addr[4] = cvmx_desc_ptr->mac_addr_base[4];
827        octeon_mac_addr[5] = cvmx_desc_ptr->mac_addr_base[5];
828        octeon_mac_addr_count = cvmx_desc_ptr->mac_addr_count;
829
830        if (app_desc_ptr->dram_size > 16*1024*1024) {
831            	octeon_dram = (uint64_t)app_desc_ptr->dram_size;
832        } else {
833            	octeon_dram = (uint64_t)app_desc_ptr->dram_size * 1024 * 1024;
834        }
835        return 0;
836}
837
838static int octeon_process_app_desc_ver_3_4_5 (void)
839{
840
841    	octeon_cvmx_bd_ver = octeon_bd_ver;
842        octeon_core_mask = app_desc_ptr->core_mask;
843
844        if (app_desc_ptr->desc_version > 3) {
845            	octeon_cpu_clock = app_desc_ptr->eclock_hz;
846        } else {
847            	octeon_cpu_clock  = OCTEON_CLOCK_DEFAULT;
848        }
849
850        if (app_desc_ptr->dram_size > 16*1024*1024) {
851            	octeon_dram = (uint64_t)app_desc_ptr->dram_size;
852        } else {
853            	octeon_dram = (uint64_t)app_desc_ptr->dram_size * 1024 * 1024;
854        }
855
856        if (app_desc_ptr->desc_version > 4) {
857            	octeon_board_type = app_desc_ptr->board_type;
858                octeon_board_rev_major = app_desc_ptr->board_rev_major;
859                octeon_board_rev_minor = app_desc_ptr->board_rev_minor;
860                octeon_chip_type = app_desc_ptr->chip_type;
861                octeon_chip_rev_major = app_desc_ptr->chip_rev_major;
862                octeon_chip_rev_minor = app_desc_ptr->chip_rev_minor;
863
864                octeon_mac_addr[0] = app_desc_ptr->mac_addr_base[0];
865                octeon_mac_addr[1] = app_desc_ptr->mac_addr_base[1];
866                octeon_mac_addr[2] = app_desc_ptr->mac_addr_base[2];
867                octeon_mac_addr[3] = app_desc_ptr->mac_addr_base[3];
868                octeon_mac_addr[4] = app_desc_ptr->mac_addr_base[4];
869                octeon_mac_addr[5] = app_desc_ptr->mac_addr_base[5];
870                octeon_mac_addr_count = app_desc_ptr->mac_addr_count;
871        }
872        return 0;
873}
874
875
876void mips_boot_params_init(void);
877
878void mips_boot_params_init (void)
879{
880    int descriptor_not_parsed = 1;
881
882    	if ((app_descriptor_addr == 0) || (app_descriptor_addr >= MAX_APP_DESC_ADDR)) {
883
884        } else {
885
886	        app_desc_ptr = (octeon_boot_descriptor_t *) app_descriptor_addr;
887		octeon_bd_ver = app_desc_ptr->desc_version;
888
889                if ((octeon_bd_ver >= 3) && (octeon_bd_ver <= 5)) {
890		  descriptor_not_parsed = octeon_process_app_desc_ver_3_4_5();
891
892                } else if (app_desc_ptr->desc_version == 6) {
893                    	descriptor_not_parsed = octeon_process_app_desc_ver_6();
894                }
895
896        }
897
898        if (descriptor_not_parsed) {
899        	octeon_process_app_desc_ver_unknown();
900        }
901
902        printf("Boot Descriptor Ver: %u -> %u/%u",
903               octeon_bd_ver, octeon_cvmx_bd_ver/100, octeon_cvmx_bd_ver%100);
904        printf("  CPU clock: %uMHz\n", octeon_cpu_clock/1000000);
905        printf("  Dram: %u MB", (uint32_t)(octeon_dram >> 20));
906        printf("  Board Type: %u  Revision: %u/%u\n",
907               octeon_board_type, octeon_board_rev_major, octeon_board_rev_minor);
908        printf("  Octeon Chip: %u  Rev %u/%u",
909               octeon_chip_type, octeon_chip_rev_major, octeon_chip_rev_minor);
910
911        printf("  Mac Address %02X.%02X.%02X.%02X.%02X.%02X\n",
912               octeon_mac_addr[0], octeon_mac_addr[1], octeon_mac_addr[2],
913               octeon_mac_addr[3], octeon_mac_addr[4], octeon_mac_addr[5]);
914}
915