162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2004-2007 Cavium Networks 762306a36Sopenharmony_ci * Copyright (C) 2008, 2009 Wind River Systems 862306a36Sopenharmony_ci * written by Ralf Baechle <ralf@linux-mips.org> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/compiler.h> 1162306a36Sopenharmony_ci#include <linux/vmalloc.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/console.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/export.h> 1762306a36Sopenharmony_ci#include <linux/interrupt.h> 1862306a36Sopenharmony_ci#include <linux/io.h> 1962306a36Sopenharmony_ci#include <linux/memblock.h> 2062306a36Sopenharmony_ci#include <linux/serial.h> 2162306a36Sopenharmony_ci#include <linux/smp.h> 2262306a36Sopenharmony_ci#include <linux/types.h> 2362306a36Sopenharmony_ci#include <linux/string.h> /* for memset */ 2462306a36Sopenharmony_ci#include <linux/tty.h> 2562306a36Sopenharmony_ci#include <linux/time.h> 2662306a36Sopenharmony_ci#include <linux/platform_device.h> 2762306a36Sopenharmony_ci#include <linux/serial_core.h> 2862306a36Sopenharmony_ci#include <linux/serial_8250.h> 2962306a36Sopenharmony_ci#include <linux/of_fdt.h> 3062306a36Sopenharmony_ci#include <linux/libfdt.h> 3162306a36Sopenharmony_ci#include <linux/kexec.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <asm/processor.h> 3462306a36Sopenharmony_ci#include <asm/reboot.h> 3562306a36Sopenharmony_ci#include <asm/smp-ops.h> 3662306a36Sopenharmony_ci#include <asm/irq_cpu.h> 3762306a36Sopenharmony_ci#include <asm/mipsregs.h> 3862306a36Sopenharmony_ci#include <asm/bootinfo.h> 3962306a36Sopenharmony_ci#include <asm/sections.h> 4062306a36Sopenharmony_ci#include <asm/fw/fw.h> 4162306a36Sopenharmony_ci#include <asm/setup.h> 4262306a36Sopenharmony_ci#include <asm/prom.h> 4362306a36Sopenharmony_ci#include <asm/time.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include <asm/octeon/octeon.h> 4662306a36Sopenharmony_ci#include <asm/octeon/pci-octeon.h> 4762306a36Sopenharmony_ci#include <asm/octeon/cvmx-rst-defs.h> 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* 5062306a36Sopenharmony_ci * TRUE for devices having registers with little-endian byte 5162306a36Sopenharmony_ci * order, FALSE for registers with native-endian byte order. 5262306a36Sopenharmony_ci * PCI mandates little-endian, USB and SATA are configuraable, 5362306a36Sopenharmony_ci * but we chose little-endian for these. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ciconst bool octeon_should_swizzle_table[256] = { 5662306a36Sopenharmony_ci [0x00] = true, /* bootbus/CF */ 5762306a36Sopenharmony_ci [0x1b] = true, /* PCI mmio window */ 5862306a36Sopenharmony_ci [0x1c] = true, /* PCI mmio window */ 5962306a36Sopenharmony_ci [0x1d] = true, /* PCI mmio window */ 6062306a36Sopenharmony_ci [0x1e] = true, /* PCI mmio window */ 6162306a36Sopenharmony_ci [0x68] = true, /* OCTEON III USB */ 6262306a36Sopenharmony_ci [0x69] = true, /* OCTEON III USB */ 6362306a36Sopenharmony_ci [0x6c] = true, /* OCTEON III SATA */ 6462306a36Sopenharmony_ci [0x6f] = true, /* OCTEON II USB */ 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ciEXPORT_SYMBOL(octeon_should_swizzle_table); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#ifdef CONFIG_PCI 6962306a36Sopenharmony_ciextern void pci_console_init(const char *arg); 7062306a36Sopenharmony_ci#endif 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic unsigned long long max_memory = ULLONG_MAX; 7362306a36Sopenharmony_cistatic unsigned long long reserve_low_mem; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciDEFINE_SEMAPHORE(octeon_bootbus_sem, 1); 7662306a36Sopenharmony_ciEXPORT_SYMBOL(octeon_bootbus_sem); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic struct octeon_boot_descriptor *octeon_boot_desc_ptr; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistruct cvmx_bootinfo *octeon_bootinfo; 8162306a36Sopenharmony_ciEXPORT_SYMBOL(octeon_bootinfo); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#ifdef CONFIG_KEXEC 8462306a36Sopenharmony_ci#ifdef CONFIG_SMP 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * Wait for relocation code is prepared and send 8762306a36Sopenharmony_ci * secondary CPUs to spin until kernel is relocated. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cistatic void octeon_kexec_smp_down(void *ignored) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci int cpu = smp_processor_id(); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci local_irq_disable(); 9462306a36Sopenharmony_ci set_cpu_online(cpu, false); 9562306a36Sopenharmony_ci while (!atomic_read(&kexec_ready_to_reboot)) 9662306a36Sopenharmony_ci cpu_relax(); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci asm volatile ( 9962306a36Sopenharmony_ci " sync \n" 10062306a36Sopenharmony_ci " synci ($0) \n"); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci kexec_reboot(); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci#endif 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define OCTEON_DDR0_BASE (0x0ULL) 10762306a36Sopenharmony_ci#define OCTEON_DDR0_SIZE (0x010000000ULL) 10862306a36Sopenharmony_ci#define OCTEON_DDR1_BASE (0x410000000ULL) 10962306a36Sopenharmony_ci#define OCTEON_DDR1_SIZE (0x010000000ULL) 11062306a36Sopenharmony_ci#define OCTEON_DDR2_BASE (0x020000000ULL) 11162306a36Sopenharmony_ci#define OCTEON_DDR2_SIZE (0x3e0000000ULL) 11262306a36Sopenharmony_ci#define OCTEON_MAX_PHY_MEM_SIZE (16*1024*1024*1024ULL) 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic struct kimage *kimage_ptr; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void kexec_bootmem_init(uint64_t mem_size, uint32_t low_reserved_bytes) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci int64_t addr; 11962306a36Sopenharmony_ci struct cvmx_bootmem_desc *bootmem_desc; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci bootmem_desc = cvmx_bootmem_get_desc(); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (mem_size > OCTEON_MAX_PHY_MEM_SIZE) { 12462306a36Sopenharmony_ci mem_size = OCTEON_MAX_PHY_MEM_SIZE; 12562306a36Sopenharmony_ci pr_err("Error: requested memory too large," 12662306a36Sopenharmony_ci "truncating to maximum size\n"); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci bootmem_desc->major_version = CVMX_BOOTMEM_DESC_MAJ_VER; 13062306a36Sopenharmony_ci bootmem_desc->minor_version = CVMX_BOOTMEM_DESC_MIN_VER; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci addr = (OCTEON_DDR0_BASE + reserve_low_mem + low_reserved_bytes); 13362306a36Sopenharmony_ci bootmem_desc->head_addr = 0; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (mem_size <= OCTEON_DDR0_SIZE) { 13662306a36Sopenharmony_ci __cvmx_bootmem_phy_free(addr, 13762306a36Sopenharmony_ci mem_size - reserve_low_mem - 13862306a36Sopenharmony_ci low_reserved_bytes, 0); 13962306a36Sopenharmony_ci return; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci __cvmx_bootmem_phy_free(addr, 14362306a36Sopenharmony_ci OCTEON_DDR0_SIZE - reserve_low_mem - 14462306a36Sopenharmony_ci low_reserved_bytes, 0); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci mem_size -= OCTEON_DDR0_SIZE; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (mem_size > OCTEON_DDR1_SIZE) { 14962306a36Sopenharmony_ci __cvmx_bootmem_phy_free(OCTEON_DDR1_BASE, OCTEON_DDR1_SIZE, 0); 15062306a36Sopenharmony_ci __cvmx_bootmem_phy_free(OCTEON_DDR2_BASE, 15162306a36Sopenharmony_ci mem_size - OCTEON_DDR1_SIZE, 0); 15262306a36Sopenharmony_ci } else 15362306a36Sopenharmony_ci __cvmx_bootmem_phy_free(OCTEON_DDR1_BASE, mem_size, 0); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic int octeon_kexec_prepare(struct kimage *image) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci int i; 15962306a36Sopenharmony_ci char *bootloader = "kexec"; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci octeon_boot_desc_ptr->argc = 0; 16262306a36Sopenharmony_ci for (i = 0; i < image->nr_segments; i++) { 16362306a36Sopenharmony_ci if (!strncmp(bootloader, (char *)image->segment[i].buf, 16462306a36Sopenharmony_ci strlen(bootloader))) { 16562306a36Sopenharmony_ci /* 16662306a36Sopenharmony_ci * convert command line string to array 16762306a36Sopenharmony_ci * of parameters (as bootloader does). 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_ci int argc = 0, offt; 17062306a36Sopenharmony_ci char *str = (char *)image->segment[i].buf; 17162306a36Sopenharmony_ci char *ptr = strchr(str, ' '); 17262306a36Sopenharmony_ci while (ptr && (OCTEON_ARGV_MAX_ARGS > argc)) { 17362306a36Sopenharmony_ci *ptr = '\0'; 17462306a36Sopenharmony_ci if (ptr[1] != ' ') { 17562306a36Sopenharmony_ci offt = (int)(ptr - str + 1); 17662306a36Sopenharmony_ci octeon_boot_desc_ptr->argv[argc] = 17762306a36Sopenharmony_ci image->segment[i].mem + offt; 17862306a36Sopenharmony_ci argc++; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci ptr = strchr(ptr + 1, ' '); 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci octeon_boot_desc_ptr->argc = argc; 18362306a36Sopenharmony_ci break; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* 18862306a36Sopenharmony_ci * Information about segments will be needed during pre-boot memory 18962306a36Sopenharmony_ci * initialization. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ci kimage_ptr = image; 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic void octeon_generic_shutdown(void) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci int i; 19862306a36Sopenharmony_ci#ifdef CONFIG_SMP 19962306a36Sopenharmony_ci int cpu; 20062306a36Sopenharmony_ci#endif 20162306a36Sopenharmony_ci struct cvmx_bootmem_desc *bootmem_desc; 20262306a36Sopenharmony_ci void *named_block_array_ptr; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci bootmem_desc = cvmx_bootmem_get_desc(); 20562306a36Sopenharmony_ci named_block_array_ptr = 20662306a36Sopenharmony_ci cvmx_phys_to_ptr(bootmem_desc->named_block_array_addr); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#ifdef CONFIG_SMP 20962306a36Sopenharmony_ci /* disable watchdogs */ 21062306a36Sopenharmony_ci for_each_online_cpu(cpu) 21162306a36Sopenharmony_ci cvmx_write_csr(CVMX_CIU_WDOGX(cpu_logical_map(cpu)), 0); 21262306a36Sopenharmony_ci#else 21362306a36Sopenharmony_ci cvmx_write_csr(CVMX_CIU_WDOGX(cvmx_get_core_num()), 0); 21462306a36Sopenharmony_ci#endif 21562306a36Sopenharmony_ci if (kimage_ptr != kexec_crash_image) { 21662306a36Sopenharmony_ci memset(named_block_array_ptr, 21762306a36Sopenharmony_ci 0x0, 21862306a36Sopenharmony_ci CVMX_BOOTMEM_NUM_NAMED_BLOCKS * 21962306a36Sopenharmony_ci sizeof(struct cvmx_bootmem_named_block_desc)); 22062306a36Sopenharmony_ci /* 22162306a36Sopenharmony_ci * Mark all memory (except low 0x100000 bytes) as free. 22262306a36Sopenharmony_ci * It is the same thing that bootloader does. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ci kexec_bootmem_init(octeon_bootinfo->dram_size*1024ULL*1024ULL, 22562306a36Sopenharmony_ci 0x100000); 22662306a36Sopenharmony_ci /* 22762306a36Sopenharmony_ci * Allocate all segments to avoid their corruption during boot. 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_ci for (i = 0; i < kimage_ptr->nr_segments; i++) 23062306a36Sopenharmony_ci cvmx_bootmem_alloc_address( 23162306a36Sopenharmony_ci kimage_ptr->segment[i].memsz + 2*PAGE_SIZE, 23262306a36Sopenharmony_ci kimage_ptr->segment[i].mem - PAGE_SIZE, 23362306a36Sopenharmony_ci PAGE_SIZE); 23462306a36Sopenharmony_ci } else { 23562306a36Sopenharmony_ci /* 23662306a36Sopenharmony_ci * Do not mark all memory as free. Free only named sections 23762306a36Sopenharmony_ci * leaving the rest of memory unchanged. 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci struct cvmx_bootmem_named_block_desc *ptr = 24062306a36Sopenharmony_ci (struct cvmx_bootmem_named_block_desc *) 24162306a36Sopenharmony_ci named_block_array_ptr; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci for (i = 0; i < bootmem_desc->named_block_num_blocks; i++) 24462306a36Sopenharmony_ci if (ptr[i].size) 24562306a36Sopenharmony_ci cvmx_bootmem_free_named(ptr[i].name); 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci kexec_args[2] = 1UL; /* running on octeon_main_processor */ 24862306a36Sopenharmony_ci kexec_args[3] = (unsigned long)octeon_boot_desc_ptr; 24962306a36Sopenharmony_ci#ifdef CONFIG_SMP 25062306a36Sopenharmony_ci secondary_kexec_args[2] = 0UL; /* running on secondary cpu */ 25162306a36Sopenharmony_ci secondary_kexec_args[3] = (unsigned long)octeon_boot_desc_ptr; 25262306a36Sopenharmony_ci#endif 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic void octeon_shutdown(void) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci octeon_generic_shutdown(); 25862306a36Sopenharmony_ci#ifdef CONFIG_SMP 25962306a36Sopenharmony_ci smp_call_function(octeon_kexec_smp_down, NULL, 0); 26062306a36Sopenharmony_ci smp_wmb(); 26162306a36Sopenharmony_ci while (num_online_cpus() > 1) { 26262306a36Sopenharmony_ci cpu_relax(); 26362306a36Sopenharmony_ci mdelay(1); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci#endif 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic void octeon_crash_shutdown(struct pt_regs *regs) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci octeon_generic_shutdown(); 27162306a36Sopenharmony_ci default_machine_crash_shutdown(regs); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci#ifdef CONFIG_SMP 27562306a36Sopenharmony_civoid octeon_crash_smp_send_stop(void) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci int cpu; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* disable watchdogs */ 28062306a36Sopenharmony_ci for_each_online_cpu(cpu) 28162306a36Sopenharmony_ci cvmx_write_csr(CVMX_CIU_WDOGX(cpu_logical_map(cpu)), 0); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci#endif 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci#endif /* CONFIG_KEXEC */ 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ciuint64_t octeon_reserve32_memory; 28862306a36Sopenharmony_ciEXPORT_SYMBOL(octeon_reserve32_memory); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci#ifdef CONFIG_KEXEC 29162306a36Sopenharmony_ci/* crashkernel cmdline parameter is parsed _after_ memory setup 29262306a36Sopenharmony_ci * we also parse it here (workaround for EHB5200) */ 29362306a36Sopenharmony_cistatic uint64_t crashk_size, crashk_base; 29462306a36Sopenharmony_ci#endif 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic int octeon_uart; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ciextern asmlinkage void handle_int(void); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/** 30162306a36Sopenharmony_ci * octeon_is_simulation - Return non-zero if we are currently running 30262306a36Sopenharmony_ci * in the Octeon simulator 30362306a36Sopenharmony_ci * 30462306a36Sopenharmony_ci * Return: non-0 if running in the Octeon simulator, 0 otherwise 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ciint octeon_is_simulation(void) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci return octeon_bootinfo->board_type == CVMX_BOARD_TYPE_SIM; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ciEXPORT_SYMBOL(octeon_is_simulation); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci/** 31362306a36Sopenharmony_ci * octeon_is_pci_host - Return true if Octeon is in PCI Host mode. This means 31462306a36Sopenharmony_ci * Linux can control the PCI bus. 31562306a36Sopenharmony_ci * 31662306a36Sopenharmony_ci * Return: Non-zero if Octeon is in host mode. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ciint octeon_is_pci_host(void) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci#ifdef CONFIG_PCI 32162306a36Sopenharmony_ci return octeon_bootinfo->config_flags & CVMX_BOOTINFO_CFG_FLAG_PCI_HOST; 32262306a36Sopenharmony_ci#else 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci#endif 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci/** 32862306a36Sopenharmony_ci * octeon_get_clock_rate - Get the clock rate of Octeon 32962306a36Sopenharmony_ci * 33062306a36Sopenharmony_ci * Return: Clock rate in HZ 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ciuint64_t octeon_get_clock_rate(void) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct cvmx_sysinfo *sysinfo = cvmx_sysinfo_get(); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return sysinfo->cpu_clock_hz; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ciEXPORT_SYMBOL(octeon_get_clock_rate); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic u64 octeon_io_clock_rate; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ciu64 octeon_get_io_clock_rate(void) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci return octeon_io_clock_rate; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ciEXPORT_SYMBOL(octeon_get_io_clock_rate); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/** 35062306a36Sopenharmony_ci * octeon_write_lcd - Write to the LCD display connected to the bootbus. 35162306a36Sopenharmony_ci * @s: String to write 35262306a36Sopenharmony_ci * 35362306a36Sopenharmony_ci * This display exists on most Cavium evaluation boards. If it doesn't exist, 35462306a36Sopenharmony_ci * then this function doesn't do anything. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_cistatic void octeon_write_lcd(const char *s) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci if (octeon_bootinfo->led_display_base_addr) { 35962306a36Sopenharmony_ci void __iomem *lcd_address = 36062306a36Sopenharmony_ci ioremap(octeon_bootinfo->led_display_base_addr, 36162306a36Sopenharmony_ci 8); 36262306a36Sopenharmony_ci int i; 36362306a36Sopenharmony_ci for (i = 0; i < 8; i++, s++) { 36462306a36Sopenharmony_ci if (*s) 36562306a36Sopenharmony_ci iowrite8(*s, lcd_address + i); 36662306a36Sopenharmony_ci else 36762306a36Sopenharmony_ci iowrite8(' ', lcd_address + i); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci iounmap(lcd_address); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/** 37462306a36Sopenharmony_ci * octeon_get_boot_uart - Return the console uart passed by the bootloader 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * Return: uart number (0 or 1) 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_cistatic int octeon_get_boot_uart(void) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci return (octeon_boot_desc_ptr->flags & OCTEON_BL_FLAG_CONSOLE_UART1) ? 38162306a36Sopenharmony_ci 1 : 0; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci/** 38562306a36Sopenharmony_ci * octeon_get_boot_coremask - Get the coremask Linux was booted on. 38662306a36Sopenharmony_ci * 38762306a36Sopenharmony_ci * Return: Core mask 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ciint octeon_get_boot_coremask(void) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci return octeon_boot_desc_ptr->core_mask; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/** 39562306a36Sopenharmony_ci * octeon_check_cpu_bist - Check the hardware BIST results for a CPU 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_civoid octeon_check_cpu_bist(void) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci const int coreid = cvmx_get_core_num(); 40062306a36Sopenharmony_ci unsigned long long mask; 40162306a36Sopenharmony_ci unsigned long long bist_val; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Check BIST results for COP0 registers */ 40462306a36Sopenharmony_ci mask = 0x1f00000000ull; 40562306a36Sopenharmony_ci bist_val = read_octeon_c0_icacheerr(); 40662306a36Sopenharmony_ci if (bist_val & mask) 40762306a36Sopenharmony_ci pr_err("Core%d BIST Failure: CacheErr(icache) = 0x%llx\n", 40862306a36Sopenharmony_ci coreid, bist_val); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci bist_val = read_octeon_c0_dcacheerr(); 41162306a36Sopenharmony_ci if (bist_val & 1) 41262306a36Sopenharmony_ci pr_err("Core%d L1 Dcache parity error: " 41362306a36Sopenharmony_ci "CacheErr(dcache) = 0x%llx\n", 41462306a36Sopenharmony_ci coreid, bist_val); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci mask = 0xfc00000000000000ull; 41762306a36Sopenharmony_ci bist_val = read_c0_cvmmemctl(); 41862306a36Sopenharmony_ci if (bist_val & mask) 41962306a36Sopenharmony_ci pr_err("Core%d BIST Failure: COP0_CVM_MEM_CTL = 0x%llx\n", 42062306a36Sopenharmony_ci coreid, bist_val); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci write_octeon_c0_dcacheerr(0); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/** 42662306a36Sopenharmony_ci * octeon_restart - Reboot Octeon 42762306a36Sopenharmony_ci * 42862306a36Sopenharmony_ci * @command: Command to pass to the bootloader. Currently ignored. 42962306a36Sopenharmony_ci */ 43062306a36Sopenharmony_cistatic void octeon_restart(char *command) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci /* Disable all watchdogs before soft reset. They don't get cleared */ 43362306a36Sopenharmony_ci#ifdef CONFIG_SMP 43462306a36Sopenharmony_ci int cpu; 43562306a36Sopenharmony_ci for_each_online_cpu(cpu) 43662306a36Sopenharmony_ci cvmx_write_csr(CVMX_CIU_WDOGX(cpu_logical_map(cpu)), 0); 43762306a36Sopenharmony_ci#else 43862306a36Sopenharmony_ci cvmx_write_csr(CVMX_CIU_WDOGX(cvmx_get_core_num()), 0); 43962306a36Sopenharmony_ci#endif 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci mb(); 44262306a36Sopenharmony_ci while (1) 44362306a36Sopenharmony_ci if (OCTEON_IS_OCTEON3()) 44462306a36Sopenharmony_ci cvmx_write_csr(CVMX_RST_SOFT_RST, 1); 44562306a36Sopenharmony_ci else 44662306a36Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_RST, 1); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci/** 45162306a36Sopenharmony_ci * octeon_kill_core - Permanently stop a core. 45262306a36Sopenharmony_ci * 45362306a36Sopenharmony_ci * @arg: Ignored. 45462306a36Sopenharmony_ci */ 45562306a36Sopenharmony_cistatic void octeon_kill_core(void *arg) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci if (octeon_is_simulation()) 45862306a36Sopenharmony_ci /* A break instruction causes the simulator stop a core */ 45962306a36Sopenharmony_ci asm volatile ("break" ::: "memory"); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci local_irq_disable(); 46262306a36Sopenharmony_ci /* Disable watchdog on this core. */ 46362306a36Sopenharmony_ci cvmx_write_csr(CVMX_CIU_WDOGX(cvmx_get_core_num()), 0); 46462306a36Sopenharmony_ci /* Spin in a low power mode. */ 46562306a36Sopenharmony_ci while (true) 46662306a36Sopenharmony_ci asm volatile ("wait" ::: "memory"); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/** 47162306a36Sopenharmony_ci * octeon_halt - Halt the system 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_cistatic void octeon_halt(void) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci smp_call_function(octeon_kill_core, NULL, 0); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci switch (octeon_bootinfo->board_type) { 47862306a36Sopenharmony_ci case CVMX_BOARD_TYPE_NAO38: 47962306a36Sopenharmony_ci /* Driving a 1 to GPIO 12 shuts off this board */ 48062306a36Sopenharmony_ci cvmx_write_csr(CVMX_GPIO_BIT_CFGX(12), 1); 48162306a36Sopenharmony_ci cvmx_write_csr(CVMX_GPIO_TX_SET, 0x1000); 48262306a36Sopenharmony_ci break; 48362306a36Sopenharmony_ci default: 48462306a36Sopenharmony_ci octeon_write_lcd("PowerOff"); 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci octeon_kill_core(NULL); 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic char __read_mostly octeon_system_type[80]; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic void __init init_octeon_system_type(void) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci char const *board_type; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci board_type = cvmx_board_type_to_string(octeon_bootinfo->board_type); 49862306a36Sopenharmony_ci if (board_type == NULL) { 49962306a36Sopenharmony_ci struct device_node *root; 50062306a36Sopenharmony_ci int ret; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci root = of_find_node_by_path("/"); 50362306a36Sopenharmony_ci ret = of_property_read_string(root, "model", &board_type); 50462306a36Sopenharmony_ci of_node_put(root); 50562306a36Sopenharmony_ci if (ret) 50662306a36Sopenharmony_ci board_type = "Unsupported Board"; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci snprintf(octeon_system_type, sizeof(octeon_system_type), "%s (%s)", 51062306a36Sopenharmony_ci board_type, octeon_model_get_string(read_c0_prid())); 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci/** 51462306a36Sopenharmony_ci * octeon_board_type_string - Return a string representing the system type 51562306a36Sopenharmony_ci * 51662306a36Sopenharmony_ci * Return: system type string 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_ciconst char *octeon_board_type_string(void) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci return octeon_system_type; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ciconst char *get_system_type(void) 52462306a36Sopenharmony_ci __attribute__ ((alias("octeon_board_type_string"))); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_civoid octeon_user_io_init(void) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci union octeon_cvmemctl cvmmemctl; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* Get the current settings for CP0_CVMMEMCTL_REG */ 53162306a36Sopenharmony_ci cvmmemctl.u64 = read_c0_cvmmemctl(); 53262306a36Sopenharmony_ci /* R/W If set, marked write-buffer entries time out the same 53362306a36Sopenharmony_ci * as other entries; if clear, marked write-buffer entries 53462306a36Sopenharmony_ci * use the maximum timeout. */ 53562306a36Sopenharmony_ci cvmmemctl.s.dismarkwblongto = 1; 53662306a36Sopenharmony_ci /* R/W If set, a merged store does not clear the write-buffer 53762306a36Sopenharmony_ci * entry timeout state. */ 53862306a36Sopenharmony_ci cvmmemctl.s.dismrgclrwbto = 0; 53962306a36Sopenharmony_ci /* R/W Two bits that are the MSBs of the resultant CVMSEG LM 54062306a36Sopenharmony_ci * word location for an IOBDMA. The other 8 bits come from the 54162306a36Sopenharmony_ci * SCRADDR field of the IOBDMA. */ 54262306a36Sopenharmony_ci cvmmemctl.s.iobdmascrmsb = 0; 54362306a36Sopenharmony_ci /* R/W If set, SYNCWS and SYNCS only order marked stores; if 54462306a36Sopenharmony_ci * clear, SYNCWS and SYNCS only order unmarked 54562306a36Sopenharmony_ci * stores. SYNCWSMARKED has no effect when DISSYNCWS is 54662306a36Sopenharmony_ci * set. */ 54762306a36Sopenharmony_ci cvmmemctl.s.syncwsmarked = 0; 54862306a36Sopenharmony_ci /* R/W If set, SYNCWS acts as SYNCW and SYNCS acts as SYNC. */ 54962306a36Sopenharmony_ci cvmmemctl.s.dissyncws = 0; 55062306a36Sopenharmony_ci /* R/W If set, no stall happens on write buffer full. */ 55162306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2)) 55262306a36Sopenharmony_ci cvmmemctl.s.diswbfst = 1; 55362306a36Sopenharmony_ci else 55462306a36Sopenharmony_ci cvmmemctl.s.diswbfst = 0; 55562306a36Sopenharmony_ci /* R/W If set (and SX set), supervisor-level loads/stores can 55662306a36Sopenharmony_ci * use XKPHYS addresses with <48>==0 */ 55762306a36Sopenharmony_ci cvmmemctl.s.xkmemenas = 0; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* R/W If set (and UX set), user-level loads/stores can use 56062306a36Sopenharmony_ci * XKPHYS addresses with VA<48>==0 */ 56162306a36Sopenharmony_ci cvmmemctl.s.xkmemenau = 0; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* R/W If set (and SX set), supervisor-level loads/stores can 56462306a36Sopenharmony_ci * use XKPHYS addresses with VA<48>==1 */ 56562306a36Sopenharmony_ci cvmmemctl.s.xkioenas = 0; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* R/W If set (and UX set), user-level loads/stores can use 56862306a36Sopenharmony_ci * XKPHYS addresses with VA<48>==1 */ 56962306a36Sopenharmony_ci cvmmemctl.s.xkioenau = 0; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* R/W If set, all stores act as SYNCW (NOMERGE must be set 57262306a36Sopenharmony_ci * when this is set) RW, reset to 0. */ 57362306a36Sopenharmony_ci cvmmemctl.s.allsyncw = 0; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* R/W If set, no stores merge, and all stores reach the 57662306a36Sopenharmony_ci * coherent bus in order. */ 57762306a36Sopenharmony_ci cvmmemctl.s.nomerge = 0; 57862306a36Sopenharmony_ci /* R/W Selects the bit in the counter used for DID time-outs 0 57962306a36Sopenharmony_ci * = 231, 1 = 230, 2 = 229, 3 = 214. Actual time-out is 58062306a36Sopenharmony_ci * between 1x and 2x this interval. For example, with 58162306a36Sopenharmony_ci * DIDTTO=3, expiration interval is between 16K and 32K. */ 58262306a36Sopenharmony_ci cvmmemctl.s.didtto = 0; 58362306a36Sopenharmony_ci /* R/W If set, the (mem) CSR clock never turns off. */ 58462306a36Sopenharmony_ci cvmmemctl.s.csrckalwys = 0; 58562306a36Sopenharmony_ci /* R/W If set, mclk never turns off. */ 58662306a36Sopenharmony_ci cvmmemctl.s.mclkalwys = 0; 58762306a36Sopenharmony_ci /* R/W Selects the bit in the counter used for write buffer 58862306a36Sopenharmony_ci * flush time-outs (WBFLT+11) is the bit position in an 58962306a36Sopenharmony_ci * internal counter used to determine expiration. The write 59062306a36Sopenharmony_ci * buffer expires between 1x and 2x this interval. For 59162306a36Sopenharmony_ci * example, with WBFLT = 0, a write buffer expires between 2K 59262306a36Sopenharmony_ci * and 4K cycles after the write buffer entry is allocated. */ 59362306a36Sopenharmony_ci cvmmemctl.s.wbfltime = 0; 59462306a36Sopenharmony_ci /* R/W If set, do not put Istream in the L2 cache. */ 59562306a36Sopenharmony_ci cvmmemctl.s.istrnol2 = 0; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* 59862306a36Sopenharmony_ci * R/W The write buffer threshold. As per erratum Core-14752 59962306a36Sopenharmony_ci * for CN63XX, a sc/scd might fail if the write buffer is 60062306a36Sopenharmony_ci * full. Lowering WBTHRESH greatly lowers the chances of the 60162306a36Sopenharmony_ci * write buffer ever being full and triggering the erratum. 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)) 60462306a36Sopenharmony_ci cvmmemctl.s.wbthresh = 4; 60562306a36Sopenharmony_ci else 60662306a36Sopenharmony_ci cvmmemctl.s.wbthresh = 10; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* R/W If set, CVMSEG is available for loads/stores in 60962306a36Sopenharmony_ci * kernel/debug mode. */ 61062306a36Sopenharmony_ci#if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 61162306a36Sopenharmony_ci cvmmemctl.s.cvmsegenak = 1; 61262306a36Sopenharmony_ci#else 61362306a36Sopenharmony_ci cvmmemctl.s.cvmsegenak = 0; 61462306a36Sopenharmony_ci#endif 61562306a36Sopenharmony_ci /* R/W If set, CVMSEG is available for loads/stores in 61662306a36Sopenharmony_ci * supervisor mode. */ 61762306a36Sopenharmony_ci cvmmemctl.s.cvmsegenas = 0; 61862306a36Sopenharmony_ci /* R/W If set, CVMSEG is available for loads/stores in user 61962306a36Sopenharmony_ci * mode. */ 62062306a36Sopenharmony_ci cvmmemctl.s.cvmsegenau = 0; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci write_c0_cvmmemctl(cvmmemctl.u64); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* Setup of CVMSEG is done in kernel-entry-init.h */ 62562306a36Sopenharmony_ci if (smp_processor_id() == 0) 62662306a36Sopenharmony_ci pr_notice("CVMSEG size: %d cache lines (%d bytes)\n", 62762306a36Sopenharmony_ci CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE, 62862306a36Sopenharmony_ci CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (octeon_has_feature(OCTEON_FEATURE_FAU)) { 63162306a36Sopenharmony_ci union cvmx_iob_fau_timeout fau_timeout; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* Set a default for the hardware timeouts */ 63462306a36Sopenharmony_ci fau_timeout.u64 = 0; 63562306a36Sopenharmony_ci fau_timeout.s.tout_val = 0xfff; 63662306a36Sopenharmony_ci /* Disable tagwait FAU timeout */ 63762306a36Sopenharmony_ci fau_timeout.s.tout_enb = 0; 63862306a36Sopenharmony_ci cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_timeout.u64); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if ((!OCTEON_IS_MODEL(OCTEON_CN68XX) && 64262306a36Sopenharmony_ci !OCTEON_IS_MODEL(OCTEON_CN7XXX)) || 64362306a36Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN70XX)) { 64462306a36Sopenharmony_ci union cvmx_pow_nw_tim nm_tim; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci nm_tim.u64 = 0; 64762306a36Sopenharmony_ci /* 4096 cycles */ 64862306a36Sopenharmony_ci nm_tim.s.nw_tim = 3; 64962306a36Sopenharmony_ci cvmx_write_csr(CVMX_POW_NW_TIM, nm_tim.u64); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci write_octeon_c0_icacheerr(0); 65362306a36Sopenharmony_ci write_c0_derraddr1(0); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci/** 65762306a36Sopenharmony_ci * prom_init - Early entry point for arch setup 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_civoid __init prom_init(void) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct cvmx_sysinfo *sysinfo; 66262306a36Sopenharmony_ci const char *arg; 66362306a36Sopenharmony_ci char *p; 66462306a36Sopenharmony_ci int i; 66562306a36Sopenharmony_ci u64 t; 66662306a36Sopenharmony_ci int argc; 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * The bootloader passes a pointer to the boot descriptor in 66962306a36Sopenharmony_ci * $a3, this is available as fw_arg3. 67062306a36Sopenharmony_ci */ 67162306a36Sopenharmony_ci octeon_boot_desc_ptr = (struct octeon_boot_descriptor *)fw_arg3; 67262306a36Sopenharmony_ci octeon_bootinfo = 67362306a36Sopenharmony_ci cvmx_phys_to_ptr(octeon_boot_desc_ptr->cvmx_desc_vaddr); 67462306a36Sopenharmony_ci cvmx_bootmem_init(cvmx_phys_to_ptr(octeon_bootinfo->phy_mem_desc_addr)); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci sysinfo = cvmx_sysinfo_get(); 67762306a36Sopenharmony_ci memset(sysinfo, 0, sizeof(*sysinfo)); 67862306a36Sopenharmony_ci sysinfo->system_dram_size = octeon_bootinfo->dram_size << 20; 67962306a36Sopenharmony_ci sysinfo->phy_mem_desc_addr = (u64)phys_to_virt(octeon_bootinfo->phy_mem_desc_addr); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if ((octeon_bootinfo->major_version > 1) || 68262306a36Sopenharmony_ci (octeon_bootinfo->major_version == 1 && 68362306a36Sopenharmony_ci octeon_bootinfo->minor_version >= 4)) 68462306a36Sopenharmony_ci cvmx_coremask_copy(&sysinfo->core_mask, 68562306a36Sopenharmony_ci &octeon_bootinfo->ext_core_mask); 68662306a36Sopenharmony_ci else 68762306a36Sopenharmony_ci cvmx_coremask_set64(&sysinfo->core_mask, 68862306a36Sopenharmony_ci octeon_bootinfo->core_mask); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* Some broken u-boot pass garbage in upper bits, clear them out */ 69162306a36Sopenharmony_ci if (!OCTEON_IS_MODEL(OCTEON_CN78XX)) 69262306a36Sopenharmony_ci for (i = 512; i < 1024; i++) 69362306a36Sopenharmony_ci cvmx_coremask_clear_core(&sysinfo->core_mask, i); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci sysinfo->exception_base_addr = octeon_bootinfo->exception_base_addr; 69662306a36Sopenharmony_ci sysinfo->cpu_clock_hz = octeon_bootinfo->eclock_hz; 69762306a36Sopenharmony_ci sysinfo->dram_data_rate_hz = octeon_bootinfo->dclock_hz * 2; 69862306a36Sopenharmony_ci sysinfo->board_type = octeon_bootinfo->board_type; 69962306a36Sopenharmony_ci sysinfo->board_rev_major = octeon_bootinfo->board_rev_major; 70062306a36Sopenharmony_ci sysinfo->board_rev_minor = octeon_bootinfo->board_rev_minor; 70162306a36Sopenharmony_ci memcpy(sysinfo->mac_addr_base, octeon_bootinfo->mac_addr_base, 70262306a36Sopenharmony_ci sizeof(sysinfo->mac_addr_base)); 70362306a36Sopenharmony_ci sysinfo->mac_addr_count = octeon_bootinfo->mac_addr_count; 70462306a36Sopenharmony_ci memcpy(sysinfo->board_serial_number, 70562306a36Sopenharmony_ci octeon_bootinfo->board_serial_number, 70662306a36Sopenharmony_ci sizeof(sysinfo->board_serial_number)); 70762306a36Sopenharmony_ci sysinfo->compact_flash_common_base_addr = 70862306a36Sopenharmony_ci octeon_bootinfo->compact_flash_common_base_addr; 70962306a36Sopenharmony_ci sysinfo->compact_flash_attribute_base_addr = 71062306a36Sopenharmony_ci octeon_bootinfo->compact_flash_attribute_base_addr; 71162306a36Sopenharmony_ci sysinfo->led_display_base_addr = octeon_bootinfo->led_display_base_addr; 71262306a36Sopenharmony_ci sysinfo->dfa_ref_clock_hz = octeon_bootinfo->dfa_ref_clock_hz; 71362306a36Sopenharmony_ci sysinfo->bootloader_config_flags = octeon_bootinfo->config_flags; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (OCTEON_IS_OCTEON2()) { 71662306a36Sopenharmony_ci /* I/O clock runs at a different rate than the CPU. */ 71762306a36Sopenharmony_ci union cvmx_mio_rst_boot rst_boot; 71862306a36Sopenharmony_ci rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT); 71962306a36Sopenharmony_ci octeon_io_clock_rate = 50000000 * rst_boot.s.pnr_mul; 72062306a36Sopenharmony_ci } else if (OCTEON_IS_OCTEON3()) { 72162306a36Sopenharmony_ci /* I/O clock runs at a different rate than the CPU. */ 72262306a36Sopenharmony_ci union cvmx_rst_boot rst_boot; 72362306a36Sopenharmony_ci rst_boot.u64 = cvmx_read_csr(CVMX_RST_BOOT); 72462306a36Sopenharmony_ci octeon_io_clock_rate = 50000000 * rst_boot.s.pnr_mul; 72562306a36Sopenharmony_ci } else { 72662306a36Sopenharmony_ci octeon_io_clock_rate = sysinfo->cpu_clock_hz; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci t = read_c0_cvmctl(); 73062306a36Sopenharmony_ci if ((t & (1ull << 27)) == 0) { 73162306a36Sopenharmony_ci /* 73262306a36Sopenharmony_ci * Setup the multiplier save/restore code if 73362306a36Sopenharmony_ci * CvmCtl[NOMUL] clear. 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_ci void *save; 73662306a36Sopenharmony_ci void *save_end; 73762306a36Sopenharmony_ci void *restore; 73862306a36Sopenharmony_ci void *restore_end; 73962306a36Sopenharmony_ci int save_len; 74062306a36Sopenharmony_ci int restore_len; 74162306a36Sopenharmony_ci int save_max = (char *)octeon_mult_save_end - 74262306a36Sopenharmony_ci (char *)octeon_mult_save; 74362306a36Sopenharmony_ci int restore_max = (char *)octeon_mult_restore_end - 74462306a36Sopenharmony_ci (char *)octeon_mult_restore; 74562306a36Sopenharmony_ci if (current_cpu_data.cputype == CPU_CAVIUM_OCTEON3) { 74662306a36Sopenharmony_ci save = octeon_mult_save3; 74762306a36Sopenharmony_ci save_end = octeon_mult_save3_end; 74862306a36Sopenharmony_ci restore = octeon_mult_restore3; 74962306a36Sopenharmony_ci restore_end = octeon_mult_restore3_end; 75062306a36Sopenharmony_ci } else { 75162306a36Sopenharmony_ci save = octeon_mult_save2; 75262306a36Sopenharmony_ci save_end = octeon_mult_save2_end; 75362306a36Sopenharmony_ci restore = octeon_mult_restore2; 75462306a36Sopenharmony_ci restore_end = octeon_mult_restore2_end; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci save_len = (char *)save_end - (char *)save; 75762306a36Sopenharmony_ci restore_len = (char *)restore_end - (char *)restore; 75862306a36Sopenharmony_ci if (!WARN_ON(save_len > save_max || 75962306a36Sopenharmony_ci restore_len > restore_max)) { 76062306a36Sopenharmony_ci memcpy(octeon_mult_save, save, save_len); 76162306a36Sopenharmony_ci memcpy(octeon_mult_restore, restore, restore_len); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* 76662306a36Sopenharmony_ci * Only enable the LED controller if we're running on a CN38XX, CN58XX, 76762306a36Sopenharmony_ci * or CN56XX. The CN30XX and CN31XX don't have an LED controller. 76862306a36Sopenharmony_ci */ 76962306a36Sopenharmony_ci if (!octeon_is_simulation() && 77062306a36Sopenharmony_ci octeon_has_feature(OCTEON_FEATURE_LED_CONTROLLER)) { 77162306a36Sopenharmony_ci cvmx_write_csr(CVMX_LED_EN, 0); 77262306a36Sopenharmony_ci cvmx_write_csr(CVMX_LED_PRT, 0); 77362306a36Sopenharmony_ci cvmx_write_csr(CVMX_LED_DBG, 0); 77462306a36Sopenharmony_ci cvmx_write_csr(CVMX_LED_PRT_FMT, 0); 77562306a36Sopenharmony_ci cvmx_write_csr(CVMX_LED_UDD_CNTX(0), 32); 77662306a36Sopenharmony_ci cvmx_write_csr(CVMX_LED_UDD_CNTX(1), 32); 77762306a36Sopenharmony_ci cvmx_write_csr(CVMX_LED_UDD_DATX(0), 0); 77862306a36Sopenharmony_ci cvmx_write_csr(CVMX_LED_UDD_DATX(1), 0); 77962306a36Sopenharmony_ci cvmx_write_csr(CVMX_LED_EN, 1); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* 78362306a36Sopenharmony_ci * We need to temporarily allocate all memory in the reserve32 78462306a36Sopenharmony_ci * region. This makes sure the kernel doesn't allocate this 78562306a36Sopenharmony_ci * memory when it is getting memory from the 78662306a36Sopenharmony_ci * bootloader. Later, after the memory allocations are 78762306a36Sopenharmony_ci * complete, the reserve32 will be freed. 78862306a36Sopenharmony_ci * 78962306a36Sopenharmony_ci * Allocate memory for RESERVED32 aligned on 2MB boundary. This 79062306a36Sopenharmony_ci * is in case we later use hugetlb entries with it. 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_ci if (CONFIG_CAVIUM_RESERVE32) { 79362306a36Sopenharmony_ci int64_t addr = 79462306a36Sopenharmony_ci cvmx_bootmem_phy_named_block_alloc(CONFIG_CAVIUM_RESERVE32 << 20, 79562306a36Sopenharmony_ci 0, 0, 2 << 20, 79662306a36Sopenharmony_ci "CAVIUM_RESERVE32", 0); 79762306a36Sopenharmony_ci if (addr < 0) 79862306a36Sopenharmony_ci pr_err("Failed to allocate CAVIUM_RESERVE32 memory area\n"); 79962306a36Sopenharmony_ci else 80062306a36Sopenharmony_ci octeon_reserve32_memory = addr; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2 80462306a36Sopenharmony_ci if (cvmx_read_csr(CVMX_L2D_FUS3) & (3ull << 34)) { 80562306a36Sopenharmony_ci pr_info("Skipping L2 locking due to reduced L2 cache size\n"); 80662306a36Sopenharmony_ci } else { 80762306a36Sopenharmony_ci uint32_t __maybe_unused ebase = read_c0_ebase() & 0x3ffff000; 80862306a36Sopenharmony_ci#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2_TLB 80962306a36Sopenharmony_ci /* TLB refill */ 81062306a36Sopenharmony_ci cvmx_l2c_lock_mem_region(ebase, 0x100); 81162306a36Sopenharmony_ci#endif 81262306a36Sopenharmony_ci#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2_EXCEPTION 81362306a36Sopenharmony_ci /* General exception */ 81462306a36Sopenharmony_ci cvmx_l2c_lock_mem_region(ebase + 0x180, 0x80); 81562306a36Sopenharmony_ci#endif 81662306a36Sopenharmony_ci#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2_LOW_LEVEL_INTERRUPT 81762306a36Sopenharmony_ci /* Interrupt handler */ 81862306a36Sopenharmony_ci cvmx_l2c_lock_mem_region(ebase + 0x200, 0x80); 81962306a36Sopenharmony_ci#endif 82062306a36Sopenharmony_ci#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2_INTERRUPT 82162306a36Sopenharmony_ci cvmx_l2c_lock_mem_region(__pa_symbol(handle_int), 0x100); 82262306a36Sopenharmony_ci cvmx_l2c_lock_mem_region(__pa_symbol(plat_irq_dispatch), 0x80); 82362306a36Sopenharmony_ci#endif 82462306a36Sopenharmony_ci#ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2_MEMCPY 82562306a36Sopenharmony_ci cvmx_l2c_lock_mem_region(__pa_symbol(memcpy), 0x480); 82662306a36Sopenharmony_ci#endif 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci#endif 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci octeon_check_cpu_bist(); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci octeon_uart = octeon_get_boot_uart(); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci#ifdef CONFIG_SMP 83562306a36Sopenharmony_ci octeon_write_lcd("LinuxSMP"); 83662306a36Sopenharmony_ci#else 83762306a36Sopenharmony_ci octeon_write_lcd("Linux"); 83862306a36Sopenharmony_ci#endif 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci octeon_setup_delays(); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci /* 84362306a36Sopenharmony_ci * BIST should always be enabled when doing a soft reset. L2 84462306a36Sopenharmony_ci * Cache locking for instance is not cleared unless BIST is 84562306a36Sopenharmony_ci * enabled. Unfortunately due to a chip errata G-200 for 84662306a36Sopenharmony_ci * Cn38XX and CN31XX, BIST must be disabled on these parts. 84762306a36Sopenharmony_ci */ 84862306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2) || 84962306a36Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN31XX)) 85062306a36Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_BIST, 0); 85162306a36Sopenharmony_ci else 85262306a36Sopenharmony_ci cvmx_write_csr(CVMX_CIU_SOFT_BIST, 1); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* Default to 64MB in the simulator to speed things up */ 85562306a36Sopenharmony_ci if (octeon_is_simulation()) 85662306a36Sopenharmony_ci max_memory = 64ull << 20; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci arg = strstr(arcs_cmdline, "mem="); 85962306a36Sopenharmony_ci if (arg) { 86062306a36Sopenharmony_ci max_memory = memparse(arg + 4, &p); 86162306a36Sopenharmony_ci if (max_memory == 0) 86262306a36Sopenharmony_ci max_memory = 32ull << 30; 86362306a36Sopenharmony_ci if (*p == '@') 86462306a36Sopenharmony_ci reserve_low_mem = memparse(p + 1, &p); 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci arcs_cmdline[0] = 0; 86862306a36Sopenharmony_ci argc = octeon_boot_desc_ptr->argc; 86962306a36Sopenharmony_ci for (i = 0; i < argc; i++) { 87062306a36Sopenharmony_ci const char *arg = 87162306a36Sopenharmony_ci cvmx_phys_to_ptr(octeon_boot_desc_ptr->argv[i]); 87262306a36Sopenharmony_ci if ((strncmp(arg, "MEM=", 4) == 0) || 87362306a36Sopenharmony_ci (strncmp(arg, "mem=", 4) == 0)) { 87462306a36Sopenharmony_ci max_memory = memparse(arg + 4, &p); 87562306a36Sopenharmony_ci if (max_memory == 0) 87662306a36Sopenharmony_ci max_memory = 32ull << 30; 87762306a36Sopenharmony_ci if (*p == '@') 87862306a36Sopenharmony_ci reserve_low_mem = memparse(p + 1, &p); 87962306a36Sopenharmony_ci#ifdef CONFIG_KEXEC 88062306a36Sopenharmony_ci } else if (strncmp(arg, "crashkernel=", 12) == 0) { 88162306a36Sopenharmony_ci crashk_size = memparse(arg+12, &p); 88262306a36Sopenharmony_ci if (*p == '@') 88362306a36Sopenharmony_ci crashk_base = memparse(p+1, &p); 88462306a36Sopenharmony_ci strcat(arcs_cmdline, " "); 88562306a36Sopenharmony_ci strcat(arcs_cmdline, arg); 88662306a36Sopenharmony_ci /* 88762306a36Sopenharmony_ci * To do: switch parsing to new style, something like: 88862306a36Sopenharmony_ci * parse_crashkernel(arg, sysinfo->system_dram_size, 88962306a36Sopenharmony_ci * &crashk_size, &crashk_base); 89062306a36Sopenharmony_ci */ 89162306a36Sopenharmony_ci#endif 89262306a36Sopenharmony_ci } else if (strlen(arcs_cmdline) + strlen(arg) + 1 < 89362306a36Sopenharmony_ci sizeof(arcs_cmdline) - 1) { 89462306a36Sopenharmony_ci strcat(arcs_cmdline, " "); 89562306a36Sopenharmony_ci strcat(arcs_cmdline, arg); 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci if (strstr(arcs_cmdline, "console=") == NULL) { 90062306a36Sopenharmony_ci if (octeon_uart == 1) 90162306a36Sopenharmony_ci strcat(arcs_cmdline, " console=ttyS1,115200"); 90262306a36Sopenharmony_ci else 90362306a36Sopenharmony_ci strcat(arcs_cmdline, " console=ttyS0,115200"); 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci mips_hpt_frequency = octeon_get_clock_rate(); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci octeon_init_cvmcount(); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci _machine_restart = octeon_restart; 91162306a36Sopenharmony_ci _machine_halt = octeon_halt; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci#ifdef CONFIG_KEXEC 91462306a36Sopenharmony_ci _machine_kexec_shutdown = octeon_shutdown; 91562306a36Sopenharmony_ci _machine_crash_shutdown = octeon_crash_shutdown; 91662306a36Sopenharmony_ci _machine_kexec_prepare = octeon_kexec_prepare; 91762306a36Sopenharmony_ci#ifdef CONFIG_SMP 91862306a36Sopenharmony_ci _crash_smp_send_stop = octeon_crash_smp_send_stop; 91962306a36Sopenharmony_ci#endif 92062306a36Sopenharmony_ci#endif 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci octeon_user_io_init(); 92362306a36Sopenharmony_ci octeon_setup_smp(); 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci/* Exclude a single page from the regions obtained in plat_mem_setup. */ 92762306a36Sopenharmony_ci#ifndef CONFIG_CRASH_DUMP 92862306a36Sopenharmony_cistatic __init void memory_exclude_page(u64 addr, u64 *mem, u64 *size) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci if (addr > *mem && addr < *mem + *size) { 93162306a36Sopenharmony_ci u64 inc = addr - *mem; 93262306a36Sopenharmony_ci memblock_add(*mem, inc); 93362306a36Sopenharmony_ci *mem += inc; 93462306a36Sopenharmony_ci *size -= inc; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (addr == *mem && *size > PAGE_SIZE) { 93862306a36Sopenharmony_ci *mem += PAGE_SIZE; 93962306a36Sopenharmony_ci *size -= PAGE_SIZE; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci#endif /* CONFIG_CRASH_DUMP */ 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_civoid __init fw_init_cmdline(void) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci int i; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci octeon_boot_desc_ptr = (struct octeon_boot_descriptor *)fw_arg3; 94962306a36Sopenharmony_ci for (i = 0; i < octeon_boot_desc_ptr->argc; i++) { 95062306a36Sopenharmony_ci const char *arg = 95162306a36Sopenharmony_ci cvmx_phys_to_ptr(octeon_boot_desc_ptr->argv[i]); 95262306a36Sopenharmony_ci if (strlen(arcs_cmdline) + strlen(arg) + 1 < 95362306a36Sopenharmony_ci sizeof(arcs_cmdline) - 1) { 95462306a36Sopenharmony_ci strcat(arcs_cmdline, " "); 95562306a36Sopenharmony_ci strcat(arcs_cmdline, arg); 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_civoid __init *plat_get_fdt(void) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci octeon_bootinfo = 96362306a36Sopenharmony_ci cvmx_phys_to_ptr(octeon_boot_desc_ptr->cvmx_desc_vaddr); 96462306a36Sopenharmony_ci return phys_to_virt(octeon_bootinfo->fdt_addr); 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_civoid __init plat_mem_setup(void) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci uint64_t mem_alloc_size; 97062306a36Sopenharmony_ci uint64_t total; 97162306a36Sopenharmony_ci uint64_t crashk_end; 97262306a36Sopenharmony_ci#ifndef CONFIG_CRASH_DUMP 97362306a36Sopenharmony_ci int64_t memory; 97462306a36Sopenharmony_ci#endif 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci total = 0; 97762306a36Sopenharmony_ci crashk_end = 0; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci /* 98062306a36Sopenharmony_ci * The Mips memory init uses the first memory location for 98162306a36Sopenharmony_ci * some memory vectors. When SPARSEMEM is in use, it doesn't 98262306a36Sopenharmony_ci * verify that the size is big enough for the final 98362306a36Sopenharmony_ci * vectors. Making the smallest chuck 4MB seems to be enough 98462306a36Sopenharmony_ci * to consistently work. 98562306a36Sopenharmony_ci */ 98662306a36Sopenharmony_ci mem_alloc_size = 4 << 20; 98762306a36Sopenharmony_ci if (mem_alloc_size > max_memory) 98862306a36Sopenharmony_ci mem_alloc_size = max_memory; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci/* Crashkernel ignores bootmem list. It relies on mem=X@Y option */ 99162306a36Sopenharmony_ci#ifdef CONFIG_CRASH_DUMP 99262306a36Sopenharmony_ci memblock_add(reserve_low_mem, max_memory); 99362306a36Sopenharmony_ci total += max_memory; 99462306a36Sopenharmony_ci#else 99562306a36Sopenharmony_ci#ifdef CONFIG_KEXEC 99662306a36Sopenharmony_ci if (crashk_size > 0) { 99762306a36Sopenharmony_ci memblock_add(crashk_base, crashk_size); 99862306a36Sopenharmony_ci crashk_end = crashk_base + crashk_size; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci#endif 100162306a36Sopenharmony_ci /* 100262306a36Sopenharmony_ci * When allocating memory, we want incrementing addresses, 100362306a36Sopenharmony_ci * which is handled by memblock 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_ci cvmx_bootmem_lock(); 100662306a36Sopenharmony_ci while (total < max_memory) { 100762306a36Sopenharmony_ci memory = cvmx_bootmem_phy_alloc(mem_alloc_size, 100862306a36Sopenharmony_ci __pa_symbol(&_end), -1, 100962306a36Sopenharmony_ci 0x100000, 101062306a36Sopenharmony_ci CVMX_BOOTMEM_FLAG_NO_LOCKING); 101162306a36Sopenharmony_ci if (memory >= 0) { 101262306a36Sopenharmony_ci u64 size = mem_alloc_size; 101362306a36Sopenharmony_ci#ifdef CONFIG_KEXEC 101462306a36Sopenharmony_ci uint64_t end; 101562306a36Sopenharmony_ci#endif 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* 101862306a36Sopenharmony_ci * exclude a page at the beginning and end of 101962306a36Sopenharmony_ci * the 256MB PCIe 'hole' so the kernel will not 102062306a36Sopenharmony_ci * try to allocate multi-page buffers that 102162306a36Sopenharmony_ci * span the discontinuity. 102262306a36Sopenharmony_ci */ 102362306a36Sopenharmony_ci memory_exclude_page(CVMX_PCIE_BAR1_PHYS_BASE, 102462306a36Sopenharmony_ci &memory, &size); 102562306a36Sopenharmony_ci memory_exclude_page(CVMX_PCIE_BAR1_PHYS_BASE + 102662306a36Sopenharmony_ci CVMX_PCIE_BAR1_PHYS_SIZE, 102762306a36Sopenharmony_ci &memory, &size); 102862306a36Sopenharmony_ci#ifdef CONFIG_KEXEC 102962306a36Sopenharmony_ci end = memory + mem_alloc_size; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci /* 103262306a36Sopenharmony_ci * This function automatically merges address regions 103362306a36Sopenharmony_ci * next to each other if they are received in 103462306a36Sopenharmony_ci * incrementing order 103562306a36Sopenharmony_ci */ 103662306a36Sopenharmony_ci if (memory < crashk_base && end > crashk_end) { 103762306a36Sopenharmony_ci /* region is fully in */ 103862306a36Sopenharmony_ci memblock_add(memory, crashk_base - memory); 103962306a36Sopenharmony_ci total += crashk_base - memory; 104062306a36Sopenharmony_ci memblock_add(crashk_end, end - crashk_end); 104162306a36Sopenharmony_ci total += end - crashk_end; 104262306a36Sopenharmony_ci continue; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci if (memory >= crashk_base && end <= crashk_end) 104662306a36Sopenharmony_ci /* 104762306a36Sopenharmony_ci * Entire memory region is within the new 104862306a36Sopenharmony_ci * kernel's memory, ignore it. 104962306a36Sopenharmony_ci */ 105062306a36Sopenharmony_ci continue; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (memory > crashk_base && memory < crashk_end && 105362306a36Sopenharmony_ci end > crashk_end) { 105462306a36Sopenharmony_ci /* 105562306a36Sopenharmony_ci * Overlap with the beginning of the region, 105662306a36Sopenharmony_ci * reserve the beginning. 105762306a36Sopenharmony_ci */ 105862306a36Sopenharmony_ci mem_alloc_size -= crashk_end - memory; 105962306a36Sopenharmony_ci memory = crashk_end; 106062306a36Sopenharmony_ci } else if (memory < crashk_base && end > crashk_base && 106162306a36Sopenharmony_ci end < crashk_end) 106262306a36Sopenharmony_ci /* 106362306a36Sopenharmony_ci * Overlap with the beginning of the region, 106462306a36Sopenharmony_ci * chop of end. 106562306a36Sopenharmony_ci */ 106662306a36Sopenharmony_ci mem_alloc_size -= end - crashk_base; 106762306a36Sopenharmony_ci#endif 106862306a36Sopenharmony_ci memblock_add(memory, mem_alloc_size); 106962306a36Sopenharmony_ci total += mem_alloc_size; 107062306a36Sopenharmony_ci /* Recovering mem_alloc_size */ 107162306a36Sopenharmony_ci mem_alloc_size = 4 << 20; 107262306a36Sopenharmony_ci } else { 107362306a36Sopenharmony_ci break; 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci cvmx_bootmem_unlock(); 107762306a36Sopenharmony_ci#endif /* CONFIG_CRASH_DUMP */ 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* 108062306a36Sopenharmony_ci * Now that we've allocated the kernel memory it is safe to 108162306a36Sopenharmony_ci * free the reserved region. We free it here so that builtin 108262306a36Sopenharmony_ci * drivers can use the memory. 108362306a36Sopenharmony_ci */ 108462306a36Sopenharmony_ci if (octeon_reserve32_memory) 108562306a36Sopenharmony_ci cvmx_bootmem_free_named("CAVIUM_RESERVE32"); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (total == 0) 108862306a36Sopenharmony_ci panic("Unable to allocate memory from " 108962306a36Sopenharmony_ci "cvmx_bootmem_phy_alloc"); 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci/* 109362306a36Sopenharmony_ci * Emit one character to the boot UART. Exported for use by the 109462306a36Sopenharmony_ci * watchdog timer. 109562306a36Sopenharmony_ci */ 109662306a36Sopenharmony_civoid prom_putchar(char c) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci uint64_t lsrval; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci /* Spin until there is room */ 110162306a36Sopenharmony_ci do { 110262306a36Sopenharmony_ci lsrval = cvmx_read_csr(CVMX_MIO_UARTX_LSR(octeon_uart)); 110362306a36Sopenharmony_ci } while ((lsrval & 0x20) == 0); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* Write the byte */ 110662306a36Sopenharmony_ci cvmx_write_csr(CVMX_MIO_UARTX_THR(octeon_uart), c & 0xffull); 110762306a36Sopenharmony_ci} 110862306a36Sopenharmony_ciEXPORT_SYMBOL(prom_putchar); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_civoid __init prom_free_prom_memory(void) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { 111362306a36Sopenharmony_ci /* Check for presence of Core-14449 fix. */ 111462306a36Sopenharmony_ci u32 insn; 111562306a36Sopenharmony_ci u32 *foo; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci foo = &insn; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci asm volatile("# before" : : : "memory"); 112062306a36Sopenharmony_ci prefetch(foo); 112162306a36Sopenharmony_ci asm volatile( 112262306a36Sopenharmony_ci ".set push\n\t" 112362306a36Sopenharmony_ci ".set noreorder\n\t" 112462306a36Sopenharmony_ci "bal 1f\n\t" 112562306a36Sopenharmony_ci "nop\n" 112662306a36Sopenharmony_ci "1:\tlw %0,-12($31)\n\t" 112762306a36Sopenharmony_ci ".set pop\n\t" 112862306a36Sopenharmony_ci : "=r" (insn) : : "$31", "memory"); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci if ((insn >> 26) != 0x33) 113162306a36Sopenharmony_ci panic("No PREF instruction at Core-14449 probe point."); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci if (((insn >> 16) & 0x1f) != 28) 113462306a36Sopenharmony_ci panic("OCTEON II DCache prefetch workaround not in place (%04x).\n" 113562306a36Sopenharmony_ci "Please build kernel with proper options (CONFIG_CAVIUM_CN63XXP1).", 113662306a36Sopenharmony_ci insn); 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_civoid __init octeon_fill_mac_addresses(void); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_civoid __init device_tree_init(void) 114362306a36Sopenharmony_ci{ 114462306a36Sopenharmony_ci const void *fdt; 114562306a36Sopenharmony_ci bool do_prune; 114662306a36Sopenharmony_ci bool fill_mac; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci#ifdef CONFIG_MIPS_ELF_APPENDED_DTB 114962306a36Sopenharmony_ci if (!fdt_check_header(&__appended_dtb)) { 115062306a36Sopenharmony_ci fdt = &__appended_dtb; 115162306a36Sopenharmony_ci do_prune = false; 115262306a36Sopenharmony_ci fill_mac = true; 115362306a36Sopenharmony_ci pr_info("Using appended Device Tree.\n"); 115462306a36Sopenharmony_ci } else 115562306a36Sopenharmony_ci#endif 115662306a36Sopenharmony_ci if (octeon_bootinfo->minor_version >= 3 && octeon_bootinfo->fdt_addr) { 115762306a36Sopenharmony_ci fdt = phys_to_virt(octeon_bootinfo->fdt_addr); 115862306a36Sopenharmony_ci if (fdt_check_header(fdt)) 115962306a36Sopenharmony_ci panic("Corrupt Device Tree passed to kernel."); 116062306a36Sopenharmony_ci do_prune = false; 116162306a36Sopenharmony_ci fill_mac = false; 116262306a36Sopenharmony_ci pr_info("Using passed Device Tree.\n"); 116362306a36Sopenharmony_ci } else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { 116462306a36Sopenharmony_ci fdt = &__dtb_octeon_68xx_begin; 116562306a36Sopenharmony_ci do_prune = true; 116662306a36Sopenharmony_ci fill_mac = true; 116762306a36Sopenharmony_ci } else { 116862306a36Sopenharmony_ci fdt = &__dtb_octeon_3xxx_begin; 116962306a36Sopenharmony_ci do_prune = true; 117062306a36Sopenharmony_ci fill_mac = true; 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci initial_boot_params = (void *)fdt; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (do_prune) { 117662306a36Sopenharmony_ci octeon_prune_device_tree(); 117762306a36Sopenharmony_ci pr_info("Using internal Device Tree.\n"); 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci if (fill_mac) 118062306a36Sopenharmony_ci octeon_fill_mac_addresses(); 118162306a36Sopenharmony_ci unflatten_and_copy_device_tree(); 118262306a36Sopenharmony_ci init_octeon_system_type(); 118362306a36Sopenharmony_ci} 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cistatic int __initdata disable_octeon_edac_p; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_cistatic int __init disable_octeon_edac(char *str) 118862306a36Sopenharmony_ci{ 118962306a36Sopenharmony_ci disable_octeon_edac_p = 1; 119062306a36Sopenharmony_ci return 0; 119162306a36Sopenharmony_ci} 119262306a36Sopenharmony_ciearly_param("disable_octeon_edac", disable_octeon_edac); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_cistatic char *edac_device_names[] = { 119562306a36Sopenharmony_ci "octeon_l2c_edac", 119662306a36Sopenharmony_ci "octeon_pc_edac", 119762306a36Sopenharmony_ci}; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic int __init edac_devinit(void) 120062306a36Sopenharmony_ci{ 120162306a36Sopenharmony_ci struct platform_device *dev; 120262306a36Sopenharmony_ci int i, err = 0; 120362306a36Sopenharmony_ci int num_lmc; 120462306a36Sopenharmony_ci char *name; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci if (disable_octeon_edac_p) 120762306a36Sopenharmony_ci return 0; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(edac_device_names); i++) { 121062306a36Sopenharmony_ci name = edac_device_names[i]; 121162306a36Sopenharmony_ci dev = platform_device_register_simple(name, -1, NULL, 0); 121262306a36Sopenharmony_ci if (IS_ERR(dev)) { 121362306a36Sopenharmony_ci pr_err("Registration of %s failed!\n", name); 121462306a36Sopenharmony_ci err = PTR_ERR(dev); 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci num_lmc = OCTEON_IS_MODEL(OCTEON_CN68XX) ? 4 : 121962306a36Sopenharmony_ci (OCTEON_IS_MODEL(OCTEON_CN56XX) ? 2 : 1); 122062306a36Sopenharmony_ci for (i = 0; i < num_lmc; i++) { 122162306a36Sopenharmony_ci dev = platform_device_register_simple("octeon_lmc_edac", 122262306a36Sopenharmony_ci i, NULL, 0); 122362306a36Sopenharmony_ci if (IS_ERR(dev)) { 122462306a36Sopenharmony_ci pr_err("Registration of octeon_lmc_edac %d failed!\n", i); 122562306a36Sopenharmony_ci err = PTR_ERR(dev); 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci return err; 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_cidevice_initcall(edac_devinit); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_cistatic void __initdata *octeon_dummy_iospace; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic int __init octeon_no_pci_init(void) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci /* 123862306a36Sopenharmony_ci * Initially assume there is no PCI. The PCI/PCIe platform code will 123962306a36Sopenharmony_ci * later re-initialize these to correct values if they are present. 124062306a36Sopenharmony_ci */ 124162306a36Sopenharmony_ci octeon_dummy_iospace = vzalloc(IO_SPACE_LIMIT); 124262306a36Sopenharmony_ci set_io_port_base((unsigned long)octeon_dummy_iospace); 124362306a36Sopenharmony_ci ioport_resource.start = RESOURCE_SIZE_MAX; 124462306a36Sopenharmony_ci ioport_resource.end = 0; 124562306a36Sopenharmony_ci return 0; 124662306a36Sopenharmony_ci} 124762306a36Sopenharmony_cicore_initcall(octeon_no_pci_init); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_cistatic int __init octeon_no_pci_release(void) 125062306a36Sopenharmony_ci{ 125162306a36Sopenharmony_ci /* 125262306a36Sopenharmony_ci * Release the allocated memory if a real IO space is there. 125362306a36Sopenharmony_ci */ 125462306a36Sopenharmony_ci if ((unsigned long)octeon_dummy_iospace != mips_io_port_base) 125562306a36Sopenharmony_ci vfree(octeon_dummy_iospace); 125662306a36Sopenharmony_ci return 0; 125762306a36Sopenharmony_ci} 125862306a36Sopenharmony_cilate_initcall(octeon_no_pci_release); 1259