diff options
Diffstat (limited to 'arch/mips/netlogic')
| -rw-r--r-- | arch/mips/netlogic/Kconfig | 9 | ||||
| -rw-r--r-- | arch/mips/netlogic/common/earlycons.c | 2 | ||||
| -rw-r--r-- | arch/mips/netlogic/common/irq.c | 74 | ||||
| -rw-r--r-- | arch/mips/netlogic/common/reset.S | 98 | ||||
| -rw-r--r-- | arch/mips/netlogic/common/smp.c | 20 | ||||
| -rw-r--r-- | arch/mips/netlogic/common/smpboot.S | 16 | ||||
| -rw-r--r-- | arch/mips/netlogic/common/time.c | 5 | ||||
| -rw-r--r-- | arch/mips/netlogic/dts/Makefile | 1 | ||||
| -rw-r--r-- | arch/mips/netlogic/dts/xlp_gvp.dts | 77 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlp/Makefile | 2 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlp/ahci-init-xlp2.c | 377 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlp/ahci-init.c | 209 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlp/dt.c | 37 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlp/nlm_hal.c | 284 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlp/setup.c | 31 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlp/usb-init-xlp2.c | 88 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlp/wakeup.c | 98 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlr/fmn-config.c | 3 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlr/platform.c | 4 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlr/setup.c | 21 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlr/wakeup.c | 3 | 
21 files changed, 1256 insertions, 203 deletions
diff --git a/arch/mips/netlogic/Kconfig b/arch/mips/netlogic/Kconfig index 852a4ee0995..4eb683aef7d 100644 --- a/arch/mips/netlogic/Kconfig +++ b/arch/mips/netlogic/Kconfig @@ -28,6 +28,15 @@ config DT_XLP_FVP  	  pointer to the kernel.  The corresponding DTS file is at  	  arch/mips/netlogic/dts/xlp_fvp.dts +config DT_XLP_GVP +	bool "Built-in device tree for XLP GVP boards" +	default y +	help +	  Add an FDT blob for XLP GVP board into the kernel. +	  This DTB will be used if the firmware does not pass in a DTB +	  pointer to the kernel.  The corresponding DTS file is at +	  arch/mips/netlogic/dts/xlp_gvp.dts +  config NLM_MULTINODE  	bool "Support for multi-chip boards"  	depends on NLM_XLP_BOARD diff --git a/arch/mips/netlogic/common/earlycons.c b/arch/mips/netlogic/common/earlycons.c index 1902fa22d27..769f93032c5 100644 --- a/arch/mips/netlogic/common/earlycons.c +++ b/arch/mips/netlogic/common/earlycons.c @@ -37,9 +37,11 @@  #include <asm/mipsregs.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/uart.h>  #elif defined(CONFIG_CPU_XLR)  #include <asm/netlogic/xlr/iomap.h> diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 1c7e3a1b81a..c100b9afa0a 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -180,6 +180,7 @@ static void __init nlm_init_percpu_irqs(void)  #endif  } +  void nlm_setup_pic_irq(int node, int picirq, int irq, int irt)  {  	struct nlm_pic_irq *pic_data; @@ -202,37 +203,39 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *))  	xirq = nlm_irq_to_xirq(node, irq);  	pic_data = irq_get_handler_data(xirq); +	if (WARN_ON(!pic_data)) +		return;  	pic_data->extra_ack = xack;  }  static void nlm_init_node_irqs(int node)  { -	int i, irt; -	uint64_t irqmask;  	struct nlm_soc_info *nodep; +	int i, irt;  	pr_info("Init IRQ for node %d\n", node);  	nodep = nlm_get_node(node); -	irqmask = PERCPU_IRQ_MASK; +	nodep->irqmask = PERCPU_IRQ_MASK;  	for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) {  		irt = nlm_irq_to_irt(i); -		if (irt == -1) +		if (irt == -1)		/* unused irq */  			continue; -		nlm_setup_pic_irq(node, i, i, irt); -		/* set interrupts to first cpu in node */ +		nodep->irqmask |= 1ull << i; +		if (irt == -2)		/* not a direct PIC irq */ +			continue; +  		nlm_pic_init_irt(nodep->picbase, irt, i, -					node * NLM_CPUS_PER_NODE, 0); -		irqmask |= (1ull << i); +				node * nlm_threads_per_node(), 0); +		nlm_setup_pic_irq(node, i, i, irt);  	} -	nodep->irqmask = irqmask;  }  void nlm_smp_irq_init(int hwcpuid)  {  	int node, cpu; -	node = hwcpuid / NLM_CPUS_PER_NODE; -	cpu  = hwcpuid % NLM_CPUS_PER_NODE; +	node = nlm_cpuid_to_node(hwcpuid); +	cpu  = hwcpuid % nlm_threads_per_node();  	if (cpu == 0 && node != 0)  		nlm_init_node_irqs(node); @@ -256,13 +259,23 @@ asmlinkage void plat_irq_dispatch(void)  		return;  	} +#if defined(CONFIG_PCI_MSI) && defined(CONFIG_CPU_XLP) +	/* PCI interrupts need a second level dispatch for MSI bits */ +	if (i >= PIC_PCIE_LINK_MSI_IRQ(0) && i <= PIC_PCIE_LINK_MSI_IRQ(3)) { +		nlm_dispatch_msi(node, i); +		return; +	} +	if (i >= PIC_PCIE_MSIX_IRQ(0) && i <= PIC_PCIE_MSIX_IRQ(3)) { +		nlm_dispatch_msix(node, i); +		return; +	} + +#endif  	/* top level irq handling */  	do_IRQ(nlm_irq_to_xirq(node, i));  }  #ifdef CONFIG_OF -static struct irq_domain *xlp_pic_domain; -  static const struct irq_domain_ops xlp_pic_irq_domain_ops = {  	.xlate = irq_domain_xlate_onetwocell,  }; @@ -271,8 +284,9 @@ static int __init xlp_of_pic_init(struct device_node *node,  					struct device_node *parent)  {  	const int n_picirqs = PIC_IRT_LAST_IRQ - PIC_IRQ_BASE + 1; +	struct irq_domain *xlp_pic_domain;  	struct resource res; -	int socid, ret; +	int socid, ret, bus;  	/* we need a hack to get the PIC's SoC chip id */  	ret = of_address_to_resource(node, 0, &res); @@ -280,7 +294,34 @@ static int __init xlp_of_pic_init(struct device_node *node,  		pr_err("PIC %s: reg property not found!\n", node->name);  		return -EINVAL;  	} -	socid = (res.start >> 18) & 0x3; + +	if (cpu_is_xlp9xx()) { +		bus = (res.start >> 20) & 0xf; +		for (socid = 0; socid < NLM_NR_NODES; socid++) { +			if (!nlm_node_present(socid)) +				continue; +			if (nlm_get_node(socid)->socbus == bus) +				break; +		} +		if (socid == NLM_NR_NODES) { +			pr_err("PIC %s: Node mapping for bus %d not found!\n", +					node->name, bus); +			return -EINVAL; +		} +	} else { +		socid = (res.start >> 18) & 0x3; +		if (!nlm_node_present(socid)) { +			pr_err("PIC %s: node %d does not exist!\n", +							node->name, socid); +			return -EINVAL; +		} +	} + +	if (!nlm_node_present(socid)) { +		pr_err("PIC %s: node %d does not exist!\n", node->name, socid); +		return -EINVAL; +	} +  	xlp_pic_domain = irq_domain_add_legacy(node, n_picirqs,  		nlm_irq_to_xirq(socid, PIC_IRQ_BASE), PIC_IRQ_BASE,  		&xlp_pic_irq_domain_ops, NULL); @@ -288,8 +329,7 @@ static int __init xlp_of_pic_init(struct device_node *node,  		pr_err("PIC %s: Creating legacy domain failed!\n", node->name);  		return -EINVAL;  	} -	pr_info("Node %d: IRQ domain created for PIC@%pa\n", socid, -							&res.start); +	pr_info("Node %d: IRQ domain created for PIC@%pR\n", socid, &res);  	return 0;  } diff --git a/arch/mips/netlogic/common/reset.S b/arch/mips/netlogic/common/reset.S index adb18288a6c..701c4bcb9e4 100644 --- a/arch/mips/netlogic/common/reset.S +++ b/arch/mips/netlogic/common/reset.S @@ -32,10 +32,11 @@   * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */ -#include <linux/init.h>  #include <asm/asm.h>  #include <asm/asm-offsets.h> +#include <asm/cpu.h> +#include <asm/cacheops.h>  #include <asm/regdef.h>  #include <asm/mipsregs.h>  #include <asm/stackframe.h> @@ -50,8 +51,8 @@  #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 + \ +#define SYS_CPU_COHERENT_BASE	CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \ +			XLP_IO_SYS_OFFSET(0) + XLP_IO_PCI_HDRSZ + \  			SYS_CPU_NONCOHERENT_MODE * 4  /* Enable XLP features and workarounds in the LSU */ @@ -74,35 +75,67 @@  .endm  /* - * Low level flush for L1D cache on XLP, the normal cache ops does - * not do the complete and correct cache flush. + * Allow access to physical mem >64G by enabling ELPA in PAGEGRAIN + * register. This is needed before going to C code since the SP can + * in this region. Called from all HW threads. + */ +.macro xlp_early_mmu_init +	mfc0	t0, CP0_PAGEMASK, 1 +	li	t1, (1 << 29)		/* ELPA bit */ +	or	t0, t1 +	mtc0	t0, CP0_PAGEMASK, 1 +.endm + +/* + * L1D cache has to be flushed before enabling threads in XLP. + * On XLP8xx/XLP3xx, we do a low level flush using processor control + * registers. On XLPII CPUs, usual cache instructions work.   */  .macro	xlp_flush_l1_dcache +	mfc0	t0, CP0_EBASE, 0 +	andi	t0, t0, PRID_IMP_MASK +	slt	t1, t0, 0x1200 +	beqz	t1, 15f +	nop + +	/* XLP8xx low level cache flush */  	li	t0, LSU_DEBUG_DATA0  	li	t1, LSU_DEBUG_ADDR  	li	t2, 0		/* index */  	li	t3, 0x1000	/* loop count */ -1: +11:  	sll	v0, t2, 5  	mtcr	zero, t0  	ori	v1, v0, 0x3	/* way0 | write_enable | write_active */  	mtcr	v1, t1 -2: +12:  	mfcr	v1, t1  	andi	v1, 0x1		/* wait for write_active == 0 */ -	bnez	v1, 2b +	bnez	v1, 12b  	nop  	mtcr	zero, t0  	ori	v1, v0, 0x7	/* way1 | write_enable | write_active */  	mtcr	v1, t1 -3: +13:  	mfcr	v1, t1  	andi	v1, 0x1		/* wait for write_active == 0 */ -	bnez	v1, 3b +	bnez	v1, 13b  	nop  	addi	t2, 1 -	bne	t3, t2, 1b +	bne	t3, t2, 11b +	nop +	b	17f +	nop + +	/* XLPII CPUs, Invalidate all 64k of L1 D-cache */ +15: +	li	t0, 0x80000000 +	li	t1, 0x80010000 +16:	cache	Index_Writeback_Inv_D, 0(t0) +	addiu	t0, t0, 32 +	bne	t0, t1, 16b  	nop +17:  .endm  /* @@ -138,6 +171,17 @@ FEXPORT(nlm_reset_entry)  	nop  1:	/* Entry point on core wakeup */ +	mfc0	t0, CP0_EBASE, 0	/* processor ID */ +	andi	t0, PRID_IMP_MASK +	li	t1, 0x1500		/* XLP 9xx */ +	beq	t0, t1, 2f		/* does not need to set coherent */ +	nop + +	li	t1, 0x1300		/* XLP 5xx */ +	beq	t0, t1, 2f		/* does not need to set coherent */ +	nop + +	/* set bit in SYS coherent register for the core */  	mfc0	t0, CP0_EBASE, 1  	mfc0	t1, CP0_EBASE, 1  	srl	t1, 5 @@ -149,7 +193,7 @@ FEXPORT(nlm_reset_entry)  	li	t1, 0x1  	sll	t0, t1, t0  	nor	t0, t0, zero		/* t0 <- ~(1 << core) */ -	li	t2, SYS_CPU_COHERENT_BASE(0) +	li	t2, SYS_CPU_COHERENT_BASE  	add	t2, t2, t3		/* t2 <- SYS offset for node */  	lw	t1, 0(t2)  	and	t1, t1, t0 @@ -159,17 +203,20 @@ FEXPORT(nlm_reset_entry)  	lw	t1, 0(t2)  	sync +2:  	/* Configure LSU on Non-0 Cores. */  	xlp_config_lsu  	/* FALL THROUGH */  /* - * Wake up sibling threads from the initial thread in - * a core. + * Wake up sibling threads from the initial thread in a core.   */  EXPORT(nlm_boot_siblings)  	/* core L1D flush before enable threads */  	xlp_flush_l1_dcache +	/* save ra and sp, will be used later (only for boot cpu) */ +	dmtc0	ra, $22, 6 +	dmtc0	sp, $22, 7  	/* Enable hw threads by writing to MAP_THREADMODE of the core */  	li	t0, CKSEG1ADDR(RESET_DATA_PHYS)  	lw	t1, BOOT_THREAD_MODE(t0)	/* t1 <- thread mode */ @@ -181,8 +228,10 @@ EXPORT(nlm_boot_siblings)  	/*  	 * 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. -	*/ +	 * jump to the secondary wait function. + +	 * NOTE: All GPR contents are lost after the mtcr above! +	 */  	mfc0	v0, CP0_EBASE, 1  	andi	v0, 0x3ff		/* v0 <- node/core */ @@ -196,7 +245,9 @@ EXPORT(nlm_boot_siblings)  #endif  	mtc0	t1, CP0_STATUS -	/* mark CPU ready, careful here, previous mtcr trashed registers */ +	xlp_early_mmu_init + +	/* mark CPU ready */  	li	t3, CKSEG1ADDR(RESET_DATA_PHYS)  	ADDIU	t1, t3, BOOT_CPU_READY  	sll	v1, v0, 2 @@ -209,14 +260,12 @@ EXPORT(nlm_boot_siblings)  	nop  	/* -	 * For the boot CPU, we have to restore registers and -	 * return +	 * For the boot CPU, we have to restore ra and sp and return, rest +	 * of the registers will be restored by the caller  	 */ -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 +4: +	dmfc0	ra, $22, 6 +	dmfc0	sp, $22, 7  	jr	ra  	nop  EXPORT(nlm_reset_entry_end) @@ -224,6 +273,7 @@ EXPORT(nlm_reset_entry_end)  LEAF(nlm_init_boot_cpu)  #ifdef CONFIG_CPU_XLP  	xlp_config_lsu +	xlp_early_mmu_init  #endif  	jr	ra  	nop diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c index 6f8feb9efcf..4fde7ac76cc 100644 --- a/arch/mips/netlogic/common/smp.c +++ b/arch/mips/netlogic/common/smp.c @@ -63,7 +63,7 @@ void nlm_send_ipi_single(int logical_cpu, unsigned int action)  	uint64_t picbase;  	cpu = cpu_logical_map(logical_cpu); -	node = cpu / NLM_CPUS_PER_NODE; +	node = nlm_cpuid_to_node(cpu);  	picbase = nlm_get_node(node)->picbase;  	if (action & SMP_CALL_FUNCTION) @@ -135,10 +135,6 @@ void nlm_smp_finish(void)  	local_irq_enable();  } -void nlm_cpus_done(void) -{ -} -  /*   * Boot all other cpus in the system, initialize them, and bring them into   * the boot function @@ -152,7 +148,7 @@ void nlm_boot_secondary(int logical_cpu, struct task_struct *idle)  	int cpu, node;  	cpu = cpu_logical_map(logical_cpu); -	node = cpu / NLM_CPUS_PER_NODE; +	node = nlm_cpuid_to_node(logical_cpu);  	nlm_next_sp = (unsigned long)__KSTK_TOS(idle);  	nlm_next_gp = (unsigned long)task_thread_info(idle); @@ -164,7 +160,7 @@ void nlm_boot_secondary(int logical_cpu, struct task_struct *idle)  void __init nlm_smp_setup(void)  {  	unsigned int boot_cpu; -	int num_cpus, i, ncore; +	int num_cpus, i, ncore, node;  	volatile u32 *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY);  	char buf[64]; @@ -187,6 +183,8 @@ void __init nlm_smp_setup(void)  			__cpu_number_map[i] = num_cpus;  			__cpu_logical_map[num_cpus] = i;  			set_cpu_possible(num_cpus, true); +			node = nlm_cpuid_to_node(i); +			cpumask_set_cpu(num_cpus, &nlm_get_node(node)->cpumask);  			++num_cpus;  		}  	} @@ -196,7 +194,7 @@ void __init nlm_smp_setup(void)  	cpumask_scnprintf(buf, ARRAY_SIZE(buf), cpu_possible_mask);  	pr_info("Possible CPU mask: %s\n", buf); -	/* check with the cores we have worken up */ +	/* check with the cores we have woken up */  	for (ncore = 0, i = 0; i < NLM_NR_NODES; i++)  		ncore += hweight32(nlm_get_node(i)->coremask); @@ -211,6 +209,7 @@ static int nlm_parse_cpumask(cpumask_t *wakeup_mask)  {  	uint32_t core0_thr_mask, core_thr_mask;  	int threadmode, i, j; +	char buf[64];  	core0_thr_mask = 0;  	for (i = 0; i < NLM_THREADS_PER_CORE; i++) @@ -245,8 +244,8 @@ static int nlm_parse_cpumask(cpumask_t *wakeup_mask)  	return threadmode;  unsupp: -	panic("Unsupported CPU mask %lx\n", -		(unsigned long)cpumask_bits(wakeup_mask)[0]); +	cpumask_scnprintf(buf, ARRAY_SIZE(buf), wakeup_mask); +	panic("Unsupported CPU mask %s", buf);  	return 0;  } @@ -275,7 +274,6 @@ struct plat_smp_ops nlm_smp_ops = {  	.send_ipi_mask		= nlm_send_ipi_mask,  	.init_secondary		= nlm_init_secondary,  	.smp_finish		= nlm_smp_finish, -	.cpus_done		= nlm_cpus_done,  	.boot_secondary		= nlm_boot_secondary,  	.smp_setup		= nlm_smp_setup,  	.prepare_cpus		= nlm_prepare_cpus, diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index aa6cff0a229..805355b0bd0 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -32,7 +32,6 @@   * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */ -#include <linux/init.h>  #include <asm/asm.h>  #include <asm/asm-offsets.h> @@ -55,8 +54,9 @@  	.set	noat  	.set	arch=xlr		/* for mfcr/mtcr, XLR is sufficient */ -FEXPORT(xlp_boot_core0_siblings)	/* "Master" cpu starts from here */ -	dmtc0	sp, $4, 2		/* SP saved in UserLocal */ +/* Called by the boot cpu to wake up its sibling threads */ +NESTED(xlp_boot_core0_siblings, PT_SIZE, sp) +	/* CPU register contents lost when enabling threads, save them first */  	SAVE_ALL  	sync  	/* find the location to which nlm_boot_siblings was relocated */ @@ -66,9 +66,12 @@ FEXPORT(xlp_boot_core0_siblings)	/* "Master" cpu starts from here */  	dsubu	t2, t1  	daddu	t2, t0  	/* call it */ -	jr	t2 +	jalr	t2  	nop -	/* not reached */ +	RESTORE_ALL +	jr	ra +	nop +END(xlp_boot_core0_siblings)  NESTED(nlm_boot_secondary_cpus, 16, sp)  	/* Initialize CP0 Status */ @@ -98,7 +101,7 @@ END(nlm_boot_secondary_cpus)   * 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. + * because the bootloader area will be taken and initialized by linux.   */  NESTED(nlm_rmiboot_preboot, 16, sp)  	mfc0	t0, $15, 1	/* read ebase */ @@ -133,6 +136,7 @@ NESTED(nlm_rmiboot_preboot, 16, sp)  	or	t1, t2, v1	/* put in new value */  	mtcr	t1, t0		/* update core control */ +	/* wait for NMI to hit */  1:	wait  	b	1b  	nop diff --git a/arch/mips/netlogic/common/time.c b/arch/mips/netlogic/common/time.c index 13391b8a603..0c0a1a606f7 100644 --- a/arch/mips/netlogic/common/time.c +++ b/arch/mips/netlogic/common/time.c @@ -82,6 +82,7 @@ static struct clocksource csrc_pic = {  static void nlm_init_pic_timer(void)  {  	uint64_t picbase = nlm_get_node(0)->picbase; +	u32 picfreq;  	nlm_pic_set_timer(picbase, PIC_CLOCK_TIMER, ~0ULL, 0, 0);  	if (current_cpu_data.cputype == CPU_XLR) { @@ -92,7 +93,9 @@ static void nlm_init_pic_timer(void)  		csrc_pic.read	= nlm_get_pic_timer;  	}  	csrc_pic.rating = 1000; -	clocksource_register_hz(&csrc_pic, pic_timer_freq()); +	picfreq = pic_timer_freq(); +	clocksource_register_hz(&csrc_pic, picfreq); +	pr_info("PIC clock source added, frequency %d\n", picfreq);  }  void __init plat_time_init(void) diff --git a/arch/mips/netlogic/dts/Makefile b/arch/mips/netlogic/dts/Makefile index 0b9be5fd2e4..25c8e873ee2 100644 --- a/arch/mips/netlogic/dts/Makefile +++ b/arch/mips/netlogic/dts/Makefile @@ -1,3 +1,4 @@  obj-$(CONFIG_DT_XLP_EVP) := xlp_evp.dtb.o  obj-$(CONFIG_DT_XLP_SVP) += xlp_svp.dtb.o  obj-$(CONFIG_DT_XLP_FVP) += xlp_fvp.dtb.o +obj-$(CONFIG_DT_XLP_GVP) += xlp_gvp.dtb.o diff --git a/arch/mips/netlogic/dts/xlp_gvp.dts b/arch/mips/netlogic/dts/xlp_gvp.dts new file mode 100644 index 00000000000..bb4ecd1d47f --- /dev/null +++ b/arch/mips/netlogic/dts/xlp_gvp.dts @@ -0,0 +1,77 @@ +/* + * XLP9XX Device Tree Source for GVP boards + */ + +/dts-v1/; +/ { +	model = "netlogic,XLP-GVP"; +	compatible = "netlogic,xlp"; +	#address-cells = <2>; +	#size-cells = <2>; + +	soc { +		#address-cells = <2>; +		#size-cells = <1>; +		compatible = "simple-bus"; +		ranges = <0 0  0 0x18000000  0x04000000   // PCIe CFG +			  1 0  0 0x16000000  0x02000000>; // GBU chipselects + +		serial0: serial@30000 { +			device_type = "serial"; +			compatible = "ns16550"; +			reg = <0 0x112100 0xa00>; +			reg-shift = <2>; +			reg-io-width = <4>; +			clock-frequency = <125000000>; +			interrupt-parent = <&pic>; +			interrupts = <17>; +		}; +		pic: pic@110000 { +			compatible = "netlogic,xlp-pic"; +			#address-cells = <0>; +			#interrupt-cells = <1>; +			reg = <0 0x110000 0x200>; +			interrupt-controller; +		}; + +		nor_flash@1,0 { +			compatible = "cfi-flash"; +			#address-cells = <1>; +			#size-cells = <1>; +			bank-width = <2>; +			reg = <1 0 0x1000000>; + +			partition@0 { +				label = "x-loader"; +				reg = <0x0 0x100000>; /* 1M */ +				read-only; +			}; + +			partition@100000 { +				label = "u-boot"; +				reg = <0x100000 0x100000>; /* 1M */ +			}; + +			partition@200000 { +				label = "kernel"; +				reg = <0x200000 0x500000>; /* 5M */ +			}; + +			partition@700000 { +				label = "rootfs"; +				reg = <0x700000 0x800000>; /* 8M */ +			}; + +			partition@f00000 { +				label = "env"; +				reg = <0xf00000 0x100000>; /* 1M */ +				read-only; +			}; +		}; + +	}; + +	chosen { +		bootargs = "console=ttyS0,115200 rdinit=/sbin/init"; +	}; +}; diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile index ed9a93c0465..be358a8050c 100644 --- a/arch/mips/netlogic/xlp/Makefile +++ b/arch/mips/netlogic/xlp/Makefile @@ -2,3 +2,5 @@ obj-y				+= setup.o nlm_hal.o cop2-ex.o dt.o  obj-$(CONFIG_SMP)		+= wakeup.o  obj-$(CONFIG_USB)		+= usb-init.o  obj-$(CONFIG_USB)		+= usb-init-xlp2.o +obj-$(CONFIG_SATA_AHCI)		+= ahci-init.o +obj-$(CONFIG_SATA_AHCI)		+= ahci-init-xlp2.o diff --git a/arch/mips/netlogic/xlp/ahci-init-xlp2.c b/arch/mips/netlogic/xlp/ahci-init-xlp2.c new file mode 100644 index 00000000000..c83dbf3689e --- /dev/null +++ b/arch/mips/netlogic/xlp/ahci-init-xlp2.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2003-2014 Broadcom Corporation + * 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 Broadcom + * 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 BROADCOM ``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 BROADCOM 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/pci.h> +#include <linux/irq.h> +#include <linux/bitops.h> +#include <linux/pci_ids.h> +#include <linux/nodemask.h> + +#include <asm/cpu.h> +#include <asm/mipsregs.h> + +#include <asm/netlogic/common.h> +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/mips-extns.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/iomap.h> + +#define SATA_CTL		0x0 +#define SATA_STATUS		0x1 /* Status Reg */ +#define SATA_INT		0x2 /* Interrupt Reg */ +#define SATA_INT_MASK		0x3 /* Interrupt Mask Reg */ +#define SATA_BIU_TIMEOUT	0x4 +#define AXIWRSPERRLOG		0x5 +#define AXIRDSPERRLOG		0x6 +#define BiuTimeoutLow		0x7 +#define BiuTimeoutHi		0x8 +#define BiuSlvErLow		0x9 +#define BiuSlvErHi		0xa +#define IO_CONFIG_SWAP_DIS	0xb +#define CR_REG_TIMER		0xc +#define CORE_ID			0xd +#define AXI_SLAVE_OPT1		0xe +#define PHY_MEM_ACCESS		0xf +#define PHY0_CNTRL		0x10 +#define PHY0_STAT		0x11 +#define PHY0_RX_ALIGN		0x12 +#define PHY0_RX_EQ_LO		0x13 +#define PHY0_RX_EQ_HI		0x14 +#define PHY0_BIST_LOOP		0x15 +#define PHY1_CNTRL		0x16 +#define PHY1_STAT		0x17 +#define PHY1_RX_ALIGN		0x18 +#define PHY1_RX_EQ_LO		0x19 +#define PHY1_RX_EQ_HI		0x1a +#define PHY1_BIST_LOOP		0x1b +#define RdExBase		0x1c +#define RdExLimit		0x1d +#define CacheAllocBase		0x1e +#define CacheAllocLimit		0x1f +#define BiuSlaveCmdGstNum	0x20 + +/*SATA_CTL Bits */ +#define SATA_RST_N		BIT(0)  /* Active low reset sata_core phy */ +#define SataCtlReserve0		BIT(1) +#define M_CSYSREQ		BIT(2)  /* AXI master low power, not used */ +#define S_CSYSREQ		BIT(3)  /* AXI slave low power, not used */ +#define P0_CP_DET		BIT(8)  /* Reserved, bring in from pad */ +#define P0_MP_SW		BIT(9)  /* Mech Switch */ +#define P0_DISABLE		BIT(10) /* disable p0 */ +#define P0_ACT_LED_EN		BIT(11) /* Active LED enable */ +#define P0_IRST_HARD_SYNTH	BIT(12) /* PHY hard synth reset */ +#define P0_IRST_HARD_TXRX	BIT(13) /* PHY lane hard reset */ +#define P0_IRST_POR		BIT(14) /* PHY power on reset*/ +#define P0_IPDTXL		BIT(15) /* PHY Tx lane dis/power down */ +#define P0_IPDRXL		BIT(16) /* PHY Rx lane dis/power down */ +#define P0_IPDIPDMSYNTH		BIT(17) /* PHY synthesizer dis/porwer down */ +#define P0_CP_POD_EN		BIT(18) /* CP_POD enable */ +#define P0_AT_BYPASS		BIT(19) /* P0 address translation by pass */ +#define P1_CP_DET		BIT(20) /* Reserved,Cold Detect */ +#define P1_MP_SW		BIT(21) /* Mech Switch */ +#define P1_DISABLE		BIT(22) /* disable p1 */ +#define P1_ACT_LED_EN		BIT(23) /* Active LED enable */ +#define P1_IRST_HARD_SYNTH	BIT(24) /* PHY hard synth reset */ +#define P1_IRST_HARD_TXRX	BIT(25) /* PHY lane hard reset */ +#define P1_IRST_POR		BIT(26) /* PHY power on reset*/ +#define P1_IPDTXL		BIT(27) /* PHY Tx lane dis/porwer down */ +#define P1_IPDRXL		BIT(28) /* PHY Rx lane dis/porwer down */ +#define P1_IPDIPDMSYNTH		BIT(29) /* PHY synthesizer dis/porwer down */ +#define P1_CP_POD_EN		BIT(30) +#define P1_AT_BYPASS		BIT(31) /* P1 address translation by pass */ + +/* Status register */ +#define M_CACTIVE		BIT(0)  /* m_cactive, not used */ +#define S_CACTIVE		BIT(1)  /* s_cactive, not used */ +#define P0_PHY_READY		BIT(8)  /* phy is ready */ +#define P0_CP_POD		BIT(9)  /* Cold PowerOn */ +#define P0_SLUMBER		BIT(10) /* power mode slumber */ +#define P0_PATIAL		BIT(11) /* power mode patial */ +#define P0_PHY_SIG_DET		BIT(12) /* phy dignal detect */ +#define P0_PHY_CALI		BIT(13) /* phy calibration done */ +#define P1_PHY_READY		BIT(16) /* phy is ready */ +#define P1_CP_POD		BIT(17) /* Cold PowerOn */ +#define P1_SLUMBER		BIT(18) /* power mode slumber */ +#define P1_PATIAL		BIT(19) /* power mode patial */ +#define P1_PHY_SIG_DET		BIT(20) /* phy dignal detect */ +#define P1_PHY_CALI		BIT(21) /* phy calibration done */ + +/* SATA CR_REG_TIMER bits */ +#define CR_TIME_SCALE		(0x1000 << 0) + +/* SATA PHY specific registers start and end address */ +#define RXCDRCALFOSC0		0x0065 +#define CALDUTY			0x006e +#define RXDPIF			0x8065 +#define PPMDRIFTMAX_HI		0x80A4 + +#define nlm_read_sata_reg(b, r)		nlm_read_reg(b, r) +#define nlm_write_sata_reg(b, r, v)	nlm_write_reg(b, r, v) +#define nlm_get_sata_pcibase(node)	\ +		nlm_pcicfg_base(XLP9XX_IO_SATA_OFFSET(node)) +#define nlm_get_sata_regbase(node)	\ +		(nlm_get_sata_pcibase(node) + 0x100) + +/* SATA PHY config for register block 1 0x0065 .. 0x006e */ +static const u8 sata_phy_config1[]  = { +	0xC9, 0xC9, 0x07, 0x07, 0x18, 0x18, 0x01, 0x01, 0x22, 0x00 +}; + +/* SATA PHY config for register block 2 0x0x8065 .. 0x0x80A4 */ +static const u8 sata_phy_config2[]  = { +	0xAA, 0x00, 0x4C, 0xC9, 0xC9, 0x07, 0x07, 0x18, +	0x18, 0x05, 0x0C, 0x10, 0x00, 0x10, 0x00, 0xFF, +	0xCF, 0xF7, 0xE1, 0xF5, 0xFD, 0xFD, 0xFF, 0xFF, +	0xFF, 0xFF, 0xE3, 0xE7, 0xDB, 0xF5, 0xFD, 0xFD, +	0xF5, 0xF5, 0xFF, 0xFF, 0xE3, 0xE7, 0xDB, 0xF5, +	0xFD, 0xFD, 0xF5, 0xF5, 0xFF, 0xFF, 0xFF, 0xF5, +	0x3F, 0x00, 0x32, 0x00, 0x03, 0x01, 0x05, 0x05, +	0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x04, +}; + +const int sata_phy_debug = 0;	/* set to verify PHY writes */ + +static void sata_clear_glue_reg(u64 regbase, u32 off, u32 bit) +{ +	u32 reg_val; + +	reg_val = nlm_read_sata_reg(regbase, off); +	nlm_write_sata_reg(regbase, off, (reg_val & ~bit)); +} + +static void sata_set_glue_reg(u64 regbase, u32 off, u32 bit) +{ +	u32 reg_val; + +	reg_val = nlm_read_sata_reg(regbase, off); +	nlm_write_sata_reg(regbase, off, (reg_val | bit)); +} + +static void write_phy_reg(u64 regbase, u32 addr, u32 physel, u8 data) +{ +	nlm_write_sata_reg(regbase, PHY_MEM_ACCESS, +		(1u << 31) | (physel << 24) | (data << 16) | addr); +	udelay(850); +} + +static u8 read_phy_reg(u64 regbase, u32 addr, u32 physel) +{ +	u32 val; + +	nlm_write_sata_reg(regbase, PHY_MEM_ACCESS, +		(0 << 31) | (physel << 24) | (0 << 16) | addr); +	udelay(850); +	val = nlm_read_sata_reg(regbase, PHY_MEM_ACCESS); +	return (val >> 16) & 0xff; +} + +static void config_sata_phy(u64 regbase) +{ +	u32 port, i, reg; + +	for (port = 0; port < 2; port++) { +		for (i = 0, reg = RXCDRCALFOSC0; reg <= CALDUTY; reg++, i++) +			write_phy_reg(regbase, reg, port, sata_phy_config1[i]); + +		for (i = 0, reg = RXDPIF; reg <= PPMDRIFTMAX_HI; reg++, i++) +			write_phy_reg(regbase, reg, port, sata_phy_config2[i]); +	} +} + +static void check_phy_register(u64 regbase, u32 addr, u32 physel, u8 xdata) +{ +	u8 data; + +	data = read_phy_reg(regbase, addr, physel); +	pr_info("PHY read addr = 0x%x physel = %d data = 0x%x %s\n", +		addr, physel, data, data == xdata ? "TRUE" : "FALSE"); +} + +static void verify_sata_phy_config(u64 regbase) +{ +	u32 port, i, reg; + +	for (port = 0; port < 2; port++) { +		for (i = 0, reg = RXCDRCALFOSC0; reg <= CALDUTY; reg++, i++) +			check_phy_register(regbase, reg, port, +						sata_phy_config1[i]); + +		for (i = 0, reg = RXDPIF; reg <= PPMDRIFTMAX_HI; reg++, i++) +			check_phy_register(regbase, reg, port, +						sata_phy_config2[i]); +	} +} + +static void nlm_sata_firmware_init(int node) +{ +	u32 reg_val; +	u64 regbase; +	int n; + +	pr_info("Initializing XLP9XX On-chip AHCI...\n"); +	regbase = nlm_get_sata_regbase(node); + +	/* Reset port0 */ +	sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_POR); +	sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_TXRX); +	sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_SYNTH); +	sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDTXL); +	sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDRXL); +	sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDIPDMSYNTH); + +	/* port1 */ +	sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_POR); +	sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_TXRX); +	sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_SYNTH); +	sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDTXL); +	sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDRXL); +	sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDIPDMSYNTH); +	udelay(300); + +	/* Set PHY */ +	sata_set_glue_reg(regbase, SATA_CTL, P0_IPDTXL); +	sata_set_glue_reg(regbase, SATA_CTL, P0_IPDRXL); +	sata_set_glue_reg(regbase, SATA_CTL, P0_IPDIPDMSYNTH); +	sata_set_glue_reg(regbase, SATA_CTL, P1_IPDTXL); +	sata_set_glue_reg(regbase, SATA_CTL, P1_IPDRXL); +	sata_set_glue_reg(regbase, SATA_CTL, P1_IPDIPDMSYNTH); + +	udelay(1000); +	sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_POR); +	udelay(1000); +	sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_POR); +	udelay(1000); + +	/* setup PHY */ +	config_sata_phy(regbase); +	if (sata_phy_debug) +		verify_sata_phy_config(regbase); + +	udelay(1000); +	sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_TXRX); +	sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_SYNTH); +	sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_TXRX); +	sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_SYNTH); +	udelay(300); + +	/* Override reset in serial PHY mode */ +	sata_set_glue_reg(regbase, CR_REG_TIMER, CR_TIME_SCALE); +	/* Set reset SATA */ +	sata_set_glue_reg(regbase, SATA_CTL, SATA_RST_N); +	sata_set_glue_reg(regbase, SATA_CTL, M_CSYSREQ); +	sata_set_glue_reg(regbase, SATA_CTL, S_CSYSREQ); + +	pr_debug("Waiting for PHYs to come up.\n"); +	n = 10000; +	do { +		reg_val = nlm_read_sata_reg(regbase, SATA_STATUS); +		if ((reg_val & P1_PHY_READY) && (reg_val & P0_PHY_READY)) +			break; +		udelay(10); +	} while (--n > 0); + +	if (reg_val  & P0_PHY_READY) +		pr_info("PHY0 is up.\n"); +	else +		pr_info("PHY0 is down.\n"); +	if (reg_val  & P1_PHY_READY) +		pr_info("PHY1 is up.\n"); +	else +		pr_info("PHY1 is down.\n"); + +	pr_info("XLP AHCI Init Done.\n"); +} + +static int __init nlm_ahci_init(void) +{ +	int node; + +	if (!cpu_is_xlp9xx()) +		return 0; +	for (node = 0; node < NLM_NR_NODES; node++) +		if (nlm_node_present(node)) +			nlm_sata_firmware_init(node); +	return 0; +} + +static void nlm_sata_intr_ack(struct irq_data *data) +{ +	u64 regbase; +	u32 val; +	int node; + +	node = data->irq / NLM_IRQS_PER_NODE; +	regbase = nlm_get_sata_regbase(node); +	val = nlm_read_sata_reg(regbase, SATA_INT); +	sata_set_glue_reg(regbase, SATA_INT, val); +} + +static void nlm_sata_fixup_bar(struct pci_dev *dev) +{ +	dev->resource[5] = dev->resource[0]; +	memset(&dev->resource[0], 0, sizeof(dev->resource[0])); +} + +static void nlm_sata_fixup_final(struct pci_dev *dev) +{ +	u32 val; +	u64 regbase; +	int node; + +	/* Find end bridge function to find node */ +	node = xlp_socdev_to_node(dev); +	regbase = nlm_get_sata_regbase(node); + +	/* clear pending interrupts and then enable them */ +	val = nlm_read_sata_reg(regbase, SATA_INT); +	sata_set_glue_reg(regbase, SATA_INT, val); + +	/* Enable only the core interrupt */ +	sata_set_glue_reg(regbase, SATA_INT_MASK, 0x1); + +	dev->irq = nlm_irq_to_xirq(node, PIC_SATA_IRQ); +	nlm_set_pic_extra_ack(node, PIC_SATA_IRQ, nlm_sata_intr_ack); +} + +arch_initcall(nlm_ahci_init); + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_SATA, +		nlm_sata_fixup_bar); + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_SATA, +		nlm_sata_fixup_final); diff --git a/arch/mips/netlogic/xlp/ahci-init.c b/arch/mips/netlogic/xlp/ahci-init.c new file mode 100644 index 00000000000..a9d0fae0210 --- /dev/null +++ b/arch/mips/netlogic/xlp/ahci-init.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2003-2014 Broadcom Corporation + * 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 Broadcom + * 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 BROADCOM ``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 BROADCOM 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/pci.h> +#include <linux/irq.h> +#include <linux/bitops.h> + +#include <asm/cpu.h> +#include <asm/mipsregs.h> + +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/common.h> +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/mips-extns.h> + +#define SATA_CTL		0x0 +#define SATA_STATUS		0x1	/* Status Reg */ +#define SATA_INT		0x2	/* Interrupt Reg */ +#define SATA_INT_MASK		0x3	/* Interrupt Mask Reg */ +#define SATA_CR_REG_TIMER	0x4	/* PHY Conrol Timer Reg */ +#define SATA_CORE_ID		0x5	/* Core ID Reg */ +#define SATA_AXI_SLAVE_OPT1	0x6	/* AXI Slave Options Reg */ +#define SATA_PHY_LOS_LEV	0x7	/* PHY LOS Level Reg */ +#define SATA_PHY_MULTI		0x8	/* PHY Multiplier Reg */ +#define SATA_PHY_CLK_SEL	0x9	/* Clock Select Reg */ +#define SATA_PHY_AMP1_GEN1	0xa	/* PHY Transmit Amplitude Reg 1 */ +#define SATA_PHY_AMP1_GEN2	0xb	/* PHY Transmit Amplitude Reg 2 */ +#define SATA_PHY_AMP1_GEN3	0xc	/* PHY Transmit Amplitude Reg 3 */ +#define SATA_PHY_PRE1		0xd	/* PHY Transmit Preemphasis Reg 1 */ +#define SATA_PHY_PRE2		0xe	/* PHY Transmit Preemphasis Reg 2 */ +#define SATA_PHY_PRE3		0xf	/* PHY Transmit Preemphasis Reg 3 */ +#define SATA_SPDMODE		0x10	/* Speed Mode Reg */ +#define SATA_REFCLK		0x11	/* Reference Clock Control Reg */ +#define SATA_BYTE_SWAP_DIS	0x12	/* byte swap disable */ + +/*SATA_CTL Bits */ +#define SATA_RST_N		BIT(0) +#define PHY0_RESET_N		BIT(16) +#define PHY1_RESET_N		BIT(17) +#define PHY2_RESET_N		BIT(18) +#define PHY3_RESET_N		BIT(19) +#define M_CSYSREQ		BIT(2) +#define S_CSYSREQ		BIT(3) + +/*SATA_STATUS Bits */ +#define P0_PHY_READY		BIT(4) +#define P1_PHY_READY		BIT(5) +#define P2_PHY_READY		BIT(6) +#define P3_PHY_READY		BIT(7) + +#define nlm_read_sata_reg(b, r)		nlm_read_reg(b, r) +#define nlm_write_sata_reg(b, r, v)	nlm_write_reg(b, r, v) +#define nlm_get_sata_pcibase(node)	\ +		nlm_pcicfg_base(XLP_IO_SATA_OFFSET(node)) +/* SATA device specific configuration registers are starts at 0x900 offset */ +#define nlm_get_sata_regbase(node)	\ +		(nlm_get_sata_pcibase(node) + 0x900) + +static void sata_clear_glue_reg(uint64_t regbase, uint32_t off, uint32_t bit) +{ +	uint32_t reg_val; + +	reg_val = nlm_read_sata_reg(regbase, off); +	nlm_write_sata_reg(regbase, off, (reg_val & ~bit)); +} + +static void sata_set_glue_reg(uint64_t regbase, uint32_t off, uint32_t bit) +{ +	uint32_t reg_val; + +	reg_val = nlm_read_sata_reg(regbase, off); +	nlm_write_sata_reg(regbase, off, (reg_val | bit)); +} + +static void nlm_sata_firmware_init(int node) +{ +	uint32_t reg_val; +	uint64_t regbase; +	int i; + +	pr_info("XLP AHCI Initialization started.\n"); +	regbase = nlm_get_sata_regbase(node); + +	/* Reset SATA */ +	sata_clear_glue_reg(regbase, SATA_CTL, SATA_RST_N); +	/* Reset PHY */ +	sata_clear_glue_reg(regbase, SATA_CTL, +			(PHY3_RESET_N | PHY2_RESET_N +			 | PHY1_RESET_N | PHY0_RESET_N)); + +	/* Set SATA */ +	sata_set_glue_reg(regbase, SATA_CTL, SATA_RST_N); +	/* Set PHY */ +	sata_set_glue_reg(regbase, SATA_CTL, +			(PHY3_RESET_N | PHY2_RESET_N +			 | PHY1_RESET_N | PHY0_RESET_N)); + +	pr_debug("Waiting for PHYs to come up.\n"); +	i = 0; +	do { +		reg_val = nlm_read_sata_reg(regbase, SATA_STATUS); +		i++; +	} while (((reg_val & 0xF0) != 0xF0) && (i < 10000)); + +	for (i = 0; i < 4; i++) { +		if (reg_val  & (P0_PHY_READY << i)) +			pr_info("PHY%d is up.\n", i); +		else +			pr_info("PHY%d is down.\n", i); +	} + +	pr_info("XLP AHCI init done.\n"); +} + +static int __init nlm_ahci_init(void) +{ +	int node = 0; +	int chip = read_c0_prid() & PRID_REV_MASK; + +	if (chip == PRID_IMP_NETLOGIC_XLP3XX) +		nlm_sata_firmware_init(node); +	return 0; +} + +static void nlm_sata_intr_ack(struct irq_data *data) +{ +	uint32_t val = 0; +	uint64_t regbase; + +	regbase = nlm_get_sata_regbase(nlm_nodeid()); +	val = nlm_read_sata_reg(regbase, SATA_INT); +	sata_set_glue_reg(regbase, SATA_INT, val); +} + +static void nlm_sata_fixup_bar(struct pci_dev *dev) +{ +	/* +	 * The AHCI resource is in BAR 0, move it to +	 * BAR 5, where it is expected +	 */ +	dev->resource[5] = dev->resource[0]; +	memset(&dev->resource[0], 0, sizeof(dev->resource[0])); +} + +static void nlm_sata_fixup_final(struct pci_dev *dev) +{ +	uint32_t val; +	uint64_t regbase; +	int node = 0; /* XLP3XX does not support multi-node */ + +	regbase = nlm_get_sata_regbase(node); + +	/* clear pending interrupts and then enable them */ +	val = nlm_read_sata_reg(regbase, SATA_INT); +	sata_set_glue_reg(regbase, SATA_INT, val); + +	/* Mask the core interrupt. If all the interrupts +	 * are enabled there are spurious interrupt flow +	 * happening, to avoid only enable core interrupt +	 * mask. +	 */ +	sata_set_glue_reg(regbase, SATA_INT_MASK, 0x1); + +	dev->irq = PIC_SATA_IRQ; +	nlm_set_pic_extra_ack(node, PIC_SATA_IRQ, nlm_sata_intr_ack); +} + +arch_initcall(nlm_ahci_init); + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, +		nlm_sata_fixup_bar); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, +		nlm_sata_fixup_final); diff --git a/arch/mips/netlogic/xlp/dt.c b/arch/mips/netlogic/xlp/dt.c index 88df445dda7..7cc46032b28 100644 --- a/arch/mips/netlogic/xlp/dt.c +++ b/arch/mips/netlogic/xlp/dt.c @@ -39,13 +39,22 @@  #include <linux/of_platform.h>  #include <linux/of_device.h> +#include <asm/prom.h> +  extern u32 __dtb_xlp_evp_begin[], __dtb_xlp_svp_begin[], -	__dtb_xlp_fvp_begin[], __dtb_start[]; +	__dtb_xlp_fvp_begin[], __dtb_xlp_gvp_begin[]; +static void *xlp_fdt_blob;  void __init *xlp_dt_init(void *fdtp)  {  	if (!fdtp) { -		switch (current_cpu_data.processor_id & 0xff00) { +		switch (current_cpu_data.processor_id & PRID_IMP_MASK) { +#ifdef CONFIG_DT_XLP_GVP +		case PRID_IMP_NETLOGIC_XLP9XX: +		case PRID_IMP_NETLOGIC_XLP5XX: +			fdtp = __dtb_xlp_gvp_begin; +			break; +#endif  #ifdef CONFIG_DT_XLP_FVP  		case PRID_IMP_NETLOGIC_XLP2XX:  			fdtp = __dtb_xlp_fvp_begin; @@ -67,27 +76,19 @@ void __init *xlp_dt_init(void *fdtp)  			break;  		}  	} -	initial_boot_params = fdtp; +	xlp_fdt_blob = fdtp;  	return fdtp;  } -void __init device_tree_init(void) +void __init xlp_early_init_devtree(void)  { -	unsigned long base, size; - -	if (!initial_boot_params) -		return; - -	base = virt_to_phys((void *)initial_boot_params); -	size = be32_to_cpu(initial_boot_params->totalsize); - -	/* Before we do anything, lets reserve the dt blob */ -	reserve_bootmem(base, size, BOOTMEM_DEFAULT); - -	unflatten_device_tree(); +	__dt_setup_arch(xlp_fdt_blob); +	strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); +} -	/* free the space reserved for the dt blob */ -	free_bootmem(base, size); +void __init device_tree_init(void) +{ +	unflatten_and_copy_device_tree();  }  static struct of_device_id __initdata xlp_ids[] = { diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index 56c50ba43c9..bc24beb3a42 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -54,13 +54,47 @@ void nlm_node_init(int node)  	struct nlm_soc_info *nodep;  	nodep = nlm_get_node(node); +	if (node == 0) +		nodep->coremask = 1;	/* node 0, boot cpu */  	nodep->sysbase = nlm_get_sys_regbase(node);  	nodep->picbase = nlm_get_pic_regbase(node);  	nodep->ebase = read_c0_ebase() & (~((1 << 12) - 1)); +	if (cpu_is_xlp9xx()) +		nodep->socbus = xlp9xx_get_socbus(node); +	else +		nodep->socbus = 0;  	spin_lock_init(&nodep->piclock);  } -int nlm_irq_to_irt(int irq) +static int xlp9xx_irq_to_irt(int irq) +{ +	switch (irq) { +	case PIC_GPIO_IRQ: +		return 12; +	case PIC_9XX_XHCI_0_IRQ: +		return 114; +	case PIC_9XX_XHCI_1_IRQ: +		return 115; +	case PIC_UART_0_IRQ: +		return 133; +	case PIC_UART_1_IRQ: +		return 134; +	case PIC_SATA_IRQ: +		return 143; +	case PIC_SPI_IRQ: +		return 152; +	case PIC_MMC_IRQ: +		return 153; +	case PIC_PCIE_LINK_LEGACY_IRQ(0): +	case PIC_PCIE_LINK_LEGACY_IRQ(1): +	case PIC_PCIE_LINK_LEGACY_IRQ(2): +	case PIC_PCIE_LINK_LEGACY_IRQ(3): +		return 191 + irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE; +	} +	return -1; +} + +static int xlp_irq_to_irt(int irq)  {  	uint64_t pcibase;  	int devoff, irt; @@ -74,7 +108,7 @@ int nlm_irq_to_irt(int irq)  		devoff = XLP_IO_UART1_OFFSET(0);  		break;  	case PIC_MMC_IRQ: -		devoff = XLP_IO_SD_OFFSET(0); +		devoff = XLP_IO_MMC_OFFSET(0);  		break;  	case PIC_I2C_0_IRQ:	/* I2C will be fixed up */  	case PIC_I2C_1_IRQ: @@ -85,6 +119,18 @@ int nlm_irq_to_irt(int irq)  		else  			devoff = XLP_IO_I2C0_OFFSET(0);  		break; +	case PIC_SATA_IRQ: +		devoff = XLP_IO_SATA_OFFSET(0); +		break; +	case PIC_GPIO_IRQ: +		devoff = XLP_IO_GPIO_OFFSET(0); +		break; +	case PIC_NAND_IRQ: +		devoff = XLP_IO_NAND_OFFSET(0); +		break; +	case PIC_SPI_IRQ: +		devoff = XLP_IO_SPI_OFFSET(0); +		break;  	default:  		if (cpu_is_xlpii()) {  			switch (irq) { @@ -135,16 +181,78 @@ int nlm_irq_to_irt(int irq)  		case PIC_I2C_3_IRQ:  			irt = irt + 3; break;  		} -	} else if (irq >= PIC_PCIE_LINK_0_IRQ && irq <= PIC_PCIE_LINK_3_IRQ) { +	} else if (irq >= PIC_PCIE_LINK_LEGACY_IRQ(0) && +			irq <= PIC_PCIE_LINK_LEGACY_IRQ(3)) {  		/* HW bug, PCI IRT entries are bad on early silicon, fix */ -		irt = PIC_IRT_PCIE_LINK_INDEX(irq - PIC_PCIE_LINK_0_IRQ); +		irt = PIC_IRT_PCIE_LINK_INDEX(irq - +					PIC_PCIE_LINK_LEGACY_IRQ_BASE);  	} else {  		irt = -1;  	}  	return irt;  } -unsigned int nlm_get_core_frequency(int node, int core) +int nlm_irq_to_irt(int irq) +{ +	/* return -2 for irqs without 1-1 mapping */ +	if (irq >= PIC_PCIE_LINK_MSI_IRQ(0) && irq <= PIC_PCIE_LINK_MSI_IRQ(3)) +		return -2; +	if (irq >= PIC_PCIE_MSIX_IRQ(0) && irq <= PIC_PCIE_MSIX_IRQ(3)) +		return -2; + +	if (cpu_is_xlp9xx()) +		return xlp9xx_irq_to_irt(irq); +	else +		return xlp_irq_to_irt(irq); +} + +static unsigned int nlm_xlp2_get_core_frequency(int node, int core) +{ +	unsigned int pll_post_div, ctrl_val0, ctrl_val1, denom; +	uint64_t num, sysbase, clockbase; + +	if (cpu_is_xlp9xx()) { +		clockbase = nlm_get_clock_regbase(node); +		ctrl_val0 = nlm_read_sys_reg(clockbase, +					SYS_9XX_CPU_PLL_CTRL0(core)); +		ctrl_val1 = nlm_read_sys_reg(clockbase, +					SYS_9XX_CPU_PLL_CTRL1(core)); +	} else { +		sysbase = nlm_get_node(node)->sysbase; +		ctrl_val0 = nlm_read_sys_reg(sysbase, +						SYS_CPU_PLL_CTRL0(core)); +		ctrl_val1 = nlm_read_sys_reg(sysbase, +						SYS_CPU_PLL_CTRL1(core)); +	} + +	/* Find PLL post divider value */ +	switch ((ctrl_val0 >> 24) & 0x7) { +	case 1: +		pll_post_div = 2; +		break; +	case 3: +		pll_post_div = 4; +		break; +	case 7: +		pll_post_div = 8; +		break; +	case 6: +		pll_post_div = 16; +		break; +	case 0: +	default: +		pll_post_div = 1; +		break; +	} + +	num = 1000000ULL * (400 * 3 + 100 * (ctrl_val1 & 0x3f)); +	denom = 3 * pll_post_div; +	do_div(num, denom); + +	return (unsigned int)num; +} + +static unsigned int nlm_xlp_get_core_frequency(int node, int core)  {  	unsigned int pll_divf, pll_divr, dfs_div, ext_div;  	unsigned int rstval, dfsval, denom; @@ -152,38 +260,49 @@ unsigned int nlm_get_core_frequency(int node, int core)  	sysbase = nlm_get_node(node)->sysbase;  	rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG); -	if (cpu_is_xlpii()) { -		num = 1000000ULL * (400 * 3 + 100 * (rstval >> 26)); -		denom = 3; -	} else { -		dfsval = nlm_read_sys_reg(sysbase, 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; -	} +	dfsval = nlm_read_sys_reg(sysbase, 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;  } -/* Calculate Frequency to the PIC from PLL. - * freq_out = ( ref_freq/2 * (6 + ctrl2[7:0]) + ctrl2[20:8]/2^13 ) / - * ((2^ctrl0[7:5]) * Table(ctrl0[26:24])) +unsigned int nlm_get_core_frequency(int node, int core) +{ +	if (cpu_is_xlpii()) +		return nlm_xlp2_get_core_frequency(node, core); +	else +		return nlm_xlp_get_core_frequency(node, core); +} + +/* + * Calculate PIC frequency from PLL registers. + * freq_out = (ref_freq/2 * (6 + ctrl2[7:0]) + ctrl2[20:8]/2^13) / + * 		((2^ctrl0[7:5]) * Table(ctrl0[26:24]))   */ -static unsigned int nlm_2xx_get_pic_frequency(int node) +static unsigned int nlm_xlp2_get_pic_frequency(int node)  { -	u32 ctrl_val0, ctrl_val2, vco_post_div, pll_post_div; +	u32 ctrl_val0, ctrl_val2, vco_post_div, pll_post_div, cpu_xlp9xx;  	u32 mdiv, fdiv, pll_out_freq_den, reg_select, ref_div, pic_div; -	u64 ref_clk, sysbase, pll_out_freq_num, ref_clk_select; +	u64 sysbase, pll_out_freq_num, ref_clk_select, clockbase, ref_clk;  	sysbase = nlm_get_node(node)->sysbase; +	clockbase = nlm_get_clock_regbase(node); +	cpu_xlp9xx = cpu_is_xlp9xx();  	/* Find ref_clk_base */ -	ref_clk_select = -		(nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG) >> 18) & 0x3; +	if (cpu_xlp9xx) +		ref_clk_select = (nlm_read_sys_reg(sysbase, +				SYS_9XX_POWER_ON_RESET_CFG) >> 18) & 0x3; +	else +		ref_clk_select = (nlm_read_sys_reg(sysbase, +					SYS_POWER_ON_RESET_CFG) >> 18) & 0x3;  	switch (ref_clk_select) {  	case 0:  		ref_clk = 200000000ULL; @@ -204,30 +323,70 @@ static unsigned int nlm_2xx_get_pic_frequency(int node)  	}  	/* Find the clock source PLL device for PIC */ -	reg_select = (nlm_read_sys_reg(sysbase, SYS_CLK_DEV_SEL) >> 22) & 0x3; -	switch (reg_select) { -	case 0: -		ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0); -		ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2); -		break; -	case 1: -		ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(0)); -		ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(0)); -		break; -	case 2: -		ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(1)); -		ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(1)); -		break; -	case 3: -		ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(2)); -		ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(2)); -		break; +	if (cpu_xlp9xx) { +		reg_select = nlm_read_sys_reg(clockbase, +				SYS_9XX_CLK_DEV_SEL) & 0x3; +		switch (reg_select) { +		case 0: +			ctrl_val0 = nlm_read_sys_reg(clockbase, +					SYS_9XX_PLL_CTRL0); +			ctrl_val2 = nlm_read_sys_reg(clockbase, +					SYS_9XX_PLL_CTRL2); +			break; +		case 1: +			ctrl_val0 = nlm_read_sys_reg(clockbase, +					SYS_9XX_PLL_CTRL0_DEVX(0)); +			ctrl_val2 = nlm_read_sys_reg(clockbase, +					SYS_9XX_PLL_CTRL2_DEVX(0)); +			break; +		case 2: +			ctrl_val0 = nlm_read_sys_reg(clockbase, +					SYS_9XX_PLL_CTRL0_DEVX(1)); +			ctrl_val2 = nlm_read_sys_reg(clockbase, +					SYS_9XX_PLL_CTRL2_DEVX(1)); +			break; +		case 3: +			ctrl_val0 = nlm_read_sys_reg(clockbase, +					SYS_9XX_PLL_CTRL0_DEVX(2)); +			ctrl_val2 = nlm_read_sys_reg(clockbase, +					SYS_9XX_PLL_CTRL2_DEVX(2)); +			break; +		} +	} else { +		reg_select = (nlm_read_sys_reg(sysbase, +					SYS_CLK_DEV_SEL) >> 22) & 0x3; +		switch (reg_select) { +		case 0: +			ctrl_val0 = nlm_read_sys_reg(sysbase, +					SYS_PLL_CTRL0); +			ctrl_val2 = nlm_read_sys_reg(sysbase, +					SYS_PLL_CTRL2); +			break; +		case 1: +			ctrl_val0 = nlm_read_sys_reg(sysbase, +					SYS_PLL_CTRL0_DEVX(0)); +			ctrl_val2 = nlm_read_sys_reg(sysbase, +					SYS_PLL_CTRL2_DEVX(0)); +			break; +		case 2: +			ctrl_val0 = nlm_read_sys_reg(sysbase, +					SYS_PLL_CTRL0_DEVX(1)); +			ctrl_val2 = nlm_read_sys_reg(sysbase, +					SYS_PLL_CTRL2_DEVX(1)); +			break; +		case 3: +			ctrl_val0 = nlm_read_sys_reg(sysbase, +					SYS_PLL_CTRL0_DEVX(2)); +			ctrl_val2 = nlm_read_sys_reg(sysbase, +					SYS_PLL_CTRL2_DEVX(2)); +			break; +		}  	}  	vco_post_div = (ctrl_val0 >> 5) & 0x7;  	pll_post_div = (ctrl_val0 >> 24) & 0x7;  	mdiv = ctrl_val2 & 0xff; -	fdiv = (ctrl_val2 >> 8) & 0xfff; +	fdiv = (ctrl_val2 >> 8) & 0x1fff;  	/* Find PLL post divider value */  	switch (pll_post_div) { @@ -257,7 +416,12 @@ static unsigned int nlm_2xx_get_pic_frequency(int node)  		do_div(pll_out_freq_num, pll_out_freq_den);  	/* PIC post divider, which happens after PLL */ -	pic_div = (nlm_read_sys_reg(sysbase, SYS_CLK_DEV_DIV) >> 22) & 0x3; +	if (cpu_xlp9xx) +		pic_div = nlm_read_sys_reg(clockbase, +				SYS_9XX_CLK_DEV_DIV) & 0x3; +	else +		pic_div = (nlm_read_sys_reg(sysbase, +					SYS_CLK_DEV_DIV) >> 22) & 0x3;  	do_div(pll_out_freq_num, 1 << pic_div);  	return pll_out_freq_num; @@ -266,7 +430,7 @@ static unsigned int nlm_2xx_get_pic_frequency(int node)  unsigned int nlm_get_pic_frequency(int node)  {  	if (cpu_is_xlpii()) -		return nlm_2xx_get_pic_frequency(node); +		return nlm_xlp2_get_pic_frequency(node);  	else  		return 133333333;  } @@ -284,21 +448,33 @@ int xlp_get_dram_map(int n, uint64_t *dram_map)  {  	uint64_t bridgebase, base, lim;  	uint32_t val; +	unsigned int barreg, limreg, xlatreg;  	int i, node, rv;  	/* Look only at mapping on Node 0, we don't handle crazy configs */  	bridgebase = nlm_get_bridge_regbase(0);  	rv = 0;  	for (i = 0; i < 8; i++) { -		val = nlm_read_bridge_reg(bridgebase, -					BRIDGE_DRAM_NODE_TRANSLN(i)); -		node = (val >> 1) & 0x3; -		if (n >= 0 && n != node) -			continue; -		val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_BAR(i)); +		if (cpu_is_xlp9xx()) { +			barreg = BRIDGE_9XX_DRAM_BAR(i); +			limreg = BRIDGE_9XX_DRAM_LIMIT(i); +			xlatreg = BRIDGE_9XX_DRAM_NODE_TRANSLN(i); +		} else { +			barreg = BRIDGE_DRAM_BAR(i); +			limreg = BRIDGE_DRAM_LIMIT(i); +			xlatreg = BRIDGE_DRAM_NODE_TRANSLN(i); +		} +		if (n >= 0) { +			/* node specified, get node mapping of BAR */ +			val = nlm_read_bridge_reg(bridgebase, xlatreg); +			node = (val >> 1) & 0x3; +			if (n != node) +				continue; +		} +		val = nlm_read_bridge_reg(bridgebase, barreg);  		val = (val >>  12) & 0xfffff;  		base = (uint64_t) val << 20; -		val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_LIMIT(i)); +		val = nlm_read_bridge_reg(bridgebase, limreg);  		val = (val >>  12) & 0xfffff;  		if (val == 0)   /* BAR not used */  			continue; diff --git a/arch/mips/netlogic/xlp/setup.c b/arch/mips/netlogic/xlp/setup.c index 76a7131e486..4fdd9fd29d1 100644 --- a/arch/mips/netlogic/xlp/setup.c +++ b/arch/mips/netlogic/xlp/setup.c @@ -51,12 +51,16 @@ uint64_t nlm_io_base;  struct nlm_soc_info nlm_nodes[NLM_NR_NODES];  cpumask_t nlm_cpumask = CPU_MASK_CPU0;  unsigned int nlm_threads_per_core; +unsigned int xlp_cores_per_node;  static void nlm_linux_exit(void)  {  	uint64_t sysbase = nlm_get_node(0)->sysbase; -	nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1); +	if (cpu_is_xlp9xx()) +		nlm_write_sys_reg(sysbase, SYS_9XX_CHIP_RESET, 1); +	else +		nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1);  	for ( ; ; )  		cpu_wait();  } @@ -92,13 +96,20 @@ static void __init xlp_init_mem_from_bars(void)  void __init plat_mem_setup(void)  { -	panic_timeout	= 5; +#ifdef CONFIG_SMP +	nlm_wakeup_secondary_cpus(); + +	/* update TLB size after waking up threads */ +	current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1; + +	register_smp_ops(&nlm_smp_ops); +#endif  	_machine_restart = (void (*)(char *))nlm_linux_exit;  	_machine_halt	= nlm_linux_exit;  	pm_power_off	= nlm_linux_exit;  	/* memory and bootargs from DT */ -	early_init_devtree(initial_boot_params); +	xlp_early_init_devtree();  	if (boot_mem_map.nr_map == 0) {  		pr_info("Using DRAM BARs for memory map.\n"); @@ -110,7 +121,9 @@ void __init plat_mem_setup(void)  const char *get_system_type(void)  { -	switch (read_c0_prid() & 0xff00) { +	switch (read_c0_prid() & PRID_IMP_MASK) { +	case PRID_IMP_NETLOGIC_XLP9XX: +	case PRID_IMP_NETLOGIC_XLP5XX:  	case PRID_IMP_NETLOGIC_XLP2XX:  		return "Broadcom XLPII Series";  	default: @@ -150,6 +163,10 @@ void __init prom_init(void)  	void *reset_vec;  	nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE); +	if (cpu_is_xlp9xx()) +		xlp_cores_per_node = 32; +	else +		xlp_cores_per_node = 8;  	nlm_init_boot_cpu();  	xlp_mmu_init();  	nlm_node_init(0); @@ -163,11 +180,5 @@ void __init prom_init(void)  #ifdef CONFIG_SMP  	cpumask_setall(&nlm_cpumask); -	nlm_wakeup_secondary_cpus(); - -	/* update TLB size after waking up threads */ -	current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1; - -	register_smp_ops(&nlm_smp_ops);  #endif  } diff --git a/arch/mips/netlogic/xlp/usb-init-xlp2.c b/arch/mips/netlogic/xlp/usb-init-xlp2.c index 36e9c22afc4..17ade1ce5df 100644 --- a/arch/mips/netlogic/xlp/usb-init-xlp2.c +++ b/arch/mips/netlogic/xlp/usb-init-xlp2.c @@ -37,6 +37,7 @@  #include <linux/delay.h>  #include <linux/init.h>  #include <linux/pci.h> +#include <linux/pci_ids.h>  #include <linux/platform_device.h>  #include <linux/irq.h> @@ -83,12 +84,14 @@  #define nlm_read_usb_reg(b, r)		nlm_read_reg(b, r)  #define nlm_write_usb_reg(b, r, v)	nlm_write_reg(b, r, v) -#define nlm_xlpii_get_usb_pcibase(node, inst)		\ -	nlm_pcicfg_base(XLP2XX_IO_USB_OFFSET(node, inst)) +#define nlm_xlpii_get_usb_pcibase(node, inst)			\ +			nlm_pcicfg_base(cpu_is_xlp9xx() ?	\ +			XLP9XX_IO_USB_OFFSET(node, inst) :	\ +			XLP2XX_IO_USB_OFFSET(node, inst))  #define nlm_xlpii_get_usb_regbase(node, inst)		\  	(nlm_xlpii_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) -static void xlpii_usb_ack(struct irq_data *data) +static void xlp2xx_usb_ack(struct irq_data *data)  {  	u64 port_addr; @@ -109,6 +112,29 @@ static void xlpii_usb_ack(struct irq_data *data)  	nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff);  } +static void xlp9xx_usb_ack(struct irq_data *data) +{ +	u64 port_addr; +	int node, irq; + +	/* Find the node and irq on the node */ +	irq = data->irq % NLM_IRQS_PER_NODE; +	node = data->irq / NLM_IRQS_PER_NODE; + +	switch (irq) { +	case PIC_9XX_XHCI_0_IRQ: +		port_addr = nlm_xlpii_get_usb_regbase(node, 1); +		break; +	case PIC_9XX_XHCI_1_IRQ: +		port_addr = nlm_xlpii_get_usb_regbase(node, 2); +		break; +	default: +		pr_err("No matching USB irq %d node  %d!\n", irq, node); +		return; +	} +	nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff); +} +  static void nlm_xlpii_usb_hw_reset(int node, int port)  {  	u64 port_addr, xhci_base, pci_base; @@ -178,17 +204,33 @@ static void nlm_xlpii_usb_hw_reset(int node, int port)  static int __init nlm_platform_xlpii_usb_init(void)  { +	int node; +  	if (!cpu_is_xlpii())  		return 0; -	pr_info("Initializing 2XX USB Interface\n"); -	nlm_xlpii_usb_hw_reset(0, 1); -	nlm_xlpii_usb_hw_reset(0, 2); -	nlm_xlpii_usb_hw_reset(0, 3); -	nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_0_IRQ, xlpii_usb_ack); -	nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_1_IRQ, xlpii_usb_ack); -	nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_2_IRQ, xlpii_usb_ack); +	if (!cpu_is_xlp9xx()) { +		/* XLP 2XX single node */ +		pr_info("Initializing 2XX USB Interface\n"); +		nlm_xlpii_usb_hw_reset(0, 1); +		nlm_xlpii_usb_hw_reset(0, 2); +		nlm_xlpii_usb_hw_reset(0, 3); +		nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_0_IRQ, xlp2xx_usb_ack); +		nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_1_IRQ, xlp2xx_usb_ack); +		nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_2_IRQ, xlp2xx_usb_ack); +		return 0; +	} +	/* XLP 9XX, multi-node */ +	pr_info("Initializing 9XX USB Interface\n"); +	for (node = 0; node < NLM_NR_NODES; node++) { +		if (!nlm_node_present(node)) +			continue; +		nlm_xlpii_usb_hw_reset(node, 1); +		nlm_xlpii_usb_hw_reset(node, 2); +		nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_0_IRQ, xlp9xx_usb_ack); +		nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_1_IRQ, xlp9xx_usb_ack); +	}  	return 0;  } @@ -196,8 +238,26 @@ arch_initcall(nlm_platform_xlpii_usb_init);  static u64 xlp_usb_dmamask = ~(u32)0; -/* Fixup IRQ for USB devices on XLP the SoC PCIe bus */ -static void nlm_usb_fixup_final(struct pci_dev *dev) +/* Fixup the IRQ for USB devices which is exist on XLP9XX SOC PCIE bus */ +static void nlm_xlp9xx_usb_fixup_final(struct pci_dev *dev) +{ +	int node; + +	node = xlp_socdev_to_node(dev); +	dev->dev.dma_mask		= &xlp_usb_dmamask; +	dev->dev.coherent_dma_mask	= DMA_BIT_MASK(32); +	switch (dev->devfn) { +	case 0x21: +		dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_0_IRQ); +		break; +	case 0x22: +		dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_1_IRQ); +		break; +	} +} + +/* Fixup the IRQ for USB devices which is exist on XLP2XX SOC PCIE bus */ +static void nlm_xlp2xx_usb_fixup_final(struct pci_dev *dev)  {  	dev->dev.dma_mask		= &xlp_usb_dmamask;  	dev->dev.coherent_dma_mask	= DMA_BIT_MASK(32); @@ -214,5 +274,7 @@ static void nlm_usb_fixup_final(struct pci_dev *dev)  	}  } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_XHCI, +		nlm_xlp9xx_usb_fixup_final);  DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_XHCI, -		nlm_usb_fixup_final); +		nlm_xlp2xx_usb_fixup_final); diff --git a/arch/mips/netlogic/xlp/wakeup.c b/arch/mips/netlogic/xlp/wakeup.c index 682d5638dc0..e5f44d2605a 100644 --- a/arch/mips/netlogic/xlp/wakeup.c +++ b/arch/mips/netlogic/xlp/wakeup.c @@ -32,7 +32,6 @@   * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */ -#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/threads.h> @@ -47,14 +46,14 @@  #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/pic.h>  #include <asm/netlogic/xlp-hal/sys.h>  static int xlp_wakeup_core(uint64_t sysbase, int node, int core)  {  	uint32_t coremask, value; -	int count; +	int count, resetreg;  	coremask = (1 << core); @@ -65,12 +64,24 @@ static int xlp_wakeup_core(uint64_t sysbase, int node, int core)  		nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, value);  	} +	/* On 9XX, mark coherent first */ +	if (cpu_is_xlp9xx()) { +		value = nlm_read_sys_reg(sysbase, SYS_9XX_CPU_NONCOHERENT_MODE); +		value &= ~coremask; +		nlm_write_sys_reg(sysbase, SYS_9XX_CPU_NONCOHERENT_MODE, value); +	} +  	/* Remove CPU Reset */ -	value = nlm_read_sys_reg(sysbase, SYS_CPU_RESET); +	resetreg = cpu_is_xlp9xx() ? SYS_9XX_CPU_RESET : SYS_CPU_RESET; +	value = nlm_read_sys_reg(sysbase, resetreg);  	value &= ~coremask; -	nlm_write_sys_reg(sysbase, SYS_CPU_RESET, value); +	nlm_write_sys_reg(sysbase, resetreg, value); + +	/* We are done on 9XX */ +	if (cpu_is_xlp9xx()) +		return 1; -	/* Poll for CPU to mark itself coherent */ +	/* Poll for CPU to mark itself coherent on other type of XLP */  	count = 100000;  	do {  		value = nlm_read_sys_reg(sysbase, SYS_CPU_NONCOHERENT_MODE); @@ -84,7 +95,7 @@ static int wait_for_cpus(int cpu, int bootcpu)  	volatile uint32_t *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY);  	int i, count, notready; -	count = 0x20000000; +	count = 0x800000;  	do {  		notready = nlm_threads_per_core;  		for (i = 0; i < nlm_threads_per_core; i++) @@ -98,27 +109,66 @@ static int wait_for_cpus(int cpu, int bootcpu)  static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask)  {  	struct nlm_soc_info *nodep; -	uint64_t syspcibase; -	uint32_t syscoremask; +	uint64_t syspcibase, fusebase; +	uint32_t syscoremask, mask, fusemask;  	int core, n, cpu;  	for (n = 0; n < NLM_NR_NODES; n++) { -		syspcibase = nlm_get_sys_pcibase(n); -		if (nlm_read_reg(syspcibase, 0) == 0xffffffff) -			break; +		if (n != 0) { +			/* check if node exists and is online */ +			if (cpu_is_xlp9xx()) { +				int b = xlp9xx_get_socbus(n); +				pr_info("Node %d SoC PCI bus %d.\n", n, b); +				if (b == 0) +					break; +			} else { +				syspcibase = nlm_get_sys_pcibase(n); +				if (nlm_read_reg(syspcibase, 0) == 0xffffffff) +					break; +			} +			nlm_node_init(n); +		}  		/* read cores in reset from SYS */ -		if (n != 0) -			nlm_node_init(n);  		nodep = nlm_get_node(n); -		syscoremask = nlm_read_sys_reg(nodep->sysbase, SYS_CPU_RESET); -		/* The boot cpu */ -		if (n == 0) { -			syscoremask |= 1; -			nodep->coremask = 1; + +		if (cpu_is_xlp9xx()) { +			fusebase = nlm_get_fuse_regbase(n); +			fusemask = nlm_read_reg(fusebase, FUSE_9XX_DEVCFG6); +			switch (read_c0_prid() & PRID_IMP_MASK) { +			case PRID_IMP_NETLOGIC_XLP5XX: +				mask = 0xff; +				break; +			case PRID_IMP_NETLOGIC_XLP9XX: +			default: +				mask = 0xfffff; +				break; +			} +		} else { +			fusemask = nlm_read_sys_reg(nodep->sysbase, +						SYS_EFUSE_DEVICE_CFG_STATUS0); +			switch (read_c0_prid() & PRID_IMP_MASK) { +			case PRID_IMP_NETLOGIC_XLP3XX: +				mask = 0xf; +				break; +			case PRID_IMP_NETLOGIC_XLP2XX: +				mask = 0x3; +				break; +			case PRID_IMP_NETLOGIC_XLP8XX: +			default: +				mask = 0xff; +				break; +			}  		} -		for (core = 0; core < NLM_CORES_PER_NODE; core++) { +		/* +		 * Fused out cores are set in the fusemask, and the remaining +		 * cores are renumbered to range 0 .. nactive-1 +		 */ +		syscoremask = (1 << hweight32(~fusemask & mask)) - 1; + +		pr_info("Node %d - SYS/FUSE coremask %x\n", n, syscoremask); +		for (core = 0; core < nlm_cores_per_node(); core++) {  			/* we will be on node 0 core 0 */  			if (n == 0 && core == 0)  				continue; @@ -128,7 +178,7 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask)  				continue;  			/* see if at least the first hw thread is enabled */ -			cpu = (n * NLM_CORES_PER_NODE + core) +			cpu = (n * nlm_cores_per_node() + core)  						* NLM_THREADS_PER_CORE;  			if (!cpumask_test_cpu(cpu, wakeup_mask))  				continue; @@ -141,7 +191,8 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask)  			nodep->coremask |= 1u << core;  			/* spin until the hw threads sets their ready */ -			wait_for_cpus(cpu, 0); +			if (!wait_for_cpus(cpu, 0)) +				pr_err("Node %d : timeout core %d\n", n, core);  		}  	}  } @@ -153,7 +204,8 @@ void xlp_wakeup_secondary_cpus()  	 * first wakeup core 0 threads  	 */  	xlp_boot_core0_siblings(); -	wait_for_cpus(0, 0); +	if (!wait_for_cpus(0, 0)) +		pr_err("Node 0 : timeout core 0\n");  	/* now get other cores out of reset */  	xlp_enable_secondary_cores(&nlm_cpumask); diff --git a/arch/mips/netlogic/xlr/fmn-config.c b/arch/mips/netlogic/xlr/fmn-config.c index ed3bf0e3f30..c7622c6e5f6 100644 --- a/arch/mips/netlogic/xlr/fmn-config.c +++ b/arch/mips/netlogic/xlr/fmn-config.c @@ -36,6 +36,7 @@  #include <linux/irq.h>  #include <linux/interrupt.h> +#include <asm/cpu.h>  #include <asm/mipsregs.h>  #include <asm/netlogic/xlr/fmn.h>  #include <asm/netlogic/xlr/xlr.h> @@ -187,7 +188,7 @@ void xlr_board_info_setup(void)  	int processor_id, num_core;  	num_core = hweight32(nlm_current_node()->coremask); -	processor_id = read_c0_prid() & 0xff00; +	processor_id = read_c0_prid() & PRID_IMP_MASK;  	setup_cpu_fmninfo(cpu, num_core);  	switch (processor_id) { diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c index 7b96a91f477..4785932af24 100644 --- a/arch/mips/netlogic/xlr/platform.c +++ b/arch/mips/netlogic/xlr/platform.c @@ -23,7 +23,7 @@  #include <asm/netlogic/xlr/pic.h>  #include <asm/netlogic/xlr/xlr.h> -unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) +static unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset)  {  	uint64_t uartbase;  	unsigned int value; @@ -41,7 +41,7 @@ unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset)  	return value;  } -void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) +static void nlm_xlr_uart_out(struct uart_port *p, int offset, int value)  {  	uint64_t uartbase; diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c index 214d123b79f..d118b9aa764 100644 --- a/arch/mips/netlogic/xlr/setup.c +++ b/arch/mips/netlogic/xlr/setup.c @@ -60,25 +60,6 @@ unsigned int  nlm_threads_per_core = 1;  struct nlm_soc_info nlm_nodes[NLM_NR_NODES];  cpumask_t nlm_cpumask = CPU_MASK_CPU0; -static void __init nlm_early_serial_setup(void) -{ -	struct uart_port s; -	unsigned long uart_base; - -	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; -	s.regshift	= 2; -	s.irq		= PIC_UART_0_IRQ; -	s.uartclk	= PIC_CLK_HZ; -	s.serial_in	= nlm_xlr_uart_in; -	s.serial_out	= nlm_xlr_uart_out; -	s.mapbase	= uart_base; -	s.membase	= (unsigned char __iomem *)uart_base; -	early_serial_setup(&s); -} -  static void nlm_linux_exit(void)  {  	uint64_t gpiobase; @@ -92,7 +73,6 @@ static void nlm_linux_exit(void)  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; @@ -215,7 +195,6 @@ void __init prom_init(void)  	memcpy(reset_vec, (void *)nlm_reset_entry,  			(nlm_reset_entry_end - nlm_reset_entry)); -	nlm_early_serial_setup();  	build_arcs_cmdline(argv);  	prom_add_memory(); diff --git a/arch/mips/netlogic/xlr/wakeup.c b/arch/mips/netlogic/xlr/wakeup.c index 9fb81fa6272..d61cba1e9c6 100644 --- a/arch/mips/netlogic/xlr/wakeup.c +++ b/arch/mips/netlogic/xlr/wakeup.c @@ -32,7 +32,6 @@   * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   */ -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/threads.h> @@ -70,7 +69,7 @@ int xlr_wakeup_secondary_cpus(void)  	/* Fill up the coremask early */  	nodep->coremask = 1; -	for (i = 1; i < NLM_CORES_PER_NODE; i++) { +	for (i = 1; i < nlm_cores_per_node(); i++) {  		for (j = 1000000; j > 0; j--) {  			if (cpu_ready[i * NLM_THREADS_PER_CORE])  				break;  | 
