/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2004-2007 Cavium Networks
* Copyright (C) 2008, 2009 Wind River Systems
* written by Ralf Baechle <ralf@linux-mips.org>
*/
#include <linux/compiler.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/memblock.h>
#include <linux/serial.h>
#include <linux/smp.h>
#include <linux/types.h>
#include <linux/string.h> /* for memset */
#include <linux/tty.h>
#include <linux/time.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
#include <linux/kexec.h>
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/smp-ops.h>
#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
#include <asm/bootinfo.h>
#include <asm/sections.h>
#include <asm/fw/fw.h>
#include <asm/setup.h>
#include <asm/prom.h>
#include <asm/time.h>
#include <asm/octeon/octeon.h>
#include <asm/octeon/pci-octeon.h>
#include <asm/octeon/cvmx-rst-defs.h>
/*
* TRUE for devices having registers with little-endian byte
* order, FALSE for registers with native-endian byte order.
* PCI mandates little-endian, USB and SATA are configuraable,
* but we chose little-endian for these.
*/
const bool octeon_should_swizzle_table[256] = {
[0x00] = true, /* bootbus/CF */
[0x1b] = true, /* PCI mmio window */
[0x1c] = true, /* PCI mmio window */
[0x1d] = true, /* PCI mmio window */
[0x1e] = true, /* PCI mmio window */
[0x68] = true, /* OCTEON III USB */
[0x69] = true, /* OCTEON III USB */
[0x6c] = true, /* OCTEON III SATA */
[0x6f] = true, /* OCTEON II USB */
};
EXPORT_SYMBOL(octeon_should_swizzle_table);
#ifdef CONFIG_PCI
extern void pci_console_init(const char *arg);
#endif
static unsigned long long max_memory = ULLONG_MAX;
static unsigned long long reserve_low_mem;
DEFINE_SEMAPHORE(octeon_bootbus_sem, 1);
EXPORT_SYMBOL(octeon_bootbus_sem);
static struct octeon_boot_descriptor *octeon_boot_desc_ptr;
struct cvmx_bootinfo *octeon_bootinfo;
EXPORT_SYMBOL(octeon_bootinfo);
#ifdef CONFIG_KEXEC
#ifdef CONFIG_SMP
/*
* Wait for relocation code is prepared and send
* secondary CPUs to spin until kernel is relocated.
*/
static void octeon_kexec_smp_down(void *ignored)
{
int cpu = smp_processor_id();
local_irq_disable();
set_cpu_online(cpu, false);
while (!atomic_read(&kexec_ready_to_reboot))
cpu_relax();
asm volatile (
" sync \n"
" synci ($0) \n");
kexec_reboot();
}
#endif
#define OCTEON_DDR0_BASE (0x0ULL)
#define OCTEON_DDR0_SIZE (0x010000000ULL)
#define OCTEON_DDR1_BASE (0x410000000ULL)
#define OCTEON_DDR1_SIZE (0x010000000ULL)
#define OCTEON_DDR2_BASE (0x020000000ULL)
#define OCTEON_DDR2_SIZE (0x3e0000000ULL)
#define OCTEON_MAX_PHY_MEM_SIZE (16*1024*1024*1024ULL)
static struct kimage *kimage_ptr;
static void kexec_bootmem_init(uint64_t mem_size, uint32_t low_reserved_bytes)
{
int64_t addr;
struct cvmx_bootmem_desc *bootmem_desc;
bootmem_desc = cvmx_bootmem_get_desc();
if (mem_size > OCTEON_MAX_PHY_MEM_SIZE) {
mem_size = OCTEON_MAX_PHY_MEM_SIZE;
pr_err("Error: requested memory too large,"
"truncating to maximum size\n");
}
bootmem_desc->major_version = CVMX_BOOTMEM_DESC_MAJ_VER;
bootmem_desc->minor_version = CVMX_BOOTMEM_DESC_MIN_VER;
addr = (OCTEON_DDR0_BASE + reserve_low_mem + low_reserved_bytes);
bootmem_desc