diff options
Diffstat (limited to 'arch/mips/netlogic')
19 files changed, 1137 insertions, 452 deletions
diff --git a/arch/mips/netlogic/Kconfig b/arch/mips/netlogic/Kconfig index a5ca743613f..75bec44b585 100644 --- a/arch/mips/netlogic/Kconfig +++ b/arch/mips/netlogic/Kconfig @@ -1,5 +1,2 @@ config NLM_COMMON bool - -config NLM_XLR - bool diff --git a/arch/mips/netlogic/Makefile b/arch/mips/netlogic/Makefile new file mode 100644 index 00000000000..36d169b2ca6 --- /dev/null +++ b/arch/mips/netlogic/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_NLM_COMMON) += common/ +obj-$(CONFIG_CPU_XLR) += xlr/ +obj-$(CONFIG_CPU_XLP) += xlp/ diff --git a/arch/mips/netlogic/Platform b/arch/mips/netlogic/Platform index b648b487fd6..cdfc9abbbb7 100644 --- a/arch/mips/netlogic/Platform +++ b/arch/mips/netlogic/Platform @@ -1,16 +1,17 @@ # # NETLOGIC includes # -cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/mach-netlogic -cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/netlogic +cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/mach-netlogic +cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/netlogic # # use mips64 if xlr is not available # -cflags-$(CONFIG_NLM_XLR) += $(call cc-option,-march=xlr,-march=mips64) +cflags-$(CONFIG_CPU_XLR) += $(call cc-option,-march=xlr,-march=mips64) +cflags-$(CONFIG_CPU_XLP) += $(call cc-option,-march=xlp,-march=mips64r2) # -# NETLOGIC XLR/XLS SoC, Simulator and boards +# NETLOGIC processor support # -core-$(CONFIG_NLM_XLR) += arch/mips/netlogic/xlr/ -load-$(CONFIG_NLM_XLR_BOARD) += 0xffffffff84000000 +platform-$(CONFIG_NLM_COMMON) += netlogic/ +load-$(CONFIG_NLM_COMMON) += 0xffffffff80100000 diff --git a/arch/mips/netlogic/common/Makefile b/arch/mips/netlogic/common/Makefile new file mode 100644 index 00000000000..291372a086f --- /dev/null +++ b/arch/mips/netlogic/common/Makefile @@ -0,0 +1,3 @@ +obj-y += irq.o time.o +obj-$(CONFIG_SMP) += smp.o smpboot.o +obj-$(CONFIG_EARLY_PRINTK) += earlycons.o diff --git a/arch/mips/netlogic/xlr/xlr_console.c b/arch/mips/netlogic/common/earlycons.c index 759df069220..f193f7b3bd8 100644 --- a/arch/mips/netlogic/xlr/xlr_console.c +++ b/arch/mips/netlogic/common/earlycons.c @@ -33,14 +33,28 @@ */ #include <linux/types.h> +#include <linux/serial_reg.h> + +#include <asm/mipsregs.h> +#include <asm/netlogic/haldefs.h> + +#if defined(CONFIG_CPU_XLP) +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/uart.h> +#elif defined(CONFIG_CPU_XLR) #include <asm/netlogic/xlr/iomap.h> +#endif void prom_putchar(char c) { - nlm_reg_t *mmio; + uint64_t uartbase; - mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); - while (netlogic_read_reg(mmio, 0x5) == 0) +#if defined(CONFIG_CPU_XLP) + uartbase = nlm_get_uart_regbase(0, 0); +#elif defined(CONFIG_CPU_XLR) + uartbase = nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET); +#endif + while (nlm_read_reg(uartbase, UART_LSR) == 0) ; - netlogic_write_reg(mmio, 0x0, c); + nlm_write_reg(uartbase, UART_TX, c); } diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c new file mode 100644 index 00000000000..49a4f6cf71e --- /dev/null +++ b/arch/mips/netlogic/common/irq.c @@ -0,0 +1,238 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/linkage.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/irq.h> + +#include <asm/errno.h> +#include <asm/signal.h> +#include <asm/system.h> +#include <asm/ptrace.h> +#include <asm/mipsregs.h> +#include <asm/thread_info.h> + +#include <asm/netlogic/mips-extns.h> +#include <asm/netlogic/interrupt.h> +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> + +#if defined(CONFIG_CPU_XLP) +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/pic.h> +#elif defined(CONFIG_CPU_XLR) +#include <asm/netlogic/xlr/iomap.h> +#include <asm/netlogic/xlr/pic.h> +#else +#error "Unknown CPU" +#endif +/* + * These are the routines that handle all the low level interrupt stuff. + * Actions handled here are: initialization of the interrupt map, requesting of + * interrupt lines by handlers, dispatching if interrupts to handlers, probing + * for interrupt lines + */ + +/* Globals */ +static uint64_t nlm_irq_mask; +static DEFINE_SPINLOCK(nlm_pic_lock); + +static void xlp_pic_enable(struct irq_data *d) +{ + unsigned long flags; + int irt; + + irt = nlm_irq_to_irt(d->irq); + if (irt == -1) + return; + spin_lock_irqsave(&nlm_pic_lock, flags); + nlm_pic_enable_irt(nlm_pic_base, irt); + spin_unlock_irqrestore(&nlm_pic_lock, flags); +} + +static void xlp_pic_disable(struct irq_data *d) +{ + unsigned long flags; + int irt; + + irt = nlm_irq_to_irt(d->irq); + if (irt == -1) + return; + spin_lock_irqsave(&nlm_pic_lock, flags); + nlm_pic_disable_irt(nlm_pic_base, irt); + spin_unlock_irqrestore(&nlm_pic_lock, flags); +} + +static void xlp_pic_mask_ack(struct irq_data *d) +{ + uint64_t mask = 1ull << d->irq; + + write_c0_eirr(mask); /* ack by writing EIRR */ +} + +static void xlp_pic_unmask(struct irq_data *d) +{ + void *hd = irq_data_get_irq_handler_data(d); + int irt; + + irt = nlm_irq_to_irt(d->irq); + if (irt == -1) + return; + + if (hd) { + void (*extra_ack)(void *) = hd; + extra_ack(d); + } + /* Ack is a single write, no need to lock */ + nlm_pic_ack(nlm_pic_base, irt); +} + +static struct irq_chip xlp_pic = { + .name = "XLP-PIC", + .irq_enable = xlp_pic_enable, + .irq_disable = xlp_pic_disable, + .irq_mask_ack = xlp_pic_mask_ack, + .irq_unmask = xlp_pic_unmask, +}; + +static void cpuintr_disable(struct irq_data *d) +{ + uint64_t eimr; + uint64_t mask = 1ull << d->irq; + + eimr = read_c0_eimr(); + write_c0_eimr(eimr & ~mask); +} + +static void cpuintr_enable(struct irq_data *d) +{ + uint64_t eimr; + uint64_t mask = 1ull << d->irq; + + eimr = read_c0_eimr(); + write_c0_eimr(eimr | mask); +} + +static void cpuintr_ack(struct irq_data *d) +{ + uint64_t mask = 1ull << d->irq; + + write_c0_eirr(mask); +} + +static void cpuintr_nop(struct irq_data *d) +{ + WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq); +} + +/* + * Chip definition for CPU originated interrupts(timer, msg) and + * IPIs + */ +struct irq_chip nlm_cpu_intr = { + .name = "XLP-CPU-INTR", + .irq_enable = cpuintr_enable, + .irq_disable = cpuintr_disable, + .irq_mask = cpuintr_nop, + .irq_ack = cpuintr_nop, + .irq_eoi = cpuintr_ack, +}; + +void __init init_nlm_common_irqs(void) +{ + int i, irq, irt; + + for (i = 0; i < PIC_IRT_FIRST_IRQ; i++) + irq_set_chip_and_handler(i, &nlm_cpu_intr, handle_percpu_irq); + + for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ ; i++) + irq_set_chip_and_handler(i, &xlp_pic, handle_level_irq); + +#ifdef CONFIG_SMP + irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr, + nlm_smp_function_ipi_handler); + irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr, + nlm_smp_resched_ipi_handler); + nlm_irq_mask |= + ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE)); +#endif + + for (irq = PIC_IRT_FIRST_IRQ; irq <= PIC_IRT_LAST_IRQ; irq++) { + irt = nlm_irq_to_irt(irq); + if (irt == -1) + continue; + nlm_irq_mask |= (1ULL << irq); + nlm_pic_init_irt(nlm_pic_base, irt, irq, 0); + } + + nlm_irq_mask |= (1ULL << IRQ_TIMER); +} + +void __init arch_init_irq(void) +{ + /* Initialize the irq descriptors */ + init_nlm_common_irqs(); + + write_c0_eimr(nlm_irq_mask); +} + +void __cpuinit nlm_smp_irq_init(void) +{ + /* set interrupt mask for non-zero cpus */ + write_c0_eimr(nlm_irq_mask); +} + +asmlinkage void plat_irq_dispatch(void) +{ + uint64_t eirr; + int i; + + eirr = read_c0_eirr() & read_c0_eimr(); + if (eirr & (1 << IRQ_TIMER)) { + do_IRQ(IRQ_TIMER); + return; + } + + i = __ilog2_u64(eirr); + if (i == -1) + return; + + do_IRQ(i); +} diff --git a/arch/mips/netlogic/xlr/smp.c b/arch/mips/netlogic/common/smp.c index 080284ded50..db17f49886c 100644 --- a/arch/mips/netlogic/xlr/smp.c +++ b/arch/mips/netlogic/common/smp.c @@ -42,31 +42,29 @@ #include <asm/netlogic/interrupt.h> #include <asm/netlogic/mips-extns.h> - +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> + +#if defined(CONFIG_CPU_XLP) +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/pic.h> +#elif defined(CONFIG_CPU_XLR) #include <asm/netlogic/xlr/iomap.h> #include <asm/netlogic/xlr/pic.h> #include <asm/netlogic/xlr/xlr.h> +#else +#error "Unknown CPU" +#endif -void core_send_ipi(int logical_cpu, unsigned int action) +void nlm_send_ipi_single(int logical_cpu, unsigned int action) { int cpu = cpu_logical_map(logical_cpu); - u32 tid = cpu & 0x3; - u32 pid = (cpu >> 2) & 0x07; - u32 ipi = (tid << 16) | (pid << 20); if (action & SMP_CALL_FUNCTION) - ipi |= IRQ_IPI_SMP_FUNCTION; - else if (action & SMP_RESCHEDULE_YOURSELF) - ipi |= IRQ_IPI_SMP_RESCHEDULE; - else - return; - - pic_send_ipi(ipi); -} - -void nlm_send_ipi_single(int cpu, unsigned int action) -{ - core_send_ipi(cpu, action); + nlm_pic_send_ipi(nlm_pic_base, cpu, IRQ_IPI_SMP_FUNCTION, 0); + if (action & SMP_RESCHEDULE_YOURSELF) + nlm_pic_send_ipi(nlm_pic_base, cpu, IRQ_IPI_SMP_RESCHEDULE, 0); } void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) @@ -74,29 +72,35 @@ void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) int cpu; for_each_cpu(cpu, mask) { - core_send_ipi(cpu, action); + nlm_send_ipi_single(cpu, action); } } /* IRQ_IPI_SMP_FUNCTION Handler */ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) { + write_c0_eirr(1ull << irq); smp_call_function_interrupt(); } /* IRQ_IPI_SMP_RESCHEDULE handler */ void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) { + write_c0_eirr(1ull << irq); scheduler_ipi(); } /* * Called before going into mips code, early cpu init */ -void nlm_early_init_secondary(void) +void nlm_early_init_secondary(int cpu) { + change_c0_config(CONF_CM_CMASK, 0x3); write_c0_ebase((uint32_t)nlm_common_ebase); - /* TLB partition here later */ +#ifdef CONFIG_CPU_XLP + if (hard_smp_processor_id() % 4 == 0) + xlp_mmu_init(); +#endif } /* @@ -104,9 +108,16 @@ void nlm_early_init_secondary(void) */ static void __cpuinit nlm_init_secondary(void) { + current_cpu_data.core = hard_smp_processor_id() / 4; nlm_smp_irq_init(); } +void nlm_prepare_cpus(unsigned int max_cpus) +{ + /* declare we are SMT capable */ + smp_num_siblings = nlm_threads_per_core; +} + void nlm_smp_finish(void) { #ifdef notyet @@ -123,10 +134,10 @@ void nlm_cpus_done(void) * Boot all other cpus in the system, initialize them, and bring them into * the boot function */ -int nlm_cpu_unblock[NR_CPUS]; int nlm_cpu_ready[NR_CPUS]; unsigned long nlm_next_gp; unsigned long nlm_next_sp; + cpumask_t phys_cpu_present_map; void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) @@ -140,7 +151,7 @@ void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) /* barrier */ __sync(); - nlm_cpu_unblock[cpu] = 1; + nlm_pic_send_ipi(nlm_pic_base, cpu, 1, 1); } void __init nlm_smp_setup(void) @@ -159,8 +170,8 @@ void __init nlm_smp_setup(void) num_cpus = 1; for (i = 0; i < NR_CPUS; i++) { /* - * BSP is not set in nlm_cpu_ready array, it is only for - * ASPs (goto see smpboot.S) + * nlm_cpu_ready array is not set for the boot_cpu, + * it is only set for ASPs (see smpboot.S) */ if (nlm_cpu_ready[i]) { cpu_set(i, phys_cpu_present_map); @@ -176,10 +187,75 @@ void __init nlm_smp_setup(void) (unsigned long)cpu_possible_map.bits[0]); pr_info("Detected %i Slave CPU(s)\n", num_cpus); + nlm_set_nmi_handler(nlm_boot_secondary_cpus); } -void nlm_prepare_cpus(unsigned int max_cpus) +static int nlm_parse_cpumask(u32 cpu_mask) +{ + uint32_t core0_thr_mask, core_thr_mask; + int threadmode, i; + + core0_thr_mask = cpu_mask & 0xf; + switch (core0_thr_mask) { + case 1: + nlm_threads_per_core = 1; + threadmode = 0; + break; + case 3: + nlm_threads_per_core = 2; + threadmode = 2; + break; + case 0xf: + nlm_threads_per_core = 4; + threadmode = 3; + break; + default: + goto unsupp; + } + + /* Verify other cores CPU masks */ + nlm_coremask = 1; + nlm_cpumask = core0_thr_mask; + for (i = 1; i < 8; i++) { + core_thr_mask = (cpu_mask >> (i * 4)) & 0xf; + if (core_thr_mask) { + if (core_thr_mask != core0_thr_mask) + goto unsupp; + nlm_coremask |= 1 << i; + nlm_cpumask |= core0_thr_mask << (4 * i); + } + } + return threadmode; + +unsupp: + panic("Unsupported CPU mask %x\n", cpu_mask); + return 0; +} + +int __cpuinit nlm_wakeup_secondary_cpus(u32 wakeup_mask) { + unsigned long reset_vec; + char *reset_data; + int threadmode; + + /* Update reset entry point with CPU init code */ + reset_vec = CKSEG1ADDR(RESET_VEC_PHYS); + memcpy((void *)reset_vec, (void *)nlm_reset_entry, + (nlm_reset_entry_end - nlm_reset_entry)); + + /* verify the mask and setup core config variables */ + threadmode = nlm_parse_cpumask(wakeup_mask); + + /* Setup CPU init parameters */ + reset_data = (char *)CKSEG1ADDR(RESET_DATA_PHYS); + *(int *)(reset_data + BOOT_THREAD_MODE) = threadmode; + +#ifdef CONFIG_CPU_XLP + xlp_wakeup_secondary_cpus(); +#else + xlr_wakeup_secondary_cpus(); +#endif + return 0; } struct plat_smp_ops nlm_smp_ops = { @@ -192,29 +268,3 @@ struct plat_smp_ops nlm_smp_ops = { .smp_setup = nlm_smp_setup, .prepare_cpus = nlm_prepare_cpus, }; - -unsigned long secondary_entry_point; - -int __cpuinit nlm_wakeup_secondary_cpus(u32 wakeup_mask) -{ - unsigned int tid, pid, ipi, i, boot_cpu; - void *reset_vec; - - secondary_entry_point = (unsigned long)prom_pre_boot_secondary_cpus; - reset_vec = (void *)CKSEG1ADDR(0x1fc00000); - memcpy(reset_vec, nlm_boot_smp_nmi, 0x80); - boot_cpu = hard_smp_processor_id(); - - for (i = 0; i < NR_CPUS; i++) { - if (i == boot_cpu) - continue; - if (wakeup_mask & (1u << i)) { - tid = i & 0x3; - pid = (i >> 2) & 0x7; - ipi = (tid << 16) | (pid << 20) | (1 << 8); - pic_send_ipi(ipi); - } - } - - return 0; -} diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S new file mode 100644 index 00000000000..c138b1a6dec --- /dev/null +++ b/arch/mips/netlogic/common/smpboot.S @@ -0,0 +1,272 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/init.h> + +#include <asm/asm.h> +#include <asm/asm-offsets.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/stackframe.h> +#include <asm/asmmacro.h> +#include <asm/addrspace.h> + +#include <asm/netlogic/common.h> + +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/sys.h> +#include <asm/netlogic/xlp-hal/cpucontrol.h> + +#define CP0_EBASE $15 +#define SYS_CPU_COHERENT_BASE(node) CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \ + XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + \ + SYS_CPU_NONCOHERENT_MODE * 4 + +.macro __config_lsu + li t0, LSU_DEFEATURE + mfcr t1, t0 + + lui t2, 0x4080 /* Enable Unaligned Access, L2HPE */ + or t1, t1, t2 + li t2, ~0xe /* S1RCM */ + and t1, t1, t2 + mtcr t1, t0 + + li t0, SCHED_DEFEATURE + lui t1, 0x0100 /* Experimental: Disable BRU accepting ALU ops */ + mtcr t1, t0 +.endm + +/* + * The cores can come start when they are woken up. This is also the NMI + * entry, so check that first. + * + * The data corresponding to reset is stored at RESET_DATA_PHYS location, + * this will have the thread mask (used when core is woken up) and the + * current NMI handler in case we reached here for an NMI. + * + * When a core or thread is newly woken up, it loops in a 'wait'. When + * the CPU really needs waking up, we send an NMI to it, with the NMI + * handler set to prom_boot_secondary_cpus + */ + + .set noreorder + .set noat + .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ + +FEXPORT(nlm_reset_entry) + dmtc0 k0, $22, 6 + dmtc0 k1, $22, 7 + mfc0 k0, CP0_STATUS + li k1, 0x80000 + and k1, k0, k1 + beqz k1, 1f /* go to real reset entry */ + nop + li k1, CKSEG1ADDR(RESET_DATA_PHYS) /* NMI */ + ld k0, BOOT_NMI_HANDLER(k1) + jr k0 + nop + +1: /* Entry point on core wakeup */ + mfc0 t0, CP0_EBASE, 1 + mfc0 t1, CP0_EBASE, 1 + srl t1, 5 + andi t1, 0x3 /* t1 <- node */ + li t2, 0x40000 + mul t3, t2, t1 /* t3 = node * 0x40000 */ + srl t0, t0, 2 + and t0, t0, 0x7 /* t0 <- core */ + li t1, 0x1 + sll t0, t1, t0 + nor t0, t0, zero /* t0 <- ~(1 << core) */ + li t2, SYS_CPU_COHERENT_BASE(0) + add t2, t2, t3 /* t2 <- SYS offset for node */ + lw t1, 0(t2) + and t1, t1, t0 + sw t1, 0(t2) + + /* read back to ensure complete */ + lw t1, 0(t2) + sync + + /* Configure LSU on Non-0 Cores. */ + __config_lsu + +/* + * Wake up sibling threads from the initial thread in + * a core. + */ +EXPORT(nlm_boot_siblings) + li t0, CKSEG1ADDR(RESET_DATA_PHYS) + lw t1, BOOT_THREAD_MODE(t0) /* t1 <- thread mode */ + li t0, ((CPU_BLOCKID_MAP << 8) | MAP_THREADMODE) + mfcr t2, t0 + or t2, t2, t1 + mtcr t2, t0 + + /* + * The new hardware thread starts at the next instruction + * For all the cases other than core 0 thread 0, we will + * jump to the secondary wait function. + */ + mfc0 v0, CP0_EBASE, 1 + andi v0, 0x7f /* v0 <- node/core */ + +#if 1 + /* A0 errata - Write MMU_SETUP after changing thread mode register. */ + andi v1, v0, 0x3 /* v1 <- thread id */ + bnez v1, 2f + nop + + li t0, MMU_SETUP + li t1, 0 + mtcr t1, t0 + ehb +#endif + +2: beqz v0, 4f + nop + + /* setup status reg */ + mfc0 t1, CP0_STATUS + li t0, ST0_BEV + or t1, t0 + xor t1, t0 +#ifdef CONFIG_64BIT + ori t1, ST0_KX +#endif + mtc0 t1, CP0_STATUS + /* mark CPU ready */ + PTR_LA t1, nlm_cpu_ready + sll v1, v0, 2 + PTR_ADDU t1, v1 + li t2, 1 + sw t2, 0(t1) + /* Wait until NMI hits */ +3: wait + j 3b + nop + + /* + * For the boot CPU, we have to restore registers and + * return + */ +4: dmfc0 t0, $4, 2 /* restore SP from UserLocal */ + li t1, 0xfadebeef + dmtc0 t1, $4, 2 /* restore SP from UserLocal */ + PTR_SUBU sp, t0, PT_SIZE + RESTORE_ALL + jr ra + nop +EXPORT(nlm_reset_entry_end) + +FEXPORT(xlp_boot_core0_siblings) /* "Master" cpu starts from here */ + __config_lsu + dmtc0 sp, $4, 2 /* SP saved in UserLocal */ + SAVE_ALL + sync + /* find the location to which nlm_boot_siblings was relocated */ + li t0, CKSEG1ADDR(RESET_VEC_PHYS) + dla t1, nlm_reset_entry + dla t2, nlm_boot_siblings + dsubu t2, t1 + daddu t2, t0 + /* call it */ + jr t2 + nop + /* not reached */ + + __CPUINIT +NESTED(nlm_boot_secondary_cpus, 16, sp) + PTR_LA t1, nlm_next_sp + PTR_L sp, 0(t1) + PTR_LA t1, nlm_next_gp + PTR_L gp, 0(t1) + + /* a0 has the processor id */ + PTR_LA t0, nlm_early_init_secondary + jalr t0 + nop + + PTR_LA t0, smp_bootstrap + jr t0 + nop +END(nlm_boot_secondary_cpus) + __FINIT + +/* + * In case of RMIboot bootloader which is used on XLR boards, the CPUs + * be already woken up and waiting in bootloader code. + * This will get them out of the bootloader code and into linux. Needed + * because the bootloader area will be taken and initialized by linux. + */ + __CPUINIT +NESTED(nlm_rmiboot_preboot, 16, sp) + mfc0 t0, $15, 1 # read ebase + andi t0, 0x1f # t0 has the processor_id() + andi t2, t0, 0x3 # thread no + sll t0, 2 # offset in cpu array + + PTR_LA t1, nlm_cpu_ready # mark CPU ready + PTR_ADDU t1, t0 + li t3, 1 + sw t3, 0(t1) + + bnez t2, 1f # skip thread programming + nop # for non zero hw threads + + /* + * MMU setup only for first thread in core + */ + li t0, 0x400 + mfcr t1, t0 + li t2, 6 # XLR thread mode mask + nor t3, t2, zero + and t2, t1, t2 # t2 - current thread mode + li v0, CKSEG1ADDR(RESET_DATA_PHYS) + lw v1, BOOT_THREAD_MODE(v0) # v1 - new thread mode + sll v1, 1 + beq v1, t2, 1f # same as request value + nop # nothing to do */ + + and t2, t1, t3 # mask out old thread mode + or t1, t2, v1 # put in new value + mtcr t1, t0 # update core control + +1: wait + j 1b + nop +END(nlm_rmiboot_preboot) + __FINIT diff --git a/arch/mips/netlogic/xlr/time.c b/arch/mips/netlogic/common/time.c index 0d81b262593..bd3e498157f 100644 --- a/arch/mips/netlogic/xlr/time.c +++ b/arch/mips/netlogic/common/time.c @@ -36,7 +36,7 @@ #include <asm/time.h> #include <asm/netlogic/interrupt.h> -#include <asm/netlogic/psb-bootinfo.h> +#include <asm/netlogic/common.h> unsigned int __cpuinit get_c0_compare_int(void) { @@ -45,7 +45,7 @@ unsigned int __cpuinit get_c0_compare_int(void) void __init plat_time_init(void) { - mips_hpt_frequency = nlm_prom_info.cpu_frequency; + mips_hpt_frequency = nlm_get_cpu_frequency(); pr_info("MIPS counter frequency [%ld]\n", - (unsigned long)mips_hpt_frequency); + (unsigned long)mips_hpt_frequency); } diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile new file mode 100644 index 00000000000..b93ed83474e --- /dev/null +++ b/arch/mips/netlogic/xlp/Makefile @@ -0,0 +1,2 @@ +obj-y += setup.o platform.o nlm_hal.o +obj-$(CONFIG_SMP) += wakeup.o diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c new file mode 100644 index 00000000000..9428e7125fe --- /dev/null +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -0,0 +1,111 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/delay.h> + +#include <asm/mipsregs.h> +#include <asm/time.h> + +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/pic.h> +#include <asm/netlogic/xlp-hal/sys.h> + +/* These addresses are computed by the nlm_hal_init() */ +uint64_t nlm_io_base; +uint64_t nlm_sys_base; +uint64_t nlm_pic_base; + +/* Main initialization */ +void nlm_hal_init(void) +{ + nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE); + nlm_sys_base = nlm_get_sys_regbase(0); /* node 0 */ + nlm_pic_base = nlm_get_pic_regbase(0); /* node 0 */ +} + +int nlm_irq_to_irt(int irq) +{ + if (!PIC_IRQ_IS_IRT(irq)) + return -1; + + switch (irq) { + case PIC_UART_0_IRQ: + return PIC_IRT_UART_0_INDEX; + case PIC_UART_1_IRQ: + return PIC_IRT_UART_1_INDEX; + default: + return -1; + } +} + +int nlm_irt_to_irq(int irt) +{ + switch (irt) { + case PIC_IRT_UART_0_INDEX: + return PIC_UART_0_IRQ; + case PIC_IRT_UART_1_INDEX: + return PIC_UART_1_IRQ; + default: + return -1; + } +} + +unsigned int nlm_get_core_frequency(int core) +{ + unsigned int pll_divf, pll_divr, dfs_div, ext_div; + unsigned int rstval, dfsval, denom; + uint64_t num; + + rstval = nlm_read_sys_reg(nlm_sys_base, SYS_POWER_ON_RESET_CFG); + dfsval = nlm_read_sys_reg(nlm_sys_base, SYS_CORE_DFS_DIV_VALUE); + pll_divf = ((rstval >> 10) & 0x7f) + 1; + pll_divr = ((rstval >> 8) & 0x3) + 1; + ext_div = ((rstval >> 30) & 0x3) + 1; + dfs_div = ((dfsval >> (core * 4)) & 0xf) + 1; + + num = 800000000ULL * pll_divf; + denom = 3 * pll_divr * ext_div * dfs_div; + do_div(num, denom); + return (unsigned int)num; +} + +unsigned int nlm_get_cpu_frequency(void) +{ + return nlm_get_core_frequency(0); +} diff --git a/arch/mips/netlogic/xlp/platform.c b/arch/mips/netlogic/xlp/platform.c new file mode 100644 index 00000000000..1f5e4cba891 --- /dev/null +++ b/arch/mips/netlogic/xlp/platform.c @@ -0,0 +1,108 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/dma-mapping.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_8250.h> +#include <linux/pci.h> +#include <linux/serial_reg.h> +#include <linux/spinlock.h> + +#include <asm/time.h> +#include <asm/addrspace.h> +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/pic.h> +#include <asm/netlogic/xlp-hal/uart.h> + +static unsigned int nlm_xlp_uart_in(struct uart_port *p, int offset) +{ + return nlm_read_reg(p->iobase, offset); +} + +static void nlm_xlp_uart_out(struct uart_port *p, int offset, int value) +{ + nlm_write_reg(p->iobase, offset, value); +} + +#define PORT(_irq) \ + { \ + .irq = _irq, \ + .regshift = 2, \ + .iotype = UPIO_MEM32, \ + .flags = (UPF_SKIP_TEST|UPF_FIXED_TYPE|\ + UPF_BOOT_AUTOCONF), \ + .uartclk = XLP_IO_CLK, \ + .type = PORT_16550A, \ + .serial_in = nlm_xlp_uart_in, \ + .serial_out = nlm_xlp_uart_out, \ + } + +static struct plat_serial8250_port xlp_uart_data[] = { + PORT(PIC_UART_0_IRQ), + PORT(PIC_UART_1_IRQ), + {}, +}; + +static struct platform_device uart_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = xlp_uart_data, + }, +}; + +static int __init nlm_platform_uart_init(void) +{ + unsigned long mmio; + + mmio = (unsigned long)nlm_get_uart_regbase(0, 0); + xlp_uart_data[0].iobase = mmio; + xlp_uart_data[0].membase = (void __iomem *)mmio; + xlp_uart_data[0].mapbase = mmio; + + mmio = (unsigned long)nlm_get_uart_regbase(0, 1); + xlp_uart_data[1].iobase = mmio; + xlp_uart_data[1].membase = (void __iomem *)mmio; + xlp_uart_data[1].mapbase = mmio; + + return platform_device_register(&uart_device); +} + +arch_initcall(nlm_platform_uart_init); diff --git a/arch/mips/netlogic/xlp/setup.c b/arch/mips/netlogic/xlp/setup.c new file mode 100644 index 00000000000..acb677a1227 --- /dev/null +++ b/arch/mips/netlogic/xlp/setup.c @@ -0,0 +1,105 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/kernel.h> +#include <linux/serial_8250.h> +#include <linux/pm.h> + +#include <asm/reboot.h> +#include <asm/time.h> +#include <asm/bootinfo.h> + +#include <linux/of_fdt.h> + +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> + +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/sys.h> + +unsigned long nlm_common_ebase = 0x0; + +/* default to uniprocessor */ +uint32_t nlm_coremask = 1, nlm_cpumask = 1; +int nlm_threads_per_core = 1; + +static void nlm_linux_exit(void) +{ + nlm_write_sys_reg(nlm_sys_base, SYS_CHIP_RESET, 1); + for ( ; ; ) + cpu_wait(); +} + +void __init plat_mem_setup(void) +{ + panic_timeout = 5; + _machine_restart = (void (*)(char *))nlm_linux_exit; + _machine_halt = nlm_linux_exit; + pm_power_off = nlm_linux_exit; +} + +const char *get_system_type(void) +{ + return "Netlogic XLP Series"; +} + +void __init prom_free_prom_memory(void) +{ + /* Nothing yet */ +} + +void xlp_mmu_init(void) +{ + write_c0_config6(read_c0_config6() | 0x24); + current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1; + write_c0_config7(PM_DEFAULT_MASK >> + (13 + (ffz(PM_DEFAULT_MASK >> 13) / 2))); +} + +void __init prom_init(void) +{ + void *fdtp; + + fdtp = (void *)(long)fw_arg0; + xlp_mmu_init(); + nlm_hal_init(); + early_init_devtree(fdtp); + + nlm_common_ebase = read_c0_ebase() & (~((1 << 12) - 1)); +#ifdef CONFIG_SMP + nlm_wakeup_secondary_cpus(0xffffffff); + register_smp_ops(&nlm_smp_ops); +#endif +} diff --git a/arch/mips/netlogic/xlp/wakeup.c b/arch/mips/netlogic/xlp/wakeup.c new file mode 100644 index 00000000000..44d923ff384 --- /dev/null +++ b/arch/mips/netlogic/xlp/wakeup.c @@ -0,0 +1,102 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/threads.h> + +#include <asm/asm.h> +#include <asm/asm-offsets.h> +#include <asm/mipsregs.h> +#include <asm/addrspace.h> +#include <asm/string.h> + +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> +#include <asm/netlogic/mips-extns.h> + +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/pic.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/sys.h> + +static void xlp_enable_secondary_cores(void) +{ + uint32_t core, value, coremask, syscoremask; + int count; + + /* read cores in reset from SYS block */ + syscoremask = nlm_read_sys_reg(nlm_sys_base, SYS_CPU_RESET); + + /* update user specified */ + nlm_coremask = nlm_coremask & (syscoremask | 1); + + for (core = 1; core < 8; core++) { + coremask = 1 << core; + if ((nlm_coremask & coremask) == 0) + continue; + + /* Enable CPU clock */ + value = nlm_read_sys_reg(nlm_sys_base, SYS_CORE_DFS_DIS_CTRL); + value &= ~coremask; + nlm_write_sys_reg(nlm_sys_base, SYS_CORE_DFS_DIS_CTRL, value); + + /* Remove CPU Reset */ + value = nlm_read_sys_reg(nlm_sys_base, SYS_CPU_RESET); + value &= ~coremask; + nlm_write_sys_reg(nlm_sys_base, SYS_CPU_RESET, value); + + /* Poll for CPU to mark itself coherent */ + count = 100000; + do { + value = nlm_read_sys_reg(nlm_sys_base, + SYS_CPU_NONCOHERENT_MODE); + } while ((value & coremask) != 0 && count-- > 0); + + if (count == 0) + pr_err("Failed to enable core %d\n", core); + } +} + +void xlp_wakeup_secondary_cpus(void) +{ + /* + * In case of u-boot, the secondaries are in reset + * first wakeup core 0 threads + */ + xlp_boot_core0_siblings(); + + /* now get other cores out of reset */ + xlp_enable_secondary_cores(); +} diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile index 2dca585dd2f..f01e4d7a060 100644 --- a/arch/mips/netlogic/xlr/Makefile +++ b/arch/mips/netlogic/xlr/Makefile @@ -1,5 +1,2 @@ -obj-y += setup.o platform.o irq.o setup.o time.o -obj-$(CONFIG_SMP) += smp.o smpboot.o -obj-$(CONFIG_EARLY_PRINTK) += xlr_console.o - -ccflags-y += -Werror +obj-y += setup.o platform.o +obj-$(CONFIG_SMP) += wakeup.o diff --git a/arch/mips/netlogic/xlr/irq.c b/arch/mips/netlogic/xlr/irq.c deleted file mode 100644 index 521bb7377eb..00000000000 --- a/arch/mips/netlogic/xlr/irq.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights - * reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the NetLogic - * license below: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/linkage.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/mm.h> - -#include <asm/mipsregs.h> - -#include <asm/netlogic/xlr/iomap.h> -#include <asm/netlogic/xlr/pic.h> -#include <asm/netlogic/xlr/xlr.h> - -#include <asm/netlogic/interrupt.h> -#include <asm/netlogic/mips-extns.h> - -static u64 nlm_irq_mask; -static DEFINE_SPINLOCK(nlm_pic_lock); - -static void xlr_pic_enable(struct irq_data *d) -{ - nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); - unsigned long flags; - nlm_reg_t reg; - int irq = d->irq; - - WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); - - spin_lock_irqsave(&nlm_pic_lock, flags); - reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE); - netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE, - reg | (1 << 6) | (1 << 30) | (1 << 31)); - spin_unlock_irqrestore(&nlm_pic_lock, flags); -} - -static void xlr_pic_mask(struct irq_data *d) -{ - nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); - unsigned long flags; - nlm_reg_t reg; - int irq = d->irq; - - WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); - - spin_lock_irqsave(&nlm_pic_lock, flags); - reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE); - netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE, - reg | (1 << 6) | (1 << 30) | (0 << 31)); - spin_unlock_irqrestore(&nlm_pic_lock, flags); -} - -#ifdef CONFIG_PCI -/* Extra ACK needed for XLR on chip PCI controller */ -static void xlr_pci_ack(struct irq_data *d) -{ - nlm_reg_t *pci_mmio = netlogic_io_mmio(NETLOGIC_IO_PCIX_OFFSET); - - netlogic_read_reg(pci_mmio, (0x140 >> 2)); -} - -/* Extra ACK needed for XLS on chip PCIe controller */ -static void xls_pcie_ack(struct irq_data *d) -{ - nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET); - - switch (d->irq) { - case PIC_PCIE_LINK0_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff); - break; - case PIC_PCIE_LINK1_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff); - break; - case PIC_PCIE_LINK2_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff); - break; - case PIC_PCIE_LINK3_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff); - break; - } -} - -/* For XLS B silicon, the 3,4 PCI interrupts are different */ -static void xls_pcie_ack_b(struct irq_data *d) -{ - nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET); - - switch (d->irq) { - case PIC_PCIE_LINK0_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff); - break; - case PIC_PCIE_LINK1_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff); - break; - case PIC_PCIE_XLSB0_LINK2_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff); - break; - case PIC_PCIE_XLSB0_LINK3_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff); - break; - } -} -#endif - -static void xlr_pic_ack(struct irq_data *d) -{ - unsigned long flags; - nlm_reg_t *mmio; - int irq = d->irq; - void *hd = irq_data_get_irq_handler_data(d); - - WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); - - if (hd) { - void (*extra_ack)(void *) = hd; - extra_ack(d); - } - mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); - spin_lock_irqsave(&nlm_pic_lock, flags); - netlogic_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE))); - spin_unlock_irqrestore(&nlm_pic_lock, flags); -} - -/* - * This chip definition handles interrupts routed thru the XLR - * hardware PIC, currently IRQs 8-39 are mapped to hardware intr - * 0-31 wired the XLR PIC - */ -static struct irq_chip xlr_pic = { - .name = "XLR-PIC", - .irq_enable = xlr_pic_enable, - .irq_mask = xlr_pic_mask, - .irq_ack = xlr_pic_ack, -}; - -static void rsvd_irq_handler(struct irq_data *d) -{ - WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq); -} - -/* - * Chip definition for CPU originated interrupts(timer, msg) and - * IPIs - */ -struct irq_chip nlm_cpu_intr = { - .name = "XLR-CPU-INTR", - .irq_enable = rsvd_irq_handler, - .irq_mask = rsvd_irq_handler, - .irq_ack = rsvd_irq_handler, -}; - -void __init init_xlr_irqs(void) -{ - nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); - uint32_t thread_mask = 1; - int level, i; - - pr_info("Interrupt thread mask [%x]\n", thread_mask); - for (i = 0; i < PIC_NUM_IRTS; i++) { - level = PIC_IRQ_IS_EDGE_TRIGGERED(i); - - /* Bind all PIC irqs to boot cpu */ - netlogic_write_reg(mmio, PIC_IRT_0_BASE + i, thread_mask); - - /* - * Use local scheduling and high polarity for all IRTs - * Invalidate all IRTs, by default - */ - netlogic_write_reg(mmio, PIC_IRT_1_BASE + i, - (level << 30) | (1 << 6) | (PIC_IRQ_BASE + i)); - } - - /* Make all IRQs as level triggered by default */ - for (i = 0; i < NR_IRQS; i++) { - if (PIC_IRQ_IS_IRT(i)) - irq_set_chip_and_handler(i, &xlr_pic, handle_level_irq); - else - irq_set_chip_and_handler(i, &nlm_cpu_intr, - handle_percpu_irq); - } -#ifdef CONFIG_SMP - irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr, - nlm_smp_function_ipi_handler); - irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr, - nlm_smp_resched_ipi_handler); - nlm_irq_mask |= - ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE)); -#endif - -#ifdef CONFIG_PCI - /* - * For PCI interrupts, we need to ack the PIC controller too, overload - * irq handler data to do this - */ - if (nlm_chip_is_xls()) { - if (nlm_chip_is_xls_b()) { - irq_set_handler_data(PIC_PCIE_LINK0_IRQ, - xls_pcie_ack_b); - irq_set_handler_data(PIC_PCIE_LINK1_IRQ, - xls_pcie_ack_b); - irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ, - xls_pcie_ack_b); - irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, - xls_pcie_ack_b); - } else { - irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack); - irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack); - irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack); - irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack); - } - } else { - /* XLR PCI controller ACK */ - irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack); - } -#endif - /* unmask all PIC related interrupts. If no handler is installed by the - * drivers, it'll just ack the interrupt and return - */ - for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) - nlm_irq_mask |= (1ULL << i); - - nlm_irq_mask |= (1ULL << IRQ_TIMER); -} - -void __init arch_init_irq(void) -{ - /* Initialize the irq descriptors */ - init_xlr_irqs(); - write_c0_eimr(nlm_irq_mask); -} - -void __cpuinit nlm_smp_irq_init(void) -{ - /* set interrupt mask for non-zero cpus */ - write_c0_eimr(nlm_irq_mask); -} - -asmlinkage void plat_irq_dispatch(void) -{ - uint64_t eirr; - int i; - - eirr = read_c0_eirr() & read_c0_eimr(); - if (!eirr) - return; - - /* no need of EIRR here, writing compare clears interrupt */ - if (eirr & (1 << IRQ_TIMER)) { - do_IRQ(IRQ_TIMER); - return; - } - - /* use dcltz: optimize below code */ - for (i = 63; i != -1; i--) { - if (eirr & (1ULL << i)) - break; - } - if (i == -1) { - pr_err("no interrupt !!\n"); - return; - } - - /* Ack eirr */ - write_c0_eirr(1ULL << i); - - do_IRQ(i); -} diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c index 609ec253464..eab64b45dff 100644 --- a/arch/mips/netlogic/xlr/platform.c +++ b/arch/mips/netlogic/xlr/platform.c @@ -15,18 +15,19 @@ #include <linux/serial_8250.h> #include <linux/serial_reg.h> +#include <asm/netlogic/haldefs.h> #include <asm/netlogic/xlr/iomap.h> #include <asm/netlogic/xlr/pic.h> #include <asm/netlogic/xlr/xlr.h> unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) { - nlm_reg_t *mmio; + uint64_t uartbase; unsigned int value; - /* XLR uart does not need any mapping of regs */ - mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift)); - value = netlogic_read_reg(mmio, 0); + /* sign extend to 64 bits, if needed */ + uartbase = (uint64_t)(long)p->membase; + value = nlm_read_reg(uartbase, offset); /* See XLR/XLS errata */ if (offset == UART_MSR) @@ -39,10 +40,10 @@ unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) { - nlm_reg_t *mmio; + uint64_t uartbase; - /* XLR uart does not need any mapping of regs */ - mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift)); + /* sign extend to 64 bits, if needed */ + uartbase = (uint64_t)(long)p->membase; /* See XLR/XLS errata */ if (offset == UART_MSR) @@ -50,7 +51,7 @@ void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) else if (offset == UART_MCR) value ^= 0x3; - netlogic_write_reg(mmio, 0, value); + nlm_write_reg(uartbase, offset, value); } #define PORT(_irq) \ @@ -82,15 +83,15 @@ static struct platform_device uart_device = { static int __init nlm_uart_init(void) { - nlm_reg_t *mmio; + unsigned long uartbase; - mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); - xlr_uart_data[0].membase = (void __iomem *)mmio; - xlr_uart_data[0].mapbase = CPHYSADDR((unsigned long)mmio); + uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET); + xlr_uart_data[0].membase = (void __iomem *)uartbase; + xlr_uart_data[0].mapbase = CPHYSADDR(uartbase); - mmio = netlogic_io_mmio(NETLOGIC_IO_UART_1_OFFSET); - xlr_uart_data[1].membase = (void __iomem *)mmio; - xlr_uart_data[1].mapbase = CPHYSADDR((unsigned long)mmio); + uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_1_OFFSET); + xlr_uart_data[1].membase = (void __iomem *)uartbase; + xlr_uart_data[1].mapbase = CPHYSADDR(uartbase); return platform_device_register(&uart_device); } diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c index cee25ddd088..c9d066dedc4 100644 --- a/arch/mips/netlogic/xlr/setup.c +++ b/arch/mips/netlogic/xlr/setup.c @@ -39,26 +39,33 @@ #include <asm/reboot.h> #include <asm/time.h> #include <asm/bootinfo.h> -#include <asm/smp-ops.h> #include <asm/netlogic/interrupt.h> #include <asm/netlogic/psb-bootinfo.h> +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> #include <asm/netlogic/xlr/xlr.h> #include <asm/netlogic/xlr/iomap.h> #include <asm/netlogic/xlr/pic.h> #include <asm/netlogic/xlr/gpio.h> -unsigned long netlogic_io_base = (unsigned long)(DEFAULT_NETLOGIC_IO_BASE); -unsigned long nlm_common_ebase = 0x0; +uint64_t nlm_io_base = DEFAULT_NETLOGIC_IO_BASE; +uint64_t nlm_pic_base; struct psb_info nlm_prom_info; +unsigned long nlm_common_ebase = 0x0; + +/* default to uniprocessor */ +uint32_t nlm_coremask = 1, nlm_cpumask = 1; +int nlm_threads_per_core = 1; + static void __init nlm_early_serial_setup(void) { struct uart_port s; - nlm_reg_t *uart_base; + unsigned long uart_base; - uart_base = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); + uart_base = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET); memset(&s, 0, sizeof(s)); s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; s.iotype = UPIO_MEM32; @@ -67,18 +74,18 @@ static void __init nlm_early_serial_setup(void) s.uartclk = PIC_CLKS_PER_SEC; s.serial_in = nlm_xlr_uart_in; s.serial_out = nlm_xlr_uart_out; - s.mapbase = (unsigned long)uart_base; + s.mapbase = uart_base; s.membase = (unsigned char __iomem *)uart_base; early_serial_setup(&s); } static void nlm_linux_exit(void) { - nlm_reg_t *mmio; + uint64_t gpiobase; - mmio = netlogic_io_mmio(NETLOGIC_IO_GPIO_OFFSET); + gpiobase = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); /* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */ - netlogic_write_reg(mmio, NETLOGIC_GPIO_SWRESET_REG, 1); + nlm_write_reg(gpiobase, NETLOGIC_GPIO_SWRESET_REG, 1); for ( ; ; ) cpu_wait(); } @@ -96,6 +103,11 @@ const char *get_system_type(void) return "Netlogic XLR/XLS Series"; } +unsigned int nlm_get_cpu_frequency(void) +{ + return (unsigned int)nlm_prom_info.cpu_frequency; +} + void __init prom_free_prom_memory(void) { /* Nothing yet */ @@ -175,6 +187,7 @@ void __init prom_init(void) prom_infop = (struct psb_info *)(long)(int)fw_arg3; nlm_prom_info = *prom_infop; + nlm_pic_base = nlm_mmio_base(NETLOGIC_IO_PIC_OFFSET); nlm_early_serial_setup(); build_arcs_cmdline(argv); diff --git a/arch/mips/netlogic/xlr/smpboot.S b/arch/mips/netlogic/xlr/wakeup.c index 8cb7889ce0c..db5d987d488 100644 --- a/arch/mips/netlogic/xlr/smpboot.S +++ b/arch/mips/netlogic/xlr/wakeup.c @@ -33,68 +33,36 @@ */ #include <linux/init.h> +#include <linux/threads.h> #include <asm/asm.h> #include <asm/asm-offsets.h> -#include <asm/regdef.h> #include <asm/mipsregs.h> +#include <asm/addrspace.h> +#include <asm/string.h> -/* - * Early code for secondary CPUs. This will get them out of the bootloader - * code and into linux. Needed because the bootloader area will be taken - * and initialized by linux. - */ - __CPUINIT -NESTED(prom_pre_boot_secondary_cpus, 16, sp) - .set mips64 - mfc0 t0, $15, 1 # read ebase - andi t0, 0x1f # t0 has the processor_id() - sll t0, 2 # offset in cpu array - - PTR_LA t1, nlm_cpu_ready # mark CPU ready - PTR_ADDU t1, t0 - li t2, 1 - sw t2, 0(t1) - - PTR_LA t1, nlm_cpu_unblock - PTR_ADDU t1, t0 -1: lw t2, 0(t1) # wait till unblocked - beqz t2, 1b - nop +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> +#include <asm/netlogic/mips-extns.h> - PTR_LA t1, nlm_next_sp - PTR_L sp, 0(t1) - PTR_LA t1, nlm_next_gp - PTR_L gp, 0(t1) +#include <asm/netlogic/xlr/iomap.h> +#include <asm/netlogic/xlr/pic.h> - PTR_LA t0, nlm_early_init_secondary - jalr t0 - nop - - PTR_LA t0, smp_bootstrap - jr t0 - nop -END(prom_pre_boot_secondary_cpus) - __FINIT - -/* - * NMI code, used for CPU wakeup, copied to reset entry - */ -NESTED(nlm_boot_smp_nmi, 0, sp) - .set push - .set noat - .set mips64 - .set noreorder +int __cpuinit xlr_wakeup_secondary_cpus(void) +{ + unsigned int i, boot_cpu; - /* Clear the NMI and BEV bits */ - MFC0 k0, CP0_STATUS - li k1, 0xffb7ffff - and k0, k0, k1 - MTC0 k0, CP0_STATUS + /* + * In case of RMI boot, hit with NMI to get the cores + * from bootloader to linux code. + */ + boot_cpu = hard_smp_processor_id(); + nlm_set_nmi_handler(nlm_rmiboot_preboot); + for (i = 0; i < NR_CPUS; i++) { + if (i == boot_cpu || (nlm_cpumask & (1u << i)) == 0) + continue; + nlm_pic_send_ipi(nlm_pic_base, i, 1, 1); /* send NMI */ + } - PTR_LA k1, secondary_entry_point - PTR_L k0, 0(k1) - jr k0 - nop - .set pop -END(nlm_boot_smp_nmi) + return 0; +} |