1210284Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40210284Sjmallett
41210284Sjmallett
42210284Sjmallett
43210284Sjmallett
44210284Sjmallett
45215990Sjmallett
46210284Sjmallett#include <stdio.h>
47210284Sjmallett#include <stdint.h>
48210284Sjmallett#include <stdlib.h>
49210284Sjmallett#include <string.h>
50232812Sjmallett#include "executive-config.h"
51210284Sjmallett#include "cvmx-config.h"
52210284Sjmallett#include "cvmx.h"
53210284Sjmallett#include "cvmx-spinlock.h"
54210284Sjmallett#include <octeon-app-init.h>
55210284Sjmallett#include "cvmx-sysinfo.h"
56210284Sjmallett#include "cvmx-bootmem.h"
57210284Sjmallett#include "cvmx-uart.h"
58210284Sjmallett#include "cvmx-coremask.h"
59210284Sjmallett#include "cvmx-core.h"
60210284Sjmallett#include "cvmx-interrupt.h"
61210284Sjmallett#include "cvmx-ebt3000.h"
62215990Sjmallett#include "cvmx-sim-magic.h"
63215990Sjmallett#include "cvmx-debug.h"
64232812Sjmallett#include "cvmx-qlm.h"
65232812Sjmallett#include "cvmx-scratch.h"
66232812Sjmallett#include "cvmx-helper-cfg.h"
67232812Sjmallett#include "cvmx-helper-jtag.h"
68232812Sjmallett#include <octeon_mem_map.h>
69232812Sjmallett#include "libfdt.h"
70215990Sjmallettint cvmx_debug_uart = -1;
71210284Sjmallett
72210284Sjmallett/**
73210284Sjmallett * @file
74210284Sjmallett *
75210284Sjmallett * Main entry point for all simple executive based programs.
76210284Sjmallett */
77210284Sjmallett
78210284Sjmallett
79210284Sjmallettextern void cvmx_interrupt_initialize(void);
80210284Sjmallett
81210284Sjmallett
82210284Sjmallett
83210284Sjmallett/**
84210284Sjmallett * Main entry point for all simple executive based programs.
85210284Sjmallett * This is the first C function called. It completes
86210284Sjmallett * initialization, calls main, and performs C level cleanup.
87210284Sjmallett *
88210284Sjmallett * @param app_desc_addr
89210284Sjmallett *               Address of the application description structure passed
90210284Sjmallett *               brom the boot loader.
91210284Sjmallett */
92210284SjmallettEXTERN_ASM void __cvmx_app_init(uint64_t app_desc_addr);
93210284Sjmallett
94210284Sjmallett
95210284Sjmallett/**
96210284Sjmallett * Set up sysinfo structure from boot descriptor versions 6 and higher.
97210284Sjmallett * In these versions, the interesting data in not in the boot info structure
98210284Sjmallett * defined by the toolchain, but is in the cvmx_bootinfo structure defined in
99210284Sjmallett * the simple exec.
100210284Sjmallett *
101210284Sjmallett * @param app_desc_ptr
102210284Sjmallett *               pointer to boot descriptor block
103210284Sjmallett *
104210284Sjmallett * @param sys_info_ptr
105210284Sjmallett *               pointer to sysinfo structure to fill in
106210284Sjmallett */
107210284Sjmallettstatic void process_boot_desc_ver_6(octeon_boot_descriptor_t *app_desc_ptr, cvmx_sysinfo_t *sys_info_ptr)
108210284Sjmallett{
109210284Sjmallett    cvmx_bootinfo_t *cvmx_bootinfo_ptr = CASTPTR(cvmx_bootinfo_t, app_desc_ptr->cvmx_desc_vaddr);
110210284Sjmallett
111210284Sjmallett    /* copy application information for simple exec use */
112210284Sjmallett    /* Populate the sys_info structure from the boot descriptor block created by the bootloader.
113210284Sjmallett    ** The boot descriptor block is put in the top of the heap, so it will be overwritten when the
114210284Sjmallett    ** heap is fully used.  Information that is to be used must be copied before that.
115210284Sjmallett    ** Applications should only use the sys_info structure, not the boot descriptor
116210284Sjmallett    */
117210284Sjmallett    if (cvmx_bootinfo_ptr->major_version == 1)
118210284Sjmallett    {
119210284Sjmallett        sys_info_ptr->core_mask = cvmx_bootinfo_ptr->core_mask;
120210284Sjmallett        sys_info_ptr->heap_base = cvmx_bootinfo_ptr->heap_base;
121210284Sjmallett        sys_info_ptr->heap_size = cvmx_bootinfo_ptr->heap_end - cvmx_bootinfo_ptr->heap_base;
122210284Sjmallett        sys_info_ptr->stack_top = cvmx_bootinfo_ptr->stack_top;
123210284Sjmallett        sys_info_ptr->stack_size = cvmx_bootinfo_ptr->stack_size;
124210284Sjmallett        sys_info_ptr->init_core = cvmx_get_core_num();
125215990Sjmallett        sys_info_ptr->phy_mem_desc_addr = cvmx_bootinfo_ptr->phy_mem_desc_addr;
126210284Sjmallett        sys_info_ptr->exception_base_addr = cvmx_bootinfo_ptr->exception_base_addr;
127210284Sjmallett        sys_info_ptr->cpu_clock_hz  = cvmx_bootinfo_ptr->eclock_hz;
128210284Sjmallett        sys_info_ptr->dram_data_rate_hz  = cvmx_bootinfo_ptr->dclock_hz * 2;
129210284Sjmallett
130210284Sjmallett        sys_info_ptr->board_type = cvmx_bootinfo_ptr->board_type;
131210284Sjmallett        sys_info_ptr->board_rev_major = cvmx_bootinfo_ptr->board_rev_major;
132210284Sjmallett        sys_info_ptr->board_rev_minor = cvmx_bootinfo_ptr->board_rev_minor;
133210284Sjmallett        memcpy(sys_info_ptr->mac_addr_base, cvmx_bootinfo_ptr->mac_addr_base, 6);
134210284Sjmallett        sys_info_ptr->mac_addr_count = cvmx_bootinfo_ptr->mac_addr_count;
135210284Sjmallett        memcpy(sys_info_ptr->board_serial_number, cvmx_bootinfo_ptr->board_serial_number, CVMX_BOOTINFO_OCTEON_SERIAL_LEN);
136210284Sjmallett        sys_info_ptr->console_uart_num = 0;
137210284Sjmallett        if (cvmx_bootinfo_ptr->flags & OCTEON_BL_FLAG_CONSOLE_UART1)
138210284Sjmallett            sys_info_ptr->console_uart_num = 1;
139210284Sjmallett
140215990Sjmallett        if (cvmx_bootinfo_ptr->dram_size > 32*1024*1024)
141210284Sjmallett            sys_info_ptr->system_dram_size = (uint64_t)cvmx_bootinfo_ptr->dram_size;  /* older bootloaders incorrectly gave this in bytes, so don't convert */
142210284Sjmallett        else
143210284Sjmallett            sys_info_ptr->system_dram_size = (uint64_t)cvmx_bootinfo_ptr->dram_size * 1024 * 1024;  /* convert from Megabytes to bytes */
144210284Sjmallett        if (cvmx_bootinfo_ptr->minor_version >= 1)
145210284Sjmallett        {
146210284Sjmallett            sys_info_ptr->compact_flash_common_base_addr = cvmx_bootinfo_ptr->compact_flash_common_base_addr;
147210284Sjmallett            sys_info_ptr->compact_flash_attribute_base_addr = cvmx_bootinfo_ptr->compact_flash_attribute_base_addr;
148210284Sjmallett            sys_info_ptr->led_display_base_addr = cvmx_bootinfo_ptr->led_display_base_addr;
149210284Sjmallett        }
150210284Sjmallett        else if (sys_info_ptr->board_type == CVMX_BOARD_TYPE_EBT3000 ||
151215990Sjmallett                 sys_info_ptr->board_type == CVMX_BOARD_TYPE_EBT5800 ||
152215990Sjmallett                 sys_info_ptr->board_type == CVMX_BOARD_TYPE_EBT5810)
153210284Sjmallett        {
154210284Sjmallett            /* Default these variables so that users of structure can be the same no
155210284Sjmallett            ** matter what version fo boot info block the bootloader passes */
156210284Sjmallett            sys_info_ptr->compact_flash_common_base_addr = 0x1d000000 + 0x800;
157210284Sjmallett            sys_info_ptr->compact_flash_attribute_base_addr = 0x1d010000;
158210284Sjmallett            if (sys_info_ptr->board_rev_major == 1)
159210284Sjmallett                sys_info_ptr->led_display_base_addr = 0x1d020000;
160210284Sjmallett            else
161210284Sjmallett                sys_info_ptr->led_display_base_addr = 0x1d020000 + 0xf8;
162210284Sjmallett        }
163210284Sjmallett        else
164210284Sjmallett        {
165210284Sjmallett            sys_info_ptr->compact_flash_common_base_addr = 0;
166210284Sjmallett            sys_info_ptr->compact_flash_attribute_base_addr = 0;
167210284Sjmallett            sys_info_ptr->led_display_base_addr = 0;
168210284Sjmallett        }
169210284Sjmallett
170210284Sjmallett        if (cvmx_bootinfo_ptr->minor_version >= 2)
171210284Sjmallett        {
172210284Sjmallett            sys_info_ptr->dfa_ref_clock_hz = cvmx_bootinfo_ptr->dfa_ref_clock_hz;
173210284Sjmallett            sys_info_ptr->bootloader_config_flags = cvmx_bootinfo_ptr->config_flags;
174210284Sjmallett        }
175210284Sjmallett        else
176210284Sjmallett        {
177210284Sjmallett            sys_info_ptr->dfa_ref_clock_hz = 0;
178210284Sjmallett            sys_info_ptr->bootloader_config_flags = 0;
179210284Sjmallett            if (app_desc_ptr->flags & OCTEON_BL_FLAG_DEBUG)
180210284Sjmallett                sys_info_ptr->bootloader_config_flags |= CVMX_BOOTINFO_CFG_FLAG_DEBUG;
181210284Sjmallett            if (app_desc_ptr->flags & OCTEON_BL_FLAG_NO_MAGIC)
182210284Sjmallett                sys_info_ptr->bootloader_config_flags |= CVMX_BOOTINFO_CFG_FLAG_NO_MAGIC;
183210284Sjmallett        }
184210284Sjmallett
185210284Sjmallett    }
186210284Sjmallett    else
187210284Sjmallett    {
188210284Sjmallett        printf("ERROR: Incompatible CVMX descriptor passed by bootloader: %d.%d\n",
189210284Sjmallett               (int)cvmx_bootinfo_ptr->major_version, (int)cvmx_bootinfo_ptr->minor_version);
190215990Sjmallett        exit(-1);
191210284Sjmallett    }
192232812Sjmallett    if ((cvmx_bootinfo_ptr->minor_version >= 3) && (cvmx_bootinfo_ptr->fdt_addr != 0))
193232812Sjmallett    {
194232812Sjmallett        sys_info_ptr->fdt_addr = UNMAPPED_PTR(cvmx_bootinfo_ptr->fdt_addr);
195232812Sjmallett        if (fdt_check_header((const void *)sys_info_ptr->fdt_addr))
196232812Sjmallett        {
197232812Sjmallett            printf("ERROR : Corrupt Device Tree.\n");
198232812Sjmallett            exit(-1);
199232812Sjmallett        }
200232812Sjmallett        printf("Using device tree\n");
201232812Sjmallett    }
202232812Sjmallett    else
203232812Sjmallett    {
204232812Sjmallett        sys_info_ptr->fdt_addr = 0;
205232812Sjmallett    }
206210284Sjmallett}
207210284Sjmallett
208210284Sjmallett
209210284Sjmallett/**
210210284Sjmallett * Interrupt handler for calling exit on Control-C interrupts.
211210284Sjmallett *
212210284Sjmallett * @param irq_number IRQ interrupt number
213210284Sjmallett * @param registers  CPU registers at the time of the interrupt
214210284Sjmallett * @param user_arg   Unused user argument
215210284Sjmallett */
216210284Sjmallettstatic void process_break_interrupt(int irq_number, uint64_t registers[32], void *user_arg)
217210284Sjmallett{
218210284Sjmallett    /* Exclude new functionality when building with older toolchains */
219210284Sjmallett#if OCTEON_APP_INIT_H_VERSION >= 3
220210284Sjmallett    int uart = irq_number - CVMX_IRQ_UART0;
221210284Sjmallett    cvmx_uart_lsr_t lsrval;
222210284Sjmallett
223210284Sjmallett    /* Check for a Control-C interrupt from the console. This loop will eat
224210284Sjmallett        all input received on the uart */
225210284Sjmallett    lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(uart));
226210284Sjmallett    while (lsrval.s.dr)
227210284Sjmallett    {
228210284Sjmallett        int c = cvmx_read_csr(CVMX_MIO_UARTX_RBR(uart));
229210284Sjmallett        if (c == '\003')
230210284Sjmallett        {
231210284Sjmallett            register uint64_t tmp;
232210284Sjmallett
233232812Sjmallett            /* Wait for an another Control-C if right now we have no
234232812Sjmallett               access to the console.  After this point we hold the
235232812Sjmallett               lock and use a different lock to synchronize between
236232812Sjmallett               the memfile dumps from different cores.  As a
237232812Sjmallett               consequence regular printfs *don't* work after this
238232812Sjmallett               point! */
239232812Sjmallett            if (__octeon_uart_trylock () == 1)
240232812Sjmallett                return;
241210284Sjmallett
242210284Sjmallett            /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also
243232812Sjmallett               set the MCD0 to be not masked by this core so we know
244232812Sjmallett               the signal is received by someone */
245210284Sjmallett            asm volatile (
246210284Sjmallett                "dmfc0 %0, $22\n"
247210284Sjmallett                "ori   %0, %0, 0x1110\n"
248210284Sjmallett                "dmtc0 %0, $22\n"
249210284Sjmallett                : "=r" (tmp));
250210284Sjmallett        }
251210284Sjmallett        lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(uart));
252210284Sjmallett    }
253210284Sjmallett#endif
254210284Sjmallett}
255210284Sjmallett
256210284Sjmallett/**
257210284Sjmallett * This is the debug exception handler with "break".  Before calling exit to
258210284Sjmallett * dump the profile-feedback output it releases the lock on the console.
259210284Sjmallett * This way if there is buffered data in stdout it can still be flushed.
260210284Sjmallett * stdio is required to flush all output during an fread.
261210284Sjmallett */
262210284Sjmallett
263210284Sjmallettstatic void exit_on_break(void)
264210284Sjmallett{
265210284Sjmallett#if OCTEON_APP_INIT_H_VERSION >= 4
266210284Sjmallett    unsigned int coremask = cvmx_sysinfo_get()->core_mask;
267210284Sjmallett
268210284Sjmallett    cvmx_coremask_barrier_sync(coremask);
269210284Sjmallett    if (cvmx_coremask_first_core(coremask))
270210284Sjmallett      __octeon_uart_unlock();
271210284Sjmallett#endif
272210284Sjmallett
273210284Sjmallett    exit(0);
274210284Sjmallett}
275210284Sjmallett
276210284Sjmallett/* Add string signature to applications so that we can easily tell what
277210284Sjmallett** Octeon revision they were compiled for. Don't make static to avoid unused
278210284Sjmallett** variable warning. */
279210284Sjmallett#define xstr(s) str(s)
280210284Sjmallett#define str(s) #s
281210284Sjmallett
282210284Sjmallettint octeon_model_version_check(uint32_t chip_id);
283210284Sjmallett
284210284Sjmallett#define OMS xstr(OCTEON_MODEL)
285210284Sjmallettchar octeon_rev_signature[] =
286210284Sjmallett#ifdef USE_RUNTIME_MODEL_CHECKS
287210284Sjmallett    "Compiled for runtime Octeon model checking";
288210284Sjmallett#else
289210284Sjmallett    "Compiled for Octeon processor id: "OMS;
290210284Sjmallett#endif
291210284Sjmallett
292232812Sjmallett#define OCTEON_BL_FLAG_HPLUG_CORES (1 << 6)
293210284Sjmallettvoid __cvmx_app_init(uint64_t app_desc_addr)
294210284Sjmallett{
295210284Sjmallett    /* App descriptor used by bootloader */
296210284Sjmallett    octeon_boot_descriptor_t *app_desc_ptr = CASTPTR(octeon_boot_descriptor_t, app_desc_addr);
297210284Sjmallett
298210284Sjmallett    /* app info structure used by the simple exec */
299210284Sjmallett    cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get();
300215990Sjmallett    int breakflag = 0;
301210284Sjmallett
302232812Sjmallett    //printf("coremask=%08x flags=%08x \n", app_desc_ptr->core_mask, app_desc_ptr->flags);
303210284Sjmallett    if (cvmx_coremask_first_core(app_desc_ptr->core_mask))
304210284Sjmallett    {
305232812Sjmallett        /* Intialize the bootmem allocator with the descriptor that was provided by
306232812Sjmallett        * the bootloader
307232812Sjmallett        * IMPORTANT:  All printfs must happen after this since PCI console uses named
308232812Sjmallett        * blocks.
309232812Sjmallett        */
310232812Sjmallett        cvmx_bootmem_init(CASTPTR(cvmx_bootinfo_t, app_desc_ptr->cvmx_desc_vaddr)->phy_mem_desc_addr);
311232812Sjmallett
312210284Sjmallett        /* do once per application setup  */
313210284Sjmallett        if (app_desc_ptr->desc_version < 6)
314210284Sjmallett        {
315210284Sjmallett            printf("Obsolete bootloader, can't run application\n");
316215990Sjmallett            exit(-1);
317210284Sjmallett        }
318210284Sjmallett        else
319210284Sjmallett        {
320210284Sjmallett            /* Handle all newer versions here.... */
321210284Sjmallett            if (app_desc_ptr->desc_version > 7)
322210284Sjmallett            {
323210284Sjmallett                printf("Warning: newer boot descripter version than expected\n");
324210284Sjmallett            }
325210284Sjmallett            process_boot_desc_ver_6(app_desc_ptr,sys_info_ptr);
326210284Sjmallett
327210284Sjmallett        }
328232812Sjmallett
329232812Sjmallett        /*
330232812Sjmallett         * set up the feature map and config.
331232812Sjmallett         */
332232812Sjmallett        octeon_feature_init();
333232812Sjmallett
334232812Sjmallett        __cvmx_helper_cfg_init();
335210284Sjmallett    }
336232812Sjmallett    /* The flags varibale get copied over at some places and tracing the origins
337232812Sjmallett       found that
338232812Sjmallett       ** In octeon_setup_boot_desc_block
339232812Sjmallett         . cvmx_bootinfo_array[core].flags is initialized and the various bits are set
340232812Sjmallett         . cvmx_bootinfo_array[core].flags gets copied to  boot_desc[core].flags
341232812Sjmallett         . Then boot_desc then get copied over to the end of the application heap and
342232812Sjmallett            boot_info_block_array[core].boot_descr_addr is set to point to the boot_desc
343232812Sjmallett            in heap.
344232812Sjmallett       ** In start_app boot_vect->boot_info_addr->boot_desc_addr is referenced and passed on
345232812Sjmallett       to octeon_setup_crt0_tlb() and this puts it into r16
346232812Sjmallett       ** In ctr0.S of the toolchain r16 is picked up and passed on as a parameter to
347232812Sjmallett       __cvmx_app_init
348210284Sjmallett
349232812Sjmallett       Note : boot_vect->boot_info_addr points to  boot_info_block_array[core] and this
350232812Sjmallett       pointer is setup in octeon_setup_boot_vector()
351232812Sjmallett    */
352232812Sjmallett
353232812Sjmallett    if (!(app_desc_ptr->flags & OCTEON_BL_FLAG_HPLUG_CORES))
354232812Sjmallett        cvmx_coremask_barrier_sync(app_desc_ptr->core_mask);
355232812Sjmallett
356232812Sjmallett
357215990Sjmallett    breakflag = sys_info_ptr->bootloader_config_flags & CVMX_BOOTINFO_CFG_FLAG_BREAK;
358215990Sjmallett
359215990Sjmallett    /* No need to initialize bootmem, interrupts, interrupt handler and error handler
360215990Sjmallett       if version does not match. */
361215990Sjmallett    if (cvmx_coremask_first_core(sys_info_ptr->core_mask))
362210284Sjmallett    {
363215990Sjmallett        /* Check to make sure the Chip version matches the configured version */
364215990Sjmallett        uint32_t chip_id = cvmx_get_proc_id();
365215990Sjmallett        /* Make sure we can properly run on this chip */
366215990Sjmallett        octeon_model_version_check(chip_id);
367210284Sjmallett    }
368210284Sjmallett    cvmx_interrupt_initialize();
369210284Sjmallett    if (cvmx_coremask_first_core(sys_info_ptr->core_mask))
370210284Sjmallett    {
371215990Sjmallett        int break_uart = 0;
372215990Sjmallett        unsigned int i;
373210284Sjmallett
374215990Sjmallett        if (breakflag && cvmx_debug_booted())
375215990Sjmallett        {
376215990Sjmallett            printf("ERROR: Using debug and break together in not supported.\n");
377215990Sjmallett            while (1)
378215990Sjmallett                ;
379215990Sjmallett        }
380210284Sjmallett
381215990Sjmallett        /* Search through the arguments for a break=X or a debug=X. */
382215990Sjmallett        for (i = 0; i < app_desc_ptr->argc; i++)
383215990Sjmallett        {
384215990Sjmallett            const char *argv = CASTPTR(const char, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, app_desc_ptr->argv[i]));
385215990Sjmallett            if (strncmp(argv, "break=", 6) == 0)
386215990Sjmallett                break_uart = atoi(argv + 6);
387215990Sjmallett            else if (strncmp(argv, "debug=", 6) == 0)
388215990Sjmallett                cvmx_debug_uart = atoi(argv + 6);
389215990Sjmallett        }
390210284Sjmallett
391215990Sjmallett        if (breakflag)
392210284Sjmallett        {
393215990Sjmallett            int32_t *trampoline = CASTPTR(int32_t, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, BOOTLOADER_DEBUG_TRAMPOLINE));
394215990Sjmallett            /* On debug exception, call exit_on_break from all cores. */
395215990Sjmallett            *trampoline = (int32_t)(long)&exit_on_break;
396215990Sjmallett            cvmx_uart_enable_intr(break_uart, process_break_interrupt);
397210284Sjmallett        }
398210284Sjmallett    }
399232812Sjmallett    if ( !(app_desc_ptr->flags & OCTEON_BL_FLAG_HPLUG_CORES))
400232812Sjmallett         cvmx_coremask_barrier_sync(app_desc_ptr->core_mask);
401210284Sjmallett
402210284Sjmallett    /* Clear BEV now that we have installed exception handlers. */
403210284Sjmallett    uint64_t tmp;
404210284Sjmallett    asm volatile (
405210284Sjmallett               "   .set push                  \n"
406210284Sjmallett               "   .set mips64                  \n"
407210284Sjmallett               "   .set noreorder               \n"
408210284Sjmallett               "   .set noat               \n"
409210284Sjmallett               "   mfc0 %[tmp], $12, 0          \n"
410210284Sjmallett               "   li   $at, 1 << 22            \n"
411210284Sjmallett               "   not  $at, $at                \n"
412210284Sjmallett               "   and  %[tmp], $at             \n"
413210284Sjmallett               "   mtc0 %[tmp], $12, 0          \n"
414210284Sjmallett               "   .set pop                  \n"
415210284Sjmallett                  : [tmp] "=&r" (tmp) : );
416210284Sjmallett
417210284Sjmallett    /* Set all cores to stop on MCD0 signals */
418210284Sjmallett    asm volatile(
419210284Sjmallett        "dmfc0 %0, $22, 0\n"
420210284Sjmallett        "or %0, %0, 0x1100\n"
421210284Sjmallett        "dmtc0 %0, $22, 0\n" : "=r" (tmp));
422210284Sjmallett
423210284Sjmallett    CVMX_SYNC;
424215990Sjmallett    /* Now intialize the debug exception handler as BEV is cleared. */
425232812Sjmallett    if ((!breakflag) && (!(app_desc_ptr->flags & OCTEON_BL_FLAG_HPLUG_CORES)))
426215990Sjmallett        cvmx_debug_init();
427215990Sjmallett
428210284Sjmallett    /* Synchronise all cores at this point */
429232812Sjmallett     if ( !(app_desc_ptr->flags & OCTEON_BL_FLAG_HPLUG_CORES))
430232812Sjmallett         cvmx_coremask_barrier_sync(app_desc_ptr->core_mask);
431210284Sjmallett
432210284Sjmallett}
433210284Sjmallett
434210284Sjmallettint cvmx_user_app_init(void)
435210284Sjmallett{
436210284Sjmallett    uint64_t bist_val;
437210284Sjmallett    uint64_t mask;
438210284Sjmallett    int bist_errors = 0;
439210284Sjmallett    uint64_t tmp;
440210284Sjmallett    uint64_t base_addr;
441210284Sjmallett
442210284Sjmallett
443210284Sjmallett    /* Put message on LED display */
444210284Sjmallett    if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM)
445232812Sjmallett        ebt3000_str_write("CVMX    ");
446210284Sjmallett
447210284Sjmallett    /* Check BIST results for COP0 registers, some values only meaningful in pass 2 */
448210284Sjmallett    CVMX_MF_CACHE_ERR(bist_val);
449232812Sjmallett    mask = (0x3fULL<<32); // Icache;BHT;AES;HSH/GFM;LRU;register file
450210284Sjmallett    bist_val &= mask;
451210284Sjmallett    if (bist_val)
452210284Sjmallett    {
453210284Sjmallett        printf("BIST FAILURE: COP0_CACHE_ERR: 0x%llx\n", (unsigned long long)bist_val);
454210284Sjmallett        bist_errors++;
455210284Sjmallett    }
456210284Sjmallett
457210284Sjmallett    mask = 0xfc00000000000000ull;
458210284Sjmallett    CVMX_MF_CVM_MEM_CTL(bist_val);
459210284Sjmallett    bist_val &=  mask;
460210284Sjmallett    if (bist_val)
461210284Sjmallett    {
462210284Sjmallett        printf("BIST FAILURE: COP0_CVM_MEM_CTL: 0x%llx\n", (unsigned long long)bist_val);
463210284Sjmallett        bist_errors++;
464210284Sjmallett    }
465210284Sjmallett
466210284Sjmallett    /* Set up 4 cache lines of local memory, make available from Kernel space */
467210284Sjmallett    CVMX_MF_CVM_MEM_CTL(tmp);
468210284Sjmallett    tmp &= ~0x1ffull;
469210284Sjmallett    tmp |= 0x104ull;
470215990Sjmallett    /* Set WBTHRESH=4 as per Core-14752 errata in cn63xxp1.X. */
471215990Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
472215990Sjmallett    {
473215990Sjmallett        tmp &= ~(0xfull << 11);
474215990Sjmallett        tmp |= 4 << 11;
475215990Sjmallett    }
476210284Sjmallett    CVMX_MT_CVM_MEM_CTL(tmp);
477210284Sjmallett
478232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_X))
479232812Sjmallett    {
480232812Sjmallett        /* Clear the lines of scratch memory configured, for
481232812Sjmallett        ** 63XX pass 2 errata Core-15169. */
482232812Sjmallett        uint64_t addr;
483232812Sjmallett        unsigned  num_lines;
484232812Sjmallett        CVMX_MF_CVM_MEM_CTL(tmp);
485232812Sjmallett        num_lines = tmp & 0x3f;
486232812Sjmallett        for (addr = 0; addr < CVMX_CACHE_LINE_SIZE * num_lines; addr += 8)
487232812Sjmallett            cvmx_scratch_write64(addr, 0);
488232812Sjmallett    }
489210284Sjmallett
490210284Sjmallett#if CVMX_USE_1_TO_1_TLB_MAPPINGS
491210284Sjmallett
492210284Sjmallett    /* Check to see if the bootloader is indicating that the application is outside
493210284Sjmallett    ** of the 0x10000000 0x20000000 range, in which case we can't use 1-1 mappings */
494210284Sjmallett    if (cvmx_sysinfo_get()->bootloader_config_flags & CVMX_BOOTINFO_CFG_FLAG_OVERSIZE_TLB_MAPPING)
495210284Sjmallett    {
496210284Sjmallett        printf("ERROR: 1-1 TLB mappings configured and oversize application loaded.\n");
497210284Sjmallett        printf("ERROR: Either 1-1 TLB mappings must be disabled or application size reduced.\n");
498215990Sjmallett        exit(-1);
499210284Sjmallett    }
500210284Sjmallett
501210284Sjmallett    /* Create 1-1 Mappings for all DRAM up to 8 gigs, excluding the low 1 Megabyte.  This area
502210284Sjmallett    ** is reserved for the bootloader and exception vectors.  By not mapping this area, NULL pointer
503210284Sjmallett    ** dereferences will be caught with TLB exceptions.  Exception handlers should be written
504210284Sjmallett    ** using XKPHYS or KSEG0 addresses. */
505210284Sjmallett#if CVMX_NULL_POINTER_PROTECT
506210284Sjmallett    /* Exclude low 1 MByte from mapping to detect NULL pointer accesses.
507210284Sjmallett    ** The only down side of this is it uses more TLB mappings */
508210284Sjmallett    cvmx_core_add_fixed_tlb_mapping_bits(0x0, 0x0, 0x100000  | TLB_DIRTY | TLB_VALID | TLB_GLOBAL, CVMX_TLB_PAGEMASK_1M);
509210284Sjmallett    cvmx_core_add_fixed_tlb_mapping(0x200000, 0x200000, 0x300000, CVMX_TLB_PAGEMASK_1M);
510210284Sjmallett    cvmx_core_add_fixed_tlb_mapping(0x400000, 0x400000, 0x500000, CVMX_TLB_PAGEMASK_1M);
511210284Sjmallett    cvmx_core_add_fixed_tlb_mapping(0x600000, 0x600000, 0x700000, CVMX_TLB_PAGEMASK_1M);
512210284Sjmallett
513210284Sjmallett    cvmx_core_add_fixed_tlb_mapping(0x800000,  0x800000,  0xC00000, CVMX_TLB_PAGEMASK_4M);
514210284Sjmallett    cvmx_core_add_fixed_tlb_mapping(0x1000000, 0x1000000, 0x1400000, CVMX_TLB_PAGEMASK_4M);
515210284Sjmallett    cvmx_core_add_fixed_tlb_mapping(0x1800000, 0x1800000, 0x1c00000, CVMX_TLB_PAGEMASK_4M);
516210284Sjmallett
517210284Sjmallett    cvmx_core_add_fixed_tlb_mapping(0x2000000, 0x2000000, 0x3000000, CVMX_TLB_PAGEMASK_16M);
518210284Sjmallett    cvmx_core_add_fixed_tlb_mapping(0x4000000, 0x4000000, 0x5000000, CVMX_TLB_PAGEMASK_16M);
519210284Sjmallett    cvmx_core_add_fixed_tlb_mapping(0x6000000, 0x6000000, 0x7000000, CVMX_TLB_PAGEMASK_16M);
520210284Sjmallett#else
521210284Sjmallett    /* Map entire low 128 Megs, including 0x0 */
522210284Sjmallett    cvmx_core_add_fixed_tlb_mapping(0x0, 0x0, 0x4000000ULL, CVMX_TLB_PAGEMASK_64M);
523210284Sjmallett#endif
524210284Sjmallett    cvmx_core_add_fixed_tlb_mapping(0x8000000ULL, 0x8000000ULL, 0xc000000ULL, CVMX_TLB_PAGEMASK_64M);
525210284Sjmallett
526215990Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
527210284Sjmallett    {
528215990Sjmallett        for (base_addr = 0x20000000ULL; base_addr < (cvmx_sysinfo_get()->system_dram_size + 0x10000000ULL); base_addr += 0x20000000ULL)
529210284Sjmallett        {
530210284Sjmallett            if (0 > cvmx_core_add_fixed_tlb_mapping(base_addr,  base_addr,  base_addr + 0x10000000ULL, CVMX_TLB_PAGEMASK_256M))
531210284Sjmallett            {
532210284Sjmallett                printf("ERROR adding 1-1 TLB mapping for address 0x%llx\n", (unsigned long long)base_addr);
533215990Sjmallett                /* Exit from here, as expected memory mappings aren't set
534215990Sjmallett                   up if this fails */
535232812Sjmallett                exit(-1);
536210284Sjmallett            }
537210284Sjmallett        }
538210284Sjmallett    }
539215990Sjmallett    else
540215990Sjmallett    {
541215990Sjmallett        /* Create 1-1 mapping for next 256 megs
542215990Sjmallett        ** bottom page is not valid */
543215990Sjmallett        cvmx_core_add_fixed_tlb_mapping_bits(0x400000000ULL, 0, 0x410000000ULL  | TLB_DIRTY | TLB_VALID | TLB_GLOBAL, CVMX_TLB_PAGEMASK_256M);
544210284Sjmallett
545215990Sjmallett        /* Map from 0.5 up to the installed memory size in 512 MByte chunks.  If this loop runs out of memory,
546215990Sjmallett        ** the NULL pointer detection can be disabled to free up more TLB entries. */
547215990Sjmallett        if (cvmx_sysinfo_get()->system_dram_size > 0x20000000ULL)
548215990Sjmallett        {
549215990Sjmallett            for (base_addr = 0x20000000ULL; base_addr <= (cvmx_sysinfo_get()->system_dram_size - 0x20000000ULL); base_addr += 0x20000000ULL)
550215990Sjmallett            {
551215990Sjmallett                if (0 > cvmx_core_add_fixed_tlb_mapping(base_addr,  base_addr,  base_addr + 0x10000000ULL, CVMX_TLB_PAGEMASK_256M))
552215990Sjmallett                {
553215990Sjmallett                    printf("ERROR adding 1-1 TLB mapping for address 0x%llx\n", (unsigned long long)base_addr);
554215990Sjmallett                    /* Exit from here, as expected memory mappings
555215990Sjmallett                       aren't set up if this fails */
556215990Sjmallett                    exit(-1);
557215990Sjmallett                }
558215990Sjmallett            }
559215990Sjmallett        }
560215990Sjmallett    }
561210284Sjmallett#endif
562210284Sjmallett
563210284Sjmallett
564210284Sjmallett    cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get();
565215990Sjmallett    cvmx_bootmem_init(sys_info_ptr->phy_mem_desc_addr);
566210284Sjmallett
567232812Sjmallett    /* Initialize QLM and JTAG settings. Also apply any erratas. */
568232812Sjmallett    if (cvmx_coremask_first_core(cvmx_sysinfo_get()->core_mask))
569232812Sjmallett        cvmx_qlm_init();
570232812Sjmallett
571210284Sjmallett    return(0);
572210284Sjmallett}
573210284Sjmallett
574210284Sjmallettvoid __cvmx_app_exit(void)
575210284Sjmallett{
576215990Sjmallett    cvmx_debug_finish();
577215990Sjmallett
578215990Sjmallett    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
579210284Sjmallett    {
580232812Sjmallett        CVMX_BREAK;
581215990Sjmallett    }
582215990Sjmallett    /* Hang forever, until more appropriate stand alone simple executive
583215990Sjmallett       exit() is implemented */
584210284Sjmallett
585215990Sjmallett    while (1);
586210284Sjmallett}
587210284Sjmallett
588210284Sjmallett
589210284Sjmallett
590