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