1194140Simp/*- 2194140Simp * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org> 3194140Simp * All rights reserved. 4194140Simp * 5194140Simp * Redistribution and use in source and binary forms, with or without 6194140Simp * modification, are permitted provided that the following conditions 7194140Simp * are met: 8194140Simp * 1. Redistributions of source code must retain the above copyright 9194140Simp * notice, this list of conditions and the following disclaimer. 10194140Simp * 2. Redistributions in binary form must reproduce the above copyright 11194140Simp * notice, this list of conditions and the following disclaimer in the 12194140Simp * documentation and/or other materials provided with the distribution. 13194140Simp * 14194140Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15194140Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16194140Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17194140Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18194140Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19194140Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20194140Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21194140Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22194140Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23194140Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24194140Simp * SUCH DAMAGE. 25194140Simp * 26194140Simp * $FreeBSD$ 27194140Simp */ 28194140Simp#include <sys/cdefs.h> 29194140Simp__FBSDID("$FreeBSD$"); 30194140Simp 31194140Simp#include <sys/param.h> 32196262Simp#include <sys/conf.h> 33196262Simp#include <sys/kernel.h> 34194140Simp#include <sys/systm.h> 35196262Simp#include <sys/imgact.h> 36196262Simp#include <sys/bio.h> 37196262Simp#include <sys/buf.h> 38196262Simp#include <sys/bus.h> 39196262Simp#include <sys/cpu.h> 40196262Simp#include <sys/cons.h> 41196262Simp#include <sys/exec.h> 42196262Simp#include <sys/ucontext.h> 43196262Simp#include <sys/proc.h> 44196262Simp#include <sys/kdb.h> 45196262Simp#include <sys/ptrace.h> 46196262Simp#include <sys/reboot.h> 47196262Simp#include <sys/signalvar.h> 48242302Sjmallett#include <sys/sysctl.h> 49196262Simp#include <sys/sysent.h> 50196262Simp#include <sys/sysproto.h> 51210311Sjmallett#include <sys/time.h> 52210311Sjmallett#include <sys/timetc.h> 53196262Simp#include <sys/user.h> 54196262Simp 55196262Simp#include <vm/vm.h> 56196262Simp#include <vm/vm_object.h> 57196262Simp#include <vm/vm_page.h> 58196262Simp 59196262Simp#include <machine/atomic.h> 60196262Simp#include <machine/cache.h> 61196262Simp#include <machine/clock.h> 62196262Simp#include <machine/cpu.h> 63194140Simp#include <machine/cpuregs.h> 64194140Simp#include <machine/cpufunc.h> 65202063Simp#include <mips/cavium/octeon_pcmap_regs.h> 66196262Simp#include <machine/hwfunc.h> 67196262Simp#include <machine/intr_machdep.h> 68196262Simp#include <machine/locore.h> 69196262Simp#include <machine/md_var.h> 70194140Simp#include <machine/pcpu.h> 71196262Simp#include <machine/pte.h> 72196262Simp#include <machine/trap.h> 73196262Simp#include <machine/vmparam.h> 74194140Simp 75210311Sjmallett#include <contrib/octeon-sdk/cvmx.h> 76210311Sjmallett#include <contrib/octeon-sdk/cvmx-bootmem.h> 77242273Sjmallett#include <contrib/octeon-sdk/cvmx-ebt3000.h> 78242342Sjmallett#include <contrib/octeon-sdk/cvmx-helper-cfg.h> 79210311Sjmallett#include <contrib/octeon-sdk/cvmx-interrupt.h> 80210311Sjmallett#include <contrib/octeon-sdk/cvmx-version.h> 81210311Sjmallett 82232812Sjmallett#include <mips/cavium/octeon_irq.h> 83232812Sjmallett 84194140Simp#if defined(__mips_n64) 85196262Simp#define MAX_APP_DESC_ADDR 0xffffffffafffffff 86194140Simp#else 87196262Simp#define MAX_APP_DESC_ADDR 0xafffffff 88194140Simp#endif 89194140Simp 90210311Sjmallettstruct octeon_feature_description { 91210311Sjmallett octeon_feature_t ofd_feature; 92210311Sjmallett const char *ofd_string; 93210311Sjmallett}; 94210311Sjmallett 95196262Simpextern int *end; 96217518Simpextern char cpu_model[]; 97217518Simpextern char cpu_board[]; 98194140Simp 99210311Sjmallettstatic const struct octeon_feature_description octeon_feature_descriptions[] = { 100210311Sjmallett { OCTEON_FEATURE_SAAD, "SAAD" }, 101210311Sjmallett { OCTEON_FEATURE_ZIP, "ZIP" }, 102210311Sjmallett { OCTEON_FEATURE_CRYPTO, "CRYPTO" }, 103216069Sjmallett { OCTEON_FEATURE_DORM_CRYPTO, "DORM_CRYPTO" }, 104210311Sjmallett { OCTEON_FEATURE_PCIE, "PCIE" }, 105216069Sjmallett { OCTEON_FEATURE_SRIO, "SRIO" }, 106210311Sjmallett { OCTEON_FEATURE_KEY_MEMORY, "KEY_MEMORY" }, 107210311Sjmallett { OCTEON_FEATURE_LED_CONTROLLER, "LED_CONTROLLER" }, 108210311Sjmallett { OCTEON_FEATURE_TRA, "TRA" }, 109210311Sjmallett { OCTEON_FEATURE_MGMT_PORT, "MGMT_PORT" }, 110210311Sjmallett { OCTEON_FEATURE_RAID, "RAID" }, 111210311Sjmallett { OCTEON_FEATURE_USB, "USB" }, 112210311Sjmallett { OCTEON_FEATURE_NO_WPTR, "NO_WPTR" }, 113210311Sjmallett { OCTEON_FEATURE_DFA, "DFA" }, 114210311Sjmallett { OCTEON_FEATURE_MDIO_CLAUSE_45, "MDIO_CLAUSE_45" }, 115216069Sjmallett { OCTEON_FEATURE_NPEI, "NPEI" }, 116232812Sjmallett { OCTEON_FEATURE_ILK, "ILK" }, 117232812Sjmallett { OCTEON_FEATURE_HFA, "HFA" }, 118232812Sjmallett { OCTEON_FEATURE_DFM, "DFM" }, 119232812Sjmallett { OCTEON_FEATURE_CIU2, "CIU2" }, 120232812Sjmallett { OCTEON_FEATURE_DICI_MODE, "DICI_MODE" }, 121232812Sjmallett { OCTEON_FEATURE_BIT_EXTRACTOR, "BIT_EXTRACTOR" }, 122232812Sjmallett { OCTEON_FEATURE_NAND, "NAND" }, 123232812Sjmallett { OCTEON_FEATURE_MMC, "MMC" }, 124232812Sjmallett { OCTEON_FEATURE_PKND, "PKND" }, 125232812Sjmallett { OCTEON_FEATURE_CN68XX_WQE, "CN68XX_WQE" }, 126210311Sjmallett { 0, NULL } 127210311Sjmallett}; 128210311Sjmallett 129210311Sjmallettstatic uint64_t octeon_get_ticks(void); 130210311Sjmallettstatic unsigned octeon_get_timecount(struct timecounter *tc); 131210311Sjmallett 132200344Simpstatic void octeon_boot_params_init(register_t ptr); 133200344Simp 134210311Sjmallettstatic struct timecounter octeon_timecounter = { 135210311Sjmallett octeon_get_timecount, /* get_timecount */ 136210311Sjmallett 0, /* no poll_pps */ 137210311Sjmallett 0xffffffffu, /* octeon_mask */ 138210311Sjmallett 0, /* frequency */ 139210311Sjmallett "Octeon", /* name */ 140210311Sjmallett 900, /* quality (adjusted in code) */ 141210311Sjmallett}; 142210311Sjmallett 143198669Srrsvoid 144198669Srrsplatform_cpu_init() 145198669Srrs{ 146198669Srrs /* Nothing special yet */ 147198669Srrs} 148196262Simp 149194140Simp/* 150194140Simp * Perform a board-level soft-reset. 151194140Simp */ 152196314Simpvoid 153196314Simpplatform_reset(void) 154194140Simp{ 155210311Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_RST, 1); 156194140Simp} 157194140Simp 158194140Simp/* 159194140Simp * octeon_debug_symbol 160194140Simp * 161194140Simp * Does nothing. 162194140Simp * Used to mark the point for simulator to begin tracing 163194140Simp */ 164201530Simpvoid 165201530Simpocteon_debug_symbol(void) 166194140Simp{ 167194140Simp} 168194140Simp 169194140Simp/* 170194140Simp * octeon_ciu_reset 171194140Simp * 172194140Simp * Shutdown all CIU to IP2, IP3 mappings 173194140Simp */ 174201530Simpvoid 175201530Simpocteon_ciu_reset(void) 176194140Simp{ 177233417Sgonzo uint64_t cvmctl; 178233417Sgonzo 179210311Sjmallett /* Disable all CIU interrupts by default */ 180210311Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2), 0); 181210311Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2+1), 0); 182210311Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2), 0); 183210311Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2+1), 0); 184194140Simp 185210311Sjmallett#ifdef SMP 186210311Sjmallett /* Enable the MBOX interrupts. */ 187210311Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2+1), 188232812Sjmallett (1ull << (OCTEON_IRQ_MBOX0 - 8)) | 189232812Sjmallett (1ull << (OCTEON_IRQ_MBOX1 - 8))); 190210311Sjmallett#endif 191233417Sgonzo 192233417Sgonzo /* 193233417Sgonzo * Move the Performance Counter interrupt to OCTEON_PMC_IRQ 194233417Sgonzo */ 195233417Sgonzo cvmctl = mips_rd_cvmctl(); 196233417Sgonzo cvmctl &= ~(7 << 7); 197233417Sgonzo cvmctl |= (OCTEON_PMC_IRQ + 2) << 7; 198233417Sgonzo mips_wr_cvmctl(cvmctl); 199194140Simp} 200194140Simp 201210311Sjmallettstatic void 202210311Sjmallettocteon_memory_init(void) 203194140Simp{ 204210311Sjmallett vm_paddr_t phys_end; 205210311Sjmallett int64_t addr; 206216318Sgonzo unsigned i, j; 207194140Simp 208210311Sjmallett phys_end = round_page(MIPS_KSEG0_TO_PHYS((vm_offset_t)&end)); 209194140Simp 210242346Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) { 211210311Sjmallett /* Simulator we limit to 96 meg */ 212210311Sjmallett phys_avail[0] = phys_end; 213210311Sjmallett phys_avail[1] = 96 << 20; 214194140Simp 215216318Sgonzo dump_avail[0] = phys_avail[0]; 216216320Sgonzo dump_avail[1] = phys_avail[1]; 217216318Sgonzo 218210311Sjmallett realmem = physmem = btoc(phys_avail[1] - phys_avail[0]); 219210311Sjmallett return; 220201530Simp } 221194140Simp 222210311Sjmallett /* 223210311Sjmallett * Allocate memory from bootmem 1MB at a time and merge 224210311Sjmallett * adjacent entries. 225210311Sjmallett */ 226210311Sjmallett i = 0; 227210311Sjmallett while (i < PHYS_AVAIL_ENTRIES) { 228216773Sjmallett /* 229216773Sjmallett * If there is less than 2MB of memory available in 128-byte 230216773Sjmallett * blocks, do not steal any more memory. We need to leave some 231216773Sjmallett * memory for the command queues to be allocated out of. 232216773Sjmallett */ 233216773Sjmallett if (cvmx_bootmem_available_mem(128) < 2 << 20) 234216773Sjmallett break; 235216773Sjmallett 236210311Sjmallett addr = cvmx_bootmem_phy_alloc(1 << 20, phys_end, 237210311Sjmallett ~(vm_paddr_t)0, PAGE_SIZE, 0); 238210311Sjmallett if (addr == -1) 239210311Sjmallett break; 240194140Simp 241212842Sjmallett /* 242212842Sjmallett * The SDK needs to be able to easily map any memory that might 243212842Sjmallett * come to it e.g. in the form of an mbuf. Because on !n64 we 244212842Sjmallett * can't direct-map some addresses and we don't want to manage 245212842Sjmallett * temporary mappings within the SDK, don't feed memory that 246212842Sjmallett * can't be direct-mapped to the kernel. 247212842Sjmallett */ 248212842Sjmallett#if !defined(__mips_n64) 249212842Sjmallett if (!MIPS_DIRECT_MAPPABLE(addr + (1 << 20) - 1)) 250212842Sjmallett continue; 251212842Sjmallett#endif 252212842Sjmallett 253210311Sjmallett physmem += btoc(1 << 20); 254194140Simp 255210311Sjmallett if (i > 0 && phys_avail[i - 1] == addr) { 256210311Sjmallett phys_avail[i - 1] += 1 << 20; 257210311Sjmallett continue; 258210311Sjmallett } 259194140Simp 260210311Sjmallett phys_avail[i + 0] = addr; 261210311Sjmallett phys_avail[i + 1] = addr + (1 << 20); 262194140Simp 263210311Sjmallett i += 2; 264201530Simp } 265194140Simp 266216320Sgonzo for (j = 0; j < i; j++) 267216318Sgonzo dump_avail[j] = phys_avail[j]; 268216318Sgonzo 269202831Simp realmem = physmem; 270202831Simp} 271202831Simp 272196262Simpvoid 273201530Simpplatform_start(__register_t a0, __register_t a1, __register_t a2 __unused, 274201530Simp __register_t a3) 275196262Simp{ 276210311Sjmallett const struct octeon_feature_description *ofd; 277196262Simp uint64_t platform_counter_freq; 278243469Sjmallett int rv; 279194140Simp 280243253Sjmallett mips_postboot_fixup(); 281243253Sjmallett 282210311Sjmallett /* 283243253Sjmallett * Initialize boot parameters so that we can determine things like 284243253Sjmallett * which console we shoud use, etc. 285210311Sjmallett */ 286243253Sjmallett octeon_boot_params_init(a3); 287210311Sjmallett 288201845Simp /* Initialize pcpu stuff */ 289201881Simp mips_pcpu0_init(); 290243253Sjmallett mips_timer_early_init(cvmx_sysinfo_get()->cpu_clock_hz); 291243253Sjmallett 292243253Sjmallett /* Initialize console. */ 293202831Simp cninit(); 294201845Simp 295243253Sjmallett /* 296243469Sjmallett * Display information about the CPU. 297243253Sjmallett */ 298243469Sjmallett#if !defined(OCTEON_MODEL) 299243469Sjmallett printf("Using runtime CPU model checks.\n"); 300243469Sjmallett#else 301243469Sjmallett printf("Compiled for CPU model: " __XSTRING(OCTEON_MODEL) "\n"); 302243469Sjmallett#endif 303243469Sjmallett strcpy(cpu_model, octeon_model_get_string(cvmx_get_proc_id())); 304243469Sjmallett printf("CPU Model: %s\n", cpu_model); 305243253Sjmallett printf("CPU clock: %uMHz Core Mask: %#x\n", 306243253Sjmallett cvmx_sysinfo_get()->cpu_clock_hz / 1000000, 307243253Sjmallett cvmx_sysinfo_get()->core_mask); 308243469Sjmallett rv = octeon_model_version_check(cvmx_get_proc_id()); 309243469Sjmallett if (rv == -1) 310243469Sjmallett panic("%s: kernel not compatible with this processor.", __func__); 311243253Sjmallett 312243469Sjmallett /* 313243469Sjmallett * Display information about the board. 314243469Sjmallett */ 315243253Sjmallett#if defined(OCTEON_BOARD_CAPK_0100ND) 316243253Sjmallett strcpy(cpu_board, "CAPK-0100ND"); 317243253Sjmallett if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_CN3010_EVB_HS5) { 318243253Sjmallett panic("Compiled for %s, but board type is %s.", cpu_board, 319243253Sjmallett cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type)); 320243253Sjmallett } 321243253Sjmallett#else 322243253Sjmallett strcpy(cpu_board, 323243253Sjmallett cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type)); 324243253Sjmallett#endif 325243253Sjmallett printf("Board: %s\n", cpu_board); 326243469Sjmallett printf("Board Type: %u Revision: %u/%u\n", 327243469Sjmallett cvmx_sysinfo_get()->board_type, 328243469Sjmallett cvmx_sysinfo_get()->board_rev_major, 329243469Sjmallett cvmx_sysinfo_get()->board_rev_minor); 330243253Sjmallett printf("Serial number: %s\n", cvmx_sysinfo_get()->board_serial_number); 331243253Sjmallett 332243469Sjmallett /* 333243469Sjmallett * Additional on-chip hardware/settings. 334243469Sjmallett * 335243469Sjmallett * XXX Display PCI host/target? What else? 336243469Sjmallett */ 337243469Sjmallett printf("MAC address base: %6D (%u configured)\n", 338243469Sjmallett cvmx_sysinfo_get()->mac_addr_base, ":", 339243469Sjmallett cvmx_sysinfo_get()->mac_addr_count); 340243469Sjmallett 341243469Sjmallett 342202831Simp octeon_ciu_reset(); 343210311Sjmallett /* 344210311Sjmallett * XXX 345210311Sjmallett * We can certainly parse command line arguments or U-Boot environment 346210311Sjmallett * to determine whether to bootverbose / single user / ... I think 347210311Sjmallett * stass has patches to add support for loader things to U-Boot even. 348210311Sjmallett */ 349196262Simp bootverbose = 1; 350194140Simp 351202831Simp /* 352202831Simp * For some reason on the cn38xx simulator ebase register is set to 353202831Simp * 0x80001000 at bootup time. Move it back to the default, but 354202831Simp * when we move to having support for multiple executives, we need 355202831Simp * to rethink this. 356202831Simp */ 357202831Simp mips_wr_ebase(0x80000000); 358196262Simp 359202831Simp octeon_memory_init(); 360196262Simp init_param1(); 361196262Simp init_param2(physmem); 362196262Simp mips_cpu_init(); 363202831Simp pmap_bootstrap(); 364202831Simp mips_proc0_init(); 365196262Simp mutex_init(); 366196262Simp kdb_init(); 367202850Simp#ifdef KDB 368202850Simp if (boothowto & RB_KDB) 369202850Simp kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 370196262Simp#endif 371217518Simp cpu_clock = cvmx_sysinfo_get()->cpu_clock_hz; 372217518Simp platform_counter_freq = cpu_clock; 373217518Simp octeon_timecounter.tc_frequency = cpu_clock; 374210311Sjmallett platform_timecounter = &octeon_timecounter; 375206721Sjmallett mips_timer_init_params(platform_counter_freq, 0); 376217518Simp set_cputicker(octeon_get_ticks, cpu_clock, 0); 377206721Sjmallett 378206721Sjmallett#ifdef SMP 379206721Sjmallett /* 380210311Sjmallett * Clear any pending IPIs. 381206721Sjmallett */ 382210311Sjmallett cvmx_write_csr(CVMX_CIU_MBOX_CLRX(0), 0xffffffff); 383206721Sjmallett#endif 384210311Sjmallett 385210311Sjmallett printf("Octeon SDK: %s\n", OCTEON_SDK_VERSION_STRING); 386210311Sjmallett printf("Available Octeon features:"); 387210311Sjmallett for (ofd = octeon_feature_descriptions; ofd->ofd_string != NULL; ofd++) 388210311Sjmallett if (octeon_has_feature(ofd->ofd_feature)) 389210311Sjmallett printf(" %s", ofd->ofd_string); 390210311Sjmallett printf("\n"); 391196262Simp} 392196262Simp 393210311Sjmallettstatic uint64_t 394210311Sjmallettocteon_get_ticks(void) 395210311Sjmallett{ 396210311Sjmallett uint64_t cvmcount; 397210311Sjmallett 398210311Sjmallett CVMX_MF_CYCLE(cvmcount); 399210311Sjmallett return (cvmcount); 400210311Sjmallett} 401210311Sjmallett 402210311Sjmallettstatic unsigned 403210311Sjmallettocteon_get_timecount(struct timecounter *tc) 404210311Sjmallett{ 405210311Sjmallett return ((unsigned)octeon_get_ticks()); 406210311Sjmallett} 407210311Sjmallett 408242302Sjmallettstatic int 409242302Sjmallettsysctl_machdep_led_display(SYSCTL_HANDLER_ARGS) 410242302Sjmallett{ 411242302Sjmallett size_t buflen; 412242302Sjmallett char buf[9]; 413242302Sjmallett int error; 414242302Sjmallett 415242302Sjmallett if (req->newptr == NULL) 416242302Sjmallett return (EINVAL); 417242302Sjmallett 418242302Sjmallett if (cvmx_sysinfo_get()->led_display_base_addr == 0) 419242302Sjmallett return (ENODEV); 420242302Sjmallett 421242302Sjmallett /* 422242302Sjmallett * Revision 1.x of the EBT3000 only supports 4 characters, but 423242302Sjmallett * other devices support 8. 424242302Sjmallett */ 425242302Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBT3000 && 426242302Sjmallett cvmx_sysinfo_get()->board_rev_major == 1) 427242302Sjmallett buflen = 4; 428242302Sjmallett else 429242302Sjmallett buflen = 8; 430242302Sjmallett 431242302Sjmallett if (req->newlen > buflen) 432242302Sjmallett return (E2BIG); 433242302Sjmallett 434242302Sjmallett error = SYSCTL_IN(req, buf, req->newlen); 435242302Sjmallett if (error != 0) 436242302Sjmallett return (error); 437242302Sjmallett 438242302Sjmallett buf[req->newlen] = '\0'; 439242302Sjmallett ebt3000_str_write(buf); 440242302Sjmallett 441242302Sjmallett return (0); 442242302Sjmallett} 443242302Sjmallett 444242302SjmallettSYSCTL_PROC(_machdep, OID_AUTO, led_display, CTLTYPE_STRING | CTLFLAG_WR, 445242302Sjmallett NULL, 0, sysctl_machdep_led_display, "A", 446242302Sjmallett "String to display on LED display"); 447242302Sjmallett 448243470Sjmallettvoid 449243470Sjmallettcvmx_dvprintf(const char *fmt, va_list ap) 450243470Sjmallett{ 451243470Sjmallett if (!bootverbose) 452243470Sjmallett return; 453243470Sjmallett vprintf(fmt, ap); 454243470Sjmallett} 455243470Sjmallett 456243470Sjmallettvoid 457243470Sjmallettcvmx_dprintf(const char *fmt, ...) 458243470Sjmallett{ 459243470Sjmallett va_list ap; 460243470Sjmallett 461243470Sjmallett va_start(ap, fmt); 462243470Sjmallett cvmx_dvprintf(fmt, ap); 463243470Sjmallett va_end(ap); 464243470Sjmallett} 465243470Sjmallett 466215990Sjmallett/** 467215990Sjmallett * version of printf that works better in exception context. 468215990Sjmallett * 469215990Sjmallett * @param format 470215990Sjmallett * 471215990Sjmallett * XXX If this function weren't in cvmx-interrupt.c, we'd use the SDK version. 472215990Sjmallett */ 473215990Sjmallettvoid cvmx_safe_printf(const char *format, ...) 474215990Sjmallett{ 475215990Sjmallett char buffer[256]; 476215990Sjmallett char *ptr = buffer; 477215990Sjmallett int count; 478215990Sjmallett va_list args; 479215990Sjmallett 480215990Sjmallett va_start(args, format); 481215990Sjmallett#ifndef __U_BOOT__ 482215990Sjmallett count = vsnprintf(buffer, sizeof(buffer), format, args); 483215990Sjmallett#else 484215990Sjmallett count = vsprintf(buffer, format, args); 485215990Sjmallett#endif 486215990Sjmallett va_end(args); 487215990Sjmallett 488215990Sjmallett while (count-- > 0) 489215990Sjmallett { 490215990Sjmallett cvmx_uart_lsr_t lsrval; 491215990Sjmallett 492215990Sjmallett /* Spin until there is room */ 493215990Sjmallett do 494215990Sjmallett { 495215990Sjmallett lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(0)); 496215990Sjmallett#if !defined(CONFIG_OCTEON_SIM_SPEED) 497215990Sjmallett if (lsrval.s.temt == 0) 498215990Sjmallett cvmx_wait(10000); /* Just to reduce the load on the system */ 499215990Sjmallett#endif 500215990Sjmallett } 501215990Sjmallett while (lsrval.s.temt == 0); 502215990Sjmallett 503215990Sjmallett if (*ptr == '\n') 504215990Sjmallett cvmx_write_csr(CVMX_MIO_UARTX_THR(0), '\r'); 505215990Sjmallett cvmx_write_csr(CVMX_MIO_UARTX_THR(0), *ptr++); 506215990Sjmallett } 507215990Sjmallett} 508215990Sjmallett 509202831Simp/* impSTART: This stuff should move back into the Cavium SDK */ 510194140Simp/* 511194140Simp **************************************************************************************** 512194140Simp * 513194140Simp * APP/BOOT DESCRIPTOR STUFF 514194140Simp * 515194140Simp **************************************************************************************** 516194140Simp */ 517194140Simp 518194140Simp/* Define the struct that is initialized by the bootloader used by the 519194140Simp * startup code. 520194140Simp * 521194140Simp * Copyright (c) 2004, 2005, 2006 Cavium Networks. 522194140Simp * 523194140Simp * The authors hereby grant permission to use, copy, modify, distribute, 524194140Simp * and license this software and its documentation for any purpose, provided 525194140Simp * that existing copyright notices are retained in all copies and that this 526194140Simp * notice is included verbatim in any distributions. No written agreement, 527194140Simp * license, or royalty fee is required for any of the authorized uses. 528194140Simp * Modifications to this software may be copyrighted by their authors 529194140Simp * and need not follow the licensing terms described here, provided that 530194140Simp * the new terms are clearly indicated on the first page of each file where 531194140Simp * they apply. 532194140Simp */ 533194140Simp 534194140Simp#define OCTEON_CURRENT_DESC_VERSION 6 535194140Simp#define OCTEON_ARGV_MAX_ARGS (64) 536194140Simp#define OCTOEN_SERIAL_LEN 20 537194140Simp 538194140Simptypedef struct { 539200344Simp /* Start of block referenced by assembly code - do not change! */ 540200344Simp uint32_t desc_version; 541200344Simp uint32_t desc_size; 542194140Simp 543200344Simp uint64_t stack_top; 544200344Simp uint64_t heap_base; 545200344Simp uint64_t heap_end; 546200344Simp uint64_t entry_point; /* Only used by bootloader */ 547200344Simp uint64_t desc_vaddr; 548200344Simp /* End of This block referenced by assembly code - do not change! */ 549194140Simp 550200344Simp uint32_t exception_base_addr; 551200344Simp uint32_t stack_size; 552200344Simp uint32_t heap_size; 553200344Simp uint32_t argc; /* Argc count for application */ 554200344Simp uint32_t argv[OCTEON_ARGV_MAX_ARGS]; 555200344Simp uint32_t flags; 556200344Simp uint32_t core_mask; 557200344Simp uint32_t dram_size; /**< DRAM size in megabyes */ 558200344Simp uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ 559200344Simp uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ 560200344Simp uint32_t eclock_hz; /**< CPU clock speed, in hz */ 561200344Simp uint32_t dclock_hz; /**< DRAM clock speed, in hz */ 562200344Simp uint32_t spi_clock_hz; /**< SPI4 clock in hz */ 563200344Simp uint16_t board_type; 564200344Simp uint8_t board_rev_major; 565200344Simp uint8_t board_rev_minor; 566200344Simp uint16_t chip_type; 567200344Simp uint8_t chip_rev_major; 568200344Simp uint8_t chip_rev_minor; 569200344Simp char board_serial_number[OCTOEN_SERIAL_LEN]; 570200344Simp uint8_t mac_addr_base[6]; 571200344Simp uint8_t mac_addr_count; 572200344Simp uint64_t cvmx_desc_vaddr; 573194140Simp} octeon_boot_descriptor_t; 574194140Simp 575243253Sjmallettstatic cvmx_bootinfo_t * 576243253Sjmallettocteon_process_app_desc_ver_6(octeon_boot_descriptor_t *app_desc_ptr) 577243253Sjmallett{ 578243253Sjmallett cvmx_bootinfo_t *octeon_bootinfo; 579194140Simp 580200344Simp /* XXX Why is 0x00000000ffffffffULL a bad value? */ 581200344Simp if (app_desc_ptr->cvmx_desc_vaddr == 0 || 582243253Sjmallett app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) { 583243253Sjmallett cvmx_safe_printf("Bad octeon_bootinfo %#jx\n", 584243253Sjmallett (uintmax_t)app_desc_ptr->cvmx_desc_vaddr); 585243253Sjmallett return (NULL); 586243253Sjmallett } 587210311Sjmallett 588243253Sjmallett octeon_bootinfo = cvmx_phys_to_ptr(app_desc_ptr->cvmx_desc_vaddr); 589243253Sjmallett if (octeon_bootinfo->major_version != 1) { 590243253Sjmallett cvmx_safe_printf("Incompatible CVMX descriptor from bootloader: %d.%d %p\n", 591243253Sjmallett (int) octeon_bootinfo->major_version, 592243253Sjmallett (int) octeon_bootinfo->minor_version, octeon_bootinfo); 593243253Sjmallett return (NULL); 594243253Sjmallett } 595194140Simp 596215990Sjmallett cvmx_sysinfo_minimal_initialize(octeon_bootinfo->phy_mem_desc_addr, 597210311Sjmallett octeon_bootinfo->board_type, 598210311Sjmallett octeon_bootinfo->board_rev_major, 599210311Sjmallett octeon_bootinfo->board_rev_minor, 600210311Sjmallett octeon_bootinfo->eclock_hz); 601242276Sjmallett memcpy(cvmx_sysinfo_get()->mac_addr_base, 602242276Sjmallett octeon_bootinfo->mac_addr_base, 6); 603228088Sgonzo cvmx_sysinfo_get()->mac_addr_count = octeon_bootinfo->mac_addr_count; 604228853Sgonzo cvmx_sysinfo_get()->compact_flash_common_base_addr = 605228853Sgonzo octeon_bootinfo->compact_flash_common_base_addr; 606228872Sgonzo cvmx_sysinfo_get()->compact_flash_attribute_base_addr = 607228872Sgonzo octeon_bootinfo->compact_flash_attribute_base_addr; 608232402Sjmallett cvmx_sysinfo_get()->core_mask = octeon_bootinfo->core_mask; 609242276Sjmallett cvmx_sysinfo_get()->led_display_base_addr = 610242276Sjmallett octeon_bootinfo->led_display_base_addr; 611242276Sjmallett memcpy(cvmx_sysinfo_get()->board_serial_number, 612242276Sjmallett octeon_bootinfo->board_serial_number, 613242276Sjmallett sizeof cvmx_sysinfo_get()->board_serial_number); 614243253Sjmallett return (octeon_bootinfo); 615194140Simp} 616194140Simp 617200344Simpstatic void 618200344Simpocteon_boot_params_init(register_t ptr) 619194140Simp{ 620243253Sjmallett octeon_boot_descriptor_t *app_desc_ptr; 621243253Sjmallett cvmx_bootinfo_t *octeon_bootinfo; 622243253Sjmallett 623243253Sjmallett if (ptr == 0 || ptr >= MAX_APP_DESC_ADDR) { 624243253Sjmallett cvmx_safe_printf("app descriptor passed at invalid address %#jx\n", 625210311Sjmallett (uintmax_t)ptr); 626243253Sjmallett platform_reset(); 627243253Sjmallett } 628194140Simp 629210311Sjmallett app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr; 630243253Sjmallett if (app_desc_ptr->desc_version < 6) { 631243253Sjmallett cvmx_safe_printf("Your boot code is too old to be supported.\n"); 632243253Sjmallett platform_reset(); 633243253Sjmallett } 634243253Sjmallett octeon_bootinfo = octeon_process_app_desc_ver_6(app_desc_ptr); 635243253Sjmallett if (octeon_bootinfo == NULL) { 636243253Sjmallett cvmx_safe_printf("Could not parse boot descriptor.\n"); 637243253Sjmallett platform_reset(); 638243253Sjmallett } 639210311Sjmallett 640242273Sjmallett if (cvmx_sysinfo_get()->led_display_base_addr != 0) { 641242273Sjmallett /* 642242273Sjmallett * Revision 1.x of the EBT3000 only supports 4 characters, but 643242273Sjmallett * other devices support 8. 644242273Sjmallett */ 645242273Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBT3000 && 646242273Sjmallett cvmx_sysinfo_get()->board_rev_major == 1) 647242273Sjmallett ebt3000_str_write("FBSD"); 648242273Sjmallett else 649242273Sjmallett ebt3000_str_write("FreeBSD!"); 650242273Sjmallett } 651242273Sjmallett 652243253Sjmallett if (cvmx_sysinfo_get()->phy_mem_desc_addr == (uint64_t)0) { 653243253Sjmallett cvmx_safe_printf("Your boot loader did not supply a memory descriptor.\n"); 654243253Sjmallett platform_reset(); 655243253Sjmallett } 656215990Sjmallett cvmx_bootmem_init(cvmx_sysinfo_get()->phy_mem_desc_addr); 657210311Sjmallett 658242342Sjmallett octeon_feature_init(); 659242342Sjmallett 660242342Sjmallett __cvmx_helper_cfg_init(); 661194140Simp} 662202831Simp/* impEND: This stuff should move back into the Cavium SDK */ 663