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