]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/cavium/octeon_machdep.c
MFV r331400: 8484 Implement aggregate sum and use for arc counters
[FreeBSD/FreeBSD.git] / sys / mips / cavium / octeon_machdep.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/conf.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h>
37 #include <sys/imgact.h>
38 #include <sys/bio.h>
39 #include <sys/buf.h>
40 #include <sys/bus.h>
41 #include <sys/cpu.h>
42 #include <sys/cons.h>
43 #include <sys/exec.h>
44 #include <sys/ucontext.h>
45 #include <sys/proc.h>
46 #include <sys/kdb.h>
47 #include <sys/ptrace.h>
48 #include <sys/reboot.h>
49 #include <sys/signalvar.h>
50 #include <sys/sysctl.h>
51 #include <sys/sysent.h>
52 #include <sys/sysproto.h>
53 #include <sys/time.h>
54 #include <sys/timetc.h>
55 #include <sys/user.h>
56
57 #include <vm/vm.h>
58 #include <vm/vm_object.h>
59 #include <vm/vm_page.h>
60
61 #include <machine/atomic.h>
62 #include <machine/cache.h>
63 #include <machine/clock.h>
64 #include <machine/cpu.h>
65 #include <machine/cpuregs.h>
66 #include <machine/cpufunc.h>
67 #include <mips/cavium/octeon_pcmap_regs.h>
68 #include <machine/hwfunc.h>
69 #include <machine/intr_machdep.h>
70 #include <machine/locore.h>
71 #include <machine/md_var.h>
72 #include <machine/pcpu.h>
73 #include <machine/pte.h>
74 #include <machine/trap.h>
75 #include <machine/vmparam.h>
76
77 #include <contrib/octeon-sdk/cvmx.h>
78 #include <contrib/octeon-sdk/cvmx-bootmem.h>
79 #include <contrib/octeon-sdk/cvmx-ebt3000.h>
80 #include <contrib/octeon-sdk/cvmx-helper-cfg.h>
81 #include <contrib/octeon-sdk/cvmx-interrupt.h>
82 #include <contrib/octeon-sdk/cvmx-version.h>
83
84 #include <mips/cavium/octeon_irq.h>
85
86 #if defined(__mips_n64) 
87 #define MAX_APP_DESC_ADDR     0xffffffffafffffff
88 #else
89 #define MAX_APP_DESC_ADDR     0xafffffff
90 #endif
91
92 struct octeon_feature_description {
93         octeon_feature_t ofd_feature;
94         const char *ofd_string;
95 };
96
97 extern int      *end;
98 extern char cpu_model[];
99 extern char cpu_board[];
100 static char octeon_kenv[0x2000];
101
102 static const struct octeon_feature_description octeon_feature_descriptions[] = {
103         { OCTEON_FEATURE_SAAD,                  "SAAD" },
104         { OCTEON_FEATURE_ZIP,                   "ZIP" },
105         { OCTEON_FEATURE_CRYPTO,                "CRYPTO" },
106         { OCTEON_FEATURE_DORM_CRYPTO,           "DORM_CRYPTO" },
107         { OCTEON_FEATURE_PCIE,                  "PCIE" },
108         { OCTEON_FEATURE_SRIO,                  "SRIO" },
109         { OCTEON_FEATURE_KEY_MEMORY,            "KEY_MEMORY" },
110         { OCTEON_FEATURE_LED_CONTROLLER,        "LED_CONTROLLER" },
111         { OCTEON_FEATURE_TRA,                   "TRA" },
112         { OCTEON_FEATURE_MGMT_PORT,             "MGMT_PORT" },
113         { OCTEON_FEATURE_RAID,                  "RAID" },
114         { OCTEON_FEATURE_USB,                   "USB" },
115         { OCTEON_FEATURE_NO_WPTR,               "NO_WPTR" },
116         { OCTEON_FEATURE_DFA,                   "DFA" },
117         { OCTEON_FEATURE_MDIO_CLAUSE_45,        "MDIO_CLAUSE_45" },
118         { OCTEON_FEATURE_NPEI,                  "NPEI" },
119         { OCTEON_FEATURE_ILK,                   "ILK" },
120         { OCTEON_FEATURE_HFA,                   "HFA" },
121         { OCTEON_FEATURE_DFM,                   "DFM" },
122         { OCTEON_FEATURE_CIU2,                  "CIU2" },
123         { OCTEON_FEATURE_DICI_MODE,             "DICI_MODE" },
124         { OCTEON_FEATURE_BIT_EXTRACTOR,         "BIT_EXTRACTOR" },
125         { OCTEON_FEATURE_NAND,                  "NAND" },
126         { OCTEON_FEATURE_MMC,                   "MMC" },
127         { OCTEON_FEATURE_PKND,                  "PKND" },
128         { OCTEON_FEATURE_CN68XX_WQE,            "CN68XX_WQE" },
129         { 0,                                    NULL }
130 };
131
132 static uint64_t octeon_get_ticks(void);
133 static unsigned octeon_get_timecount(struct timecounter *tc);
134
135 static void octeon_boot_params_init(register_t ptr);
136 static void octeon_init_kenv(register_t ptr);
137
138 static struct timecounter octeon_timecounter = {
139         octeon_get_timecount,   /* get_timecount */
140         0,                      /* no poll_pps */
141         0xffffffffu,            /* octeon_mask */
142         0,                      /* frequency */
143         "Octeon",               /* name */
144         900,                    /* quality (adjusted in code) */
145 };
146
147 void
148 platform_cpu_init()
149 {
150         /* Nothing special yet */
151 }
152
153 /*
154  * Perform a board-level soft-reset.
155  */
156 void
157 platform_reset(void)
158 {
159         cvmx_write_csr(CVMX_CIU_SOFT_RST, 1);
160 }
161
162 /*
163  * octeon_debug_symbol
164  *
165  * Does nothing.
166  * Used to mark the point for simulator to begin tracing
167  */
168 void
169 octeon_debug_symbol(void)
170 {
171 }
172
173 /*
174  * octeon_ciu_reset
175  *
176  * Shutdown all CIU to IP2, IP3 mappings
177  */
178 void
179 octeon_ciu_reset(void)
180 {
181         uint64_t cvmctl;
182
183         /* Disable all CIU interrupts by default */
184         cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2), 0);
185         cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2+1), 0);
186         cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2), 0);
187         cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2+1), 0);
188
189 #ifdef SMP
190         /* Enable the MBOX interrupts.  */
191         cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2+1),
192                        (1ull << (OCTEON_IRQ_MBOX0 - 8)) |
193                        (1ull << (OCTEON_IRQ_MBOX1 - 8)));
194 #endif
195
196         /* 
197          * Move the Performance Counter interrupt to OCTEON_PMC_IRQ
198          */
199         cvmctl = mips_rd_cvmctl();
200         cvmctl &= ~(7 << 7);
201         cvmctl |= (OCTEON_PMC_IRQ + 2) << 7;
202         mips_wr_cvmctl(cvmctl);
203 }
204
205 static void
206 octeon_memory_init(void)
207 {
208         vm_paddr_t phys_end;
209         int64_t addr;
210         unsigned i, j;
211
212         phys_end = round_page(MIPS_KSEG0_TO_PHYS((vm_offset_t)&end));
213
214         if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
215                 /* Simulator we limit to 96 meg */
216                 phys_avail[0] = phys_end;
217                 phys_avail[1] = 96 << 20;
218
219                 dump_avail[0] = phys_avail[0];
220                 dump_avail[1] = phys_avail[1];
221
222                 realmem = physmem = btoc(phys_avail[1] - phys_avail[0]);
223                 return;
224         }
225
226         /*
227          * Allocate memory from bootmem 1MB at a time and merge
228          * adjacent entries.
229          */
230         i = 0;
231         while (i < PHYS_AVAIL_ENTRIES) {
232                 /*
233                  * If there is less than 2MB of memory available in 128-byte
234                  * blocks, do not steal any more memory.  We need to leave some
235                  * memory for the command queues to be allocated out of.
236                  */
237                 if (cvmx_bootmem_available_mem(128) < 2 << 20)
238                         break;
239
240                 addr = cvmx_bootmem_phy_alloc(1 << 20, phys_end,
241                                               ~(vm_paddr_t)0, PAGE_SIZE, 0);
242                 if (addr == -1)
243                         break;
244
245                 /*
246                  * The SDK needs to be able to easily map any memory that might
247                  * come to it e.g. in the form of an mbuf.  Because on !n64 we
248                  * can't direct-map some addresses and we don't want to manage
249                  * temporary mappings within the SDK, don't feed memory that
250                  * can't be direct-mapped to the kernel.
251                  */
252 #if !defined(__mips_n64)
253                 if (!MIPS_DIRECT_MAPPABLE(addr + (1 << 20) - 1))
254                         continue;
255 #endif
256
257                 physmem += btoc(1 << 20);
258
259                 if (i > 0 && phys_avail[i - 1] == addr) {
260                         phys_avail[i - 1] += 1 << 20;
261                         continue;
262                 }
263
264                 phys_avail[i + 0] = addr;
265                 phys_avail[i + 1] = addr + (1 << 20);
266
267                 i += 2;
268         }
269
270         for (j = 0; j < i; j++)
271                 dump_avail[j] = phys_avail[j];
272
273         realmem = physmem;
274 }
275
276 void
277 platform_start(__register_t a0, __register_t a1, __register_t a2 __unused,
278     __register_t a3)
279 {
280         const struct octeon_feature_description *ofd;
281         uint64_t platform_counter_freq;
282         int rv;
283
284         mips_postboot_fixup();
285
286         /*
287          * Initialize boot parameters so that we can determine things like
288          * which console we shoud use, etc.
289          */
290         octeon_boot_params_init(a3);
291
292         /* Initialize pcpu stuff */
293         mips_pcpu0_init();
294         mips_timer_early_init(cvmx_sysinfo_get()->cpu_clock_hz);
295
296         /* Initialize console.  */
297         cninit();
298
299         /*
300          * Display information about the CPU.
301          */
302 #if !defined(OCTEON_MODEL)
303         printf("Using runtime CPU model checks.\n");
304 #else
305         printf("Compiled for CPU model: " __XSTRING(OCTEON_MODEL) "\n");
306 #endif
307         strcpy(cpu_model, octeon_model_get_string(cvmx_get_proc_id()));
308         printf("CPU Model: %s\n", cpu_model);
309         printf("CPU clock: %uMHz  Core Mask: %#x\n",
310                cvmx_sysinfo_get()->cpu_clock_hz / 1000000,
311                cvmx_sysinfo_get()->core_mask);
312         rv = octeon_model_version_check(cvmx_get_proc_id());
313         if (rv == -1)
314                 panic("%s: kernel not compatible with this processor.", __func__);
315
316         /*
317          * Display information about the board.
318          */
319 #if defined(OCTEON_BOARD_CAPK_0100ND)
320         strcpy(cpu_board, "CAPK-0100ND");
321         if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_CN3010_EVB_HS5) {
322                 panic("Compiled for %s, but board type is %s.", cpu_board,
323                        cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type));
324         }
325 #else
326         strcpy(cpu_board,
327                cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type));
328 #endif
329         printf("Board: %s\n", cpu_board);
330         printf("Board Type: %u  Revision: %u/%u\n",
331                cvmx_sysinfo_get()->board_type,
332                cvmx_sysinfo_get()->board_rev_major,
333                cvmx_sysinfo_get()->board_rev_minor);
334         printf("Serial number: %s\n", cvmx_sysinfo_get()->board_serial_number);
335
336         /*
337          * Additional on-chip hardware/settings.
338          *
339          * XXX Display PCI host/target?  What else?
340          */
341         printf("MAC address base: %6D (%u configured)\n",
342                cvmx_sysinfo_get()->mac_addr_base, ":",
343                cvmx_sysinfo_get()->mac_addr_count);
344
345
346         octeon_ciu_reset();
347         /*
348          * Convert U-Boot 'bootoctlinux' loader command line arguments into
349          * boot flags and kernel environment variables.
350          */
351         bootverbose = 1;
352         octeon_init_kenv(a3);
353
354         /*
355          * For some reason on the cn38xx simulator ebase register is set to
356          * 0x80001000 at bootup time.  Move it back to the default, but
357          * when we move to having support for multiple executives, we need
358          * to rethink this.
359          */
360         mips_wr_ebase(0x80000000);
361
362         octeon_memory_init();
363         init_param1();
364         init_param2(physmem);
365         mips_cpu_init();
366         pmap_bootstrap();
367         mips_proc0_init();
368         mutex_init();
369         kdb_init();
370 #ifdef KDB
371         if (boothowto & RB_KDB)
372                 kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
373 #endif
374         cpu_clock = cvmx_sysinfo_get()->cpu_clock_hz;
375         platform_counter_freq = cpu_clock;
376         octeon_timecounter.tc_frequency = cpu_clock;
377         platform_timecounter = &octeon_timecounter;
378         mips_timer_init_params(platform_counter_freq, 0);
379         set_cputicker(octeon_get_ticks, cpu_clock, 0);
380
381 #ifdef SMP
382         /*
383          * Clear any pending IPIs.
384          */
385         cvmx_write_csr(CVMX_CIU_MBOX_CLRX(0), 0xffffffff);
386 #endif
387
388         printf("Octeon SDK: %s\n", OCTEON_SDK_VERSION_STRING);
389         printf("Available Octeon features:");
390         for (ofd = octeon_feature_descriptions; ofd->ofd_string != NULL; ofd++)
391                 if (octeon_has_feature(ofd->ofd_feature))
392                         printf(" %s", ofd->ofd_string);
393         printf("\n");
394 }
395
396 static uint64_t
397 octeon_get_ticks(void)
398 {
399         uint64_t cvmcount;
400
401         CVMX_MF_CYCLE(cvmcount);
402         return (cvmcount);
403 }
404
405 static unsigned
406 octeon_get_timecount(struct timecounter *tc)
407 {
408         return ((unsigned)octeon_get_ticks());
409 }
410
411 static int
412 sysctl_machdep_led_display(SYSCTL_HANDLER_ARGS)
413 {
414         size_t buflen;
415         char buf[9];
416         int error;
417
418         if (req->newptr == NULL)
419                 return (EINVAL);
420
421         if (cvmx_sysinfo_get()->led_display_base_addr == 0)
422                 return (ENODEV);
423
424         /*
425          * Revision 1.x of the EBT3000 only supports 4 characters, but
426          * other devices support 8.
427          */
428         if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBT3000 &&
429             cvmx_sysinfo_get()->board_rev_major == 1)
430                 buflen = 4;
431         else
432                 buflen = 8;
433
434         if (req->newlen > buflen)
435                 return (E2BIG);
436
437         error = SYSCTL_IN(req, buf, req->newlen);
438         if (error != 0)
439                 return (error);
440
441         buf[req->newlen] = '\0';
442         ebt3000_str_write(buf);
443
444         return (0);
445 }
446
447 SYSCTL_PROC(_machdep, OID_AUTO, led_display, CTLTYPE_STRING | CTLFLAG_WR,
448     NULL, 0, sysctl_machdep_led_display, "A",
449     "String to display on LED display");
450
451 void
452 cvmx_dvprintf(const char *fmt, va_list ap)
453 {
454         if (!bootverbose)
455                 return;
456         vprintf(fmt, ap);
457 }
458
459 void
460 cvmx_dprintf(const char *fmt, ...)
461 {
462         va_list ap;
463
464         va_start(ap, fmt);
465         cvmx_dvprintf(fmt, ap);
466         va_end(ap);
467 }
468
469 /**
470  * version of printf that works better in exception context.
471  *
472  * @param format
473  *
474  * XXX If this function weren't in cvmx-interrupt.c, we'd use the SDK version.
475  */
476 void cvmx_safe_printf(const char *format, ...)
477 {
478     char buffer[256];
479     char *ptr = buffer;
480     int count;
481     va_list args;
482
483     va_start(args, format);
484 #ifndef __U_BOOT__
485     count = vsnprintf(buffer, sizeof(buffer), format, args);
486 #else
487     count = vsprintf(buffer, format, args);
488 #endif
489     va_end(args);
490
491     while (count-- > 0)
492     {
493         cvmx_uart_lsr_t lsrval;
494
495         /* Spin until there is room */
496         do
497         {
498             lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(0));
499 #if !defined(CONFIG_OCTEON_SIM_SPEED)
500             if (lsrval.s.temt == 0)
501                 cvmx_wait(10000);   /* Just to reduce the load on the system */
502 #endif
503         }
504         while (lsrval.s.temt == 0);
505
506         if (*ptr == '\n')
507             cvmx_write_csr(CVMX_MIO_UARTX_THR(0), '\r');
508         cvmx_write_csr(CVMX_MIO_UARTX_THR(0), *ptr++);
509     }
510 }
511
512 /* impSTART: This stuff should move back into the Cavium SDK */
513 /*
514  ****************************************************************************************
515  *
516  * APP/BOOT  DESCRIPTOR  STUFF
517  *
518  ****************************************************************************************
519  */
520
521 /* Define the struct that is initialized by the bootloader used by the 
522  * startup code.
523  *
524  * Copyright (c) 2004, 2005, 2006 Cavium Networks.
525  *
526  * The authors hereby grant permission to use, copy, modify, distribute,
527  * and license this software and its documentation for any purpose, provided
528  * that existing copyright notices are retained in all copies and that this
529  * notice is included verbatim in any distributions. No written agreement,
530  * license, or royalty fee is required for any of the authorized uses.
531  * Modifications to this software may be copyrighted by their authors
532  * and need not follow the licensing terms described here, provided that
533  * the new terms are clearly indicated on the first page of each file where
534  * they apply.
535  */
536
537 #define OCTEON_CURRENT_DESC_VERSION     6
538 #define OCTEON_ARGV_MAX_ARGS            (64)
539 #define OCTOEN_SERIAL_LEN 20
540
541 typedef struct {
542         /* Start of block referenced by assembly code - do not change! */
543         uint32_t desc_version;
544         uint32_t desc_size;
545
546         uint64_t stack_top;
547         uint64_t heap_base;
548         uint64_t heap_end;
549         uint64_t entry_point;   /* Only used by bootloader */
550         uint64_t desc_vaddr;
551         /* End of This block referenced by assembly code - do not change! */
552
553         uint32_t exception_base_addr;
554         uint32_t stack_size;
555         uint32_t heap_size;
556         uint32_t argc;  /* Argc count for application */
557         uint32_t argv[OCTEON_ARGV_MAX_ARGS];
558         uint32_t flags;
559         uint32_t core_mask;
560         uint32_t dram_size;  /**< DRAM size in megabyes */
561         uint32_t phy_mem_desc_addr;  /**< physical address of free memory descriptor block*/
562         uint32_t debugger_flags_base_addr;  /**< used to pass flags from app to debugger */
563         uint32_t eclock_hz;  /**< CPU clock speed, in hz */
564         uint32_t dclock_hz;  /**< DRAM clock speed, in hz */
565         uint32_t spi_clock_hz;  /**< SPI4 clock in hz */
566         uint16_t board_type;
567         uint8_t board_rev_major;
568         uint8_t board_rev_minor;
569         uint16_t chip_type;
570         uint8_t chip_rev_major;
571         uint8_t chip_rev_minor;
572         char board_serial_number[OCTOEN_SERIAL_LEN];
573         uint8_t mac_addr_base[6];
574         uint8_t mac_addr_count;
575         uint64_t cvmx_desc_vaddr;
576 } octeon_boot_descriptor_t;
577
578 static cvmx_bootinfo_t *
579 octeon_process_app_desc_ver_6(octeon_boot_descriptor_t *app_desc_ptr)
580 {
581         cvmx_bootinfo_t *octeon_bootinfo;
582
583         /* XXX Why is 0x00000000ffffffffULL a bad value?  */
584         if (app_desc_ptr->cvmx_desc_vaddr == 0 ||
585             app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) {
586                 cvmx_safe_printf("Bad octeon_bootinfo %#jx\n",
587                     (uintmax_t)app_desc_ptr->cvmx_desc_vaddr);
588                 return (NULL);
589         }
590
591         octeon_bootinfo = cvmx_phys_to_ptr(app_desc_ptr->cvmx_desc_vaddr);
592         if (octeon_bootinfo->major_version != 1) {
593                 cvmx_safe_printf("Incompatible CVMX descriptor from bootloader: %d.%d %p\n",
594                     (int) octeon_bootinfo->major_version,
595                     (int) octeon_bootinfo->minor_version, octeon_bootinfo);
596                 return (NULL);
597         }
598
599         cvmx_sysinfo_minimal_initialize(octeon_bootinfo->phy_mem_desc_addr,
600                                         octeon_bootinfo->board_type,
601                                         octeon_bootinfo->board_rev_major,
602                                         octeon_bootinfo->board_rev_minor,
603                                         octeon_bootinfo->eclock_hz);
604         memcpy(cvmx_sysinfo_get()->mac_addr_base,
605                octeon_bootinfo->mac_addr_base, 6);
606         cvmx_sysinfo_get()->mac_addr_count = octeon_bootinfo->mac_addr_count;
607         cvmx_sysinfo_get()->compact_flash_common_base_addr = 
608                 octeon_bootinfo->compact_flash_common_base_addr;
609         cvmx_sysinfo_get()->compact_flash_attribute_base_addr = 
610                 octeon_bootinfo->compact_flash_attribute_base_addr;
611         cvmx_sysinfo_get()->core_mask = octeon_bootinfo->core_mask;
612         cvmx_sysinfo_get()->led_display_base_addr =
613                 octeon_bootinfo->led_display_base_addr;
614         memcpy(cvmx_sysinfo_get()->board_serial_number,
615                octeon_bootinfo->board_serial_number,
616                sizeof cvmx_sysinfo_get()->board_serial_number);
617         return (octeon_bootinfo);
618 }
619
620 static void
621 octeon_boot_params_init(register_t ptr)
622 {
623         octeon_boot_descriptor_t *app_desc_ptr;
624         cvmx_bootinfo_t *octeon_bootinfo;
625
626         if (ptr == 0 || ptr >= MAX_APP_DESC_ADDR) {
627                 cvmx_safe_printf("app descriptor passed at invalid address %#jx\n",
628                     (uintmax_t)ptr);
629                 platform_reset();
630         }
631
632         app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr;
633         if (app_desc_ptr->desc_version < 6) {
634                 cvmx_safe_printf("Your boot code is too old to be supported.\n");
635                 platform_reset();
636         }
637         octeon_bootinfo = octeon_process_app_desc_ver_6(app_desc_ptr);
638         if (octeon_bootinfo == NULL) {
639                 cvmx_safe_printf("Could not parse boot descriptor.\n");
640                 platform_reset();
641         }
642
643         if (cvmx_sysinfo_get()->led_display_base_addr != 0) {
644                 /*
645                  * Revision 1.x of the EBT3000 only supports 4 characters, but
646                  * other devices support 8.
647                  */
648                 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBT3000 &&
649                     cvmx_sysinfo_get()->board_rev_major == 1)
650                         ebt3000_str_write("FBSD");
651                 else
652                         ebt3000_str_write("FreeBSD!");
653         }
654
655         if (cvmx_sysinfo_get()->phy_mem_desc_addr == (uint64_t)0) {
656                 cvmx_safe_printf("Your boot loader did not supply a memory descriptor.\n");
657                 platform_reset();
658         }
659         cvmx_bootmem_init(cvmx_sysinfo_get()->phy_mem_desc_addr);
660
661         octeon_feature_init();
662
663         __cvmx_helper_cfg_init();
664 }
665 /* impEND: This stuff should move back into the Cavium SDK */
666
667 static void
668 boothowto_parse(const char *v)
669 {
670         if ((v == NULL) || (*v != '-'))
671                 return;
672
673         while (*v != '\0') {
674                 v++;
675                 switch (*v) {
676                 case 'a': boothowto |= RB_ASKNAME; break;
677                 case 'C': boothowto |= RB_CDROM; break;
678                 case 'd': boothowto |= RB_KDB; break;
679                 case 'D': boothowto |= RB_MULTIPLE; break;
680                 case 'm': boothowto |= RB_MUTE; break;
681                 case 'g': boothowto |= RB_GDB; break;
682                 case 'h': boothowto |= RB_SERIAL; break;
683                 case 'p': boothowto |= RB_PAUSE; break;
684                 case 'r': boothowto |= RB_DFLTROOT; break;
685                 case 's': boothowto |= RB_SINGLE; break;
686                 case 'v': boothowto |= RB_VERBOSE; break;
687                 }
688         }
689 }
690
691 /*
692  * The boot loader command line may specify kernel environment variables or
693  * applicable boot flags of boot(8).
694  */
695 static void
696 octeon_init_kenv(register_t ptr)
697 {
698         int i;
699         char *n;
700         char *v;
701         octeon_boot_descriptor_t *app_desc_ptr;
702
703         app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr;
704         memset(octeon_kenv, 0, sizeof(octeon_kenv));
705         init_static_kenv(octeon_kenv, sizeof(octeon_kenv));
706
707         for (i = 0; i < app_desc_ptr->argc; i++) {
708                 v = cvmx_phys_to_ptr(app_desc_ptr->argv[i]);
709                 if (v == NULL)
710                         continue;
711                 if (*v == '-') {
712                         boothowto_parse(v);
713                         continue;
714                 }
715                 n = strsep(&v, "=");
716                 if (v == NULL)
717                         kern_setenv(n, "1");
718                 else
719                         kern_setenv(n, v);
720         }
721 }