diff options
Diffstat (limited to 'arch/mips/netlogic/xlr')
| -rw-r--r-- | arch/mips/netlogic/xlr/Makefile | 2 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlr/fmn-config.c | 293 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlr/fmn.c | 204 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlr/platform-flash.c | 220 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlr/platform.c | 250 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlr/setup.c | 210 | ||||
| -rw-r--r-- | arch/mips/netlogic/xlr/wakeup.c | 85 | 
7 files changed, 1264 insertions, 0 deletions
diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile new file mode 100644 index 00000000000..05902bc6f08 --- /dev/null +++ b/arch/mips/netlogic/xlr/Makefile @@ -0,0 +1,2 @@ +obj-y			+=  fmn.o fmn-config.o setup.o platform.o platform-flash.o +obj-$(CONFIG_SMP)	+= wakeup.o diff --git a/arch/mips/netlogic/xlr/fmn-config.c b/arch/mips/netlogic/xlr/fmn-config.c new file mode 100644 index 00000000000..c7622c6e5f6 --- /dev/null +++ b/arch/mips/netlogic/xlr/fmn-config.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2003-2012 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 <asm/cpu-info.h> +#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> +#include <asm/netlogic/common.h> +#include <asm/netlogic/haldefs.h> + +struct xlr_board_fmn_config xlr_board_fmn_config; + +static void __maybe_unused print_credit_config(struct xlr_fmn_info *fmn_info) +{ +	int bkt; + +	pr_info("Bucket size :\n"); +	pr_info("Station\t: Size\n"); +	for (bkt = 0; bkt < 16; bkt++) +		pr_info(" %d  %d  %d  %d  %d  %d  %d %d\n", +			xlr_board_fmn_config.bucket_size[(bkt * 8) + 0], +			xlr_board_fmn_config.bucket_size[(bkt * 8) + 1], +			xlr_board_fmn_config.bucket_size[(bkt * 8) + 2], +			xlr_board_fmn_config.bucket_size[(bkt * 8) + 3], +			xlr_board_fmn_config.bucket_size[(bkt * 8) + 4], +			xlr_board_fmn_config.bucket_size[(bkt * 8) + 5], +			xlr_board_fmn_config.bucket_size[(bkt * 8) + 6], +			xlr_board_fmn_config.bucket_size[(bkt * 8) + 7]); +	pr_info("\n"); + +	pr_info("Credits distribution :\n"); +	pr_info("Station\t: Size\n"); +	for (bkt = 0; bkt < 16; bkt++) +		pr_info(" %d  %d  %d  %d  %d  %d  %d %d\n", +			fmn_info->credit_config[(bkt * 8) + 0], +			fmn_info->credit_config[(bkt * 8) + 1], +			fmn_info->credit_config[(bkt * 8) + 2], +			fmn_info->credit_config[(bkt * 8) + 3], +			fmn_info->credit_config[(bkt * 8) + 4], +			fmn_info->credit_config[(bkt * 8) + 5], +			fmn_info->credit_config[(bkt * 8) + 6], +			fmn_info->credit_config[(bkt * 8) + 7]); +	pr_info("\n"); +} + +static void check_credit_distribution(void) +{ +	struct xlr_board_fmn_config *cfg = &xlr_board_fmn_config; +	int bkt, n, total_credits, ncores; + +	ncores = hweight32(nlm_current_node()->coremask); +	for (bkt = 0; bkt < 128; bkt++) { +		total_credits = 0; +		for (n = 0; n < ncores; n++) +			total_credits += cfg->cpu[n].credit_config[bkt]; +		total_credits += cfg->gmac[0].credit_config[bkt]; +		total_credits += cfg->gmac[1].credit_config[bkt]; +		total_credits += cfg->dma.credit_config[bkt]; +		total_credits += cfg->cmp.credit_config[bkt]; +		total_credits += cfg->sae.credit_config[bkt]; +		total_credits += cfg->xgmac[0].credit_config[bkt]; +		total_credits += cfg->xgmac[1].credit_config[bkt]; +		if (total_credits > cfg->bucket_size[bkt]) +			pr_err("ERROR: Bucket %d: credits (%d) > size (%d)\n", +				bkt, total_credits, cfg->bucket_size[bkt]); +	} +	pr_info("Credit distribution complete.\n"); +} + +/** + * Configure bucket size and credits for a device. 'size' is the size of + * the buckets for the device. This size is distributed among all the CPUs + * so that all of them can send messages to the device. + * + * The device is also given 'cpu_credits' to send messages to the CPUs + * + * @dev_info: FMN information structure for each devices + * @start_stn_id: Starting station id of dev_info + * @end_stn_id: End station id of dev_info + * @num_buckets: Total number of buckets for den_info + * @cpu_credits: Allowed credits to cpu for each devices pointing by dev_info + * @size: Size of the each buckets in the device station + */ +static void setup_fmn_cc(struct xlr_fmn_info *dev_info, int start_stn_id, +		int end_stn_id, int num_buckets, int cpu_credits, int size) +{ +	int i, j, num_core, n, credits_per_cpu; +	struct xlr_fmn_info *cpu = xlr_board_fmn_config.cpu; + +	num_core = hweight32(nlm_current_node()->coremask); +	dev_info->num_buckets	= num_buckets; +	dev_info->start_stn_id	= start_stn_id; +	dev_info->end_stn_id	= end_stn_id; + +	n = num_core; +	if (num_core == 3) +		n = 4; + +	for (i = start_stn_id; i <= end_stn_id; i++) { +		xlr_board_fmn_config.bucket_size[i] = size; + +		/* Dividing device credits equally to cpus */ +		credits_per_cpu = size / n; +		for (j = 0; j < num_core; j++) +			cpu[j].credit_config[i] = credits_per_cpu; + +		/* credits left to distribute */ +		credits_per_cpu = size - (credits_per_cpu * num_core); + +		/* distribute the remaining credits (if any), among cores */ +		for (j = 0; (j < num_core) && (credits_per_cpu >= 4); j++) { +			cpu[j].credit_config[i] += 4; +			credits_per_cpu -= 4; +		} +	} + +	/* Distributing cpu per bucket credits to devices */ +	for (i = 0; i < num_core; i++) { +		for (j = 0; j < FMN_CORE_NBUCKETS; j++) +			dev_info->credit_config[(i * 8) + j] = cpu_credits; +	} +} + +/* + * Each core has 256 slots and 8 buckets, + * Configure the 8 buckets each with 32 slots + */ +static void setup_cpu_fmninfo(struct xlr_fmn_info *cpu, int num_core) +{ +	int i, j; + +	for (i = 0; i < num_core; i++) { +		cpu[i].start_stn_id	= (8 * i); +		cpu[i].end_stn_id	= (8 * i + 8); + +		for (j = cpu[i].start_stn_id; j < cpu[i].end_stn_id; j++) +			xlr_board_fmn_config.bucket_size[j] = 32; +	} +} + +/** + * Setup the FMN details for each devices according to the device available + * in each variant of XLR/XLS processor + */ +void xlr_board_info_setup(void) +{ +	struct xlr_fmn_info *cpu = xlr_board_fmn_config.cpu; +	struct xlr_fmn_info *gmac = xlr_board_fmn_config.gmac; +	struct xlr_fmn_info *xgmac = xlr_board_fmn_config.xgmac; +	struct xlr_fmn_info *dma = &xlr_board_fmn_config.dma; +	struct xlr_fmn_info *cmp = &xlr_board_fmn_config.cmp; +	struct xlr_fmn_info *sae = &xlr_board_fmn_config.sae; +	int processor_id, num_core; + +	num_core = hweight32(nlm_current_node()->coremask); +	processor_id = read_c0_prid() & PRID_IMP_MASK; + +	setup_cpu_fmninfo(cpu, num_core); +	switch (processor_id) { +	case PRID_IMP_NETLOGIC_XLS104: +	case PRID_IMP_NETLOGIC_XLS108: +		setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, +					FMN_STNID_GMAC0_TX3, 8, 16, 32); +		setup_fmn_cc(dma, FMN_STNID_DMA_0, +					FMN_STNID_DMA_3, 4, 8, 64); +		setup_fmn_cc(sae, FMN_STNID_SEC0, +					FMN_STNID_SEC1, 2, 8, 128); +		break; + +	case PRID_IMP_NETLOGIC_XLS204: +	case PRID_IMP_NETLOGIC_XLS208: +		setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, +					FMN_STNID_GMAC0_TX3, 8, 16, 32); +		setup_fmn_cc(dma, FMN_STNID_DMA_0, +					FMN_STNID_DMA_3, 4, 8, 64); +		setup_fmn_cc(sae, FMN_STNID_SEC0, +					FMN_STNID_SEC1, 2, 8, 128); +		break; + +	case PRID_IMP_NETLOGIC_XLS404: +	case PRID_IMP_NETLOGIC_XLS408: +	case PRID_IMP_NETLOGIC_XLS404B: +	case PRID_IMP_NETLOGIC_XLS408B: +	case PRID_IMP_NETLOGIC_XLS416B: +	case PRID_IMP_NETLOGIC_XLS608B: +	case PRID_IMP_NETLOGIC_XLS616B: +		setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, +					FMN_STNID_GMAC0_TX3, 8, 8, 32); +		setup_fmn_cc(&gmac[1], FMN_STNID_GMAC1_FR_0, +					FMN_STNID_GMAC1_TX3, 8, 8, 32); +		setup_fmn_cc(dma, FMN_STNID_DMA_0, +					FMN_STNID_DMA_3, 4, 4, 64); +		setup_fmn_cc(cmp, FMN_STNID_CMP_0, +					FMN_STNID_CMP_3, 4, 4, 64); +		setup_fmn_cc(sae, FMN_STNID_SEC0, +					FMN_STNID_SEC1, 2, 8, 128); +		break; + +	case PRID_IMP_NETLOGIC_XLS412B: +		setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, +					FMN_STNID_GMAC0_TX3, 8, 8, 32); +		setup_fmn_cc(&gmac[1], FMN_STNID_GMAC1_FR_0, +					FMN_STNID_GMAC1_TX3, 8, 8, 32); +		setup_fmn_cc(dma, FMN_STNID_DMA_0, +					FMN_STNID_DMA_3, 4, 4, 64); +		setup_fmn_cc(cmp, FMN_STNID_CMP_0, +					FMN_STNID_CMP_3, 4, 4, 64); +		setup_fmn_cc(sae, FMN_STNID_SEC0, +					FMN_STNID_SEC1, 2, 8, 128); +		break; + +	case PRID_IMP_NETLOGIC_XLR308: +	case PRID_IMP_NETLOGIC_XLR308C: +		setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, +					FMN_STNID_GMAC0_TX3, 8, 16, 32); +		setup_fmn_cc(dma, FMN_STNID_DMA_0, +					FMN_STNID_DMA_3, 4, 8, 64); +		setup_fmn_cc(sae, FMN_STNID_SEC0, +					FMN_STNID_SEC1, 2, 4, 128); +		break; + +	case PRID_IMP_NETLOGIC_XLR532: +	case PRID_IMP_NETLOGIC_XLR532C: +	case PRID_IMP_NETLOGIC_XLR516C: +	case PRID_IMP_NETLOGIC_XLR508C: +		setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, +					FMN_STNID_GMAC0_TX3, 8, 16, 32); +		setup_fmn_cc(dma, FMN_STNID_DMA_0, +					FMN_STNID_DMA_3, 4, 8, 64); +		setup_fmn_cc(sae, FMN_STNID_SEC0, +					FMN_STNID_SEC1, 2, 4, 128); +		break; + +	case PRID_IMP_NETLOGIC_XLR732: +	case PRID_IMP_NETLOGIC_XLR716: +		setup_fmn_cc(&xgmac[0], FMN_STNID_XMAC0_00_TX, +					FMN_STNID_XMAC0_15_TX, 8, 0, 32); +		setup_fmn_cc(&xgmac[1], FMN_STNID_XMAC1_00_TX, +					FMN_STNID_XMAC1_15_TX, 8, 0, 32); +		setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, +					FMN_STNID_GMAC0_TX3, 8, 24, 32); +		setup_fmn_cc(dma, FMN_STNID_DMA_0, +					FMN_STNID_DMA_3, 4, 4, 64); +		setup_fmn_cc(sae, FMN_STNID_SEC0, +					FMN_STNID_SEC1, 2, 4, 128); +		break; +	default: +		pr_err("Unknown CPU with processor ID [%d]\n", processor_id); +		pr_err("Error: Cannot initialize FMN credits.\n"); +	} + +	check_credit_distribution(); + +#if 0 /* debug */ +	print_credit_config(&cpu[0]); +	print_credit_config(&gmac[0]); +#endif +} diff --git a/arch/mips/netlogic/xlr/fmn.c b/arch/mips/netlogic/xlr/fmn.c new file mode 100644 index 00000000000..d428e8471ee --- /dev/null +++ b/arch/mips/netlogic/xlr/fmn.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2003-2012 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/kernel.h> +#include <linux/irqreturn.h> +#include <linux/irq.h> +#include <linux/interrupt.h> + +#include <asm/mipsregs.h> +#include <asm/netlogic/interrupt.h> +#include <asm/netlogic/xlr/fmn.h> +#include <asm/netlogic/common.h> + +#define COP2_CC_INIT_CPU_DEST(dest, conf) \ +do { \ +	nlm_write_c2_cc##dest(0, conf[(dest * 8) + 0]); \ +	nlm_write_c2_cc##dest(1, conf[(dest * 8) + 1]); \ +	nlm_write_c2_cc##dest(2, conf[(dest * 8) + 2]); \ +	nlm_write_c2_cc##dest(3, conf[(dest * 8) + 3]); \ +	nlm_write_c2_cc##dest(4, conf[(dest * 8) + 4]); \ +	nlm_write_c2_cc##dest(5, conf[(dest * 8) + 5]); \ +	nlm_write_c2_cc##dest(6, conf[(dest * 8) + 6]); \ +	nlm_write_c2_cc##dest(7, conf[(dest * 8) + 7]); \ +} while (0) + +struct fmn_message_handler { +	void (*action)(int, int, int, int, struct nlm_fmn_msg *, void *); +	void *arg; +} msg_handlers[128]; + +/* + * FMN interrupt handler. We configure the FMN so that any messages in + * any of the CPU buckets will trigger an interrupt on the CPU. + * The message can be from any device on the FMN (like NAE/SAE/DMA). + * The source station id is used to figure out which of the registered + * handlers have to be called. + */ +static irqreturn_t fmn_message_handler(int irq, void *data) +{ +	struct fmn_message_handler *hndlr; +	int bucket, rv; +	int size = 0, code = 0, src_stnid = 0; +	struct nlm_fmn_msg msg; +	uint32_t mflags, bkt_status; + +	mflags = nlm_cop2_enable_irqsave(); +	/* Disable message ring interrupt */ +	nlm_fmn_setup_intr(irq, 0); +	while (1) { +		/* 8 bkts per core, [24:31] each bit represents one bucket +		 * Bit is Zero if bucket is not empty */ +		bkt_status = (nlm_read_c2_status0() >> 24) & 0xff; +		if (bkt_status == 0xff) +			break; +		for (bucket = 0; bucket < 8; bucket++) { +			/* Continue on empty bucket */ +			if (bkt_status & (1 << bucket)) +				continue; +			rv = nlm_fmn_receive(bucket, &size, &code, &src_stnid, +						&msg); +			if (rv != 0) +				continue; + +			hndlr = &msg_handlers[src_stnid]; +			if (hndlr->action == NULL) +				pr_warn("No msgring handler for stnid %d\n", +						src_stnid); +			else { +				nlm_cop2_disable_irqrestore(mflags); +				hndlr->action(bucket, src_stnid, size, code, +					&msg, hndlr->arg); +				mflags = nlm_cop2_enable_irqsave(); +			} +		} +	}; +	/* Enable message ring intr, to any thread in core */ +	nlm_fmn_setup_intr(irq, (1 << nlm_threads_per_core) - 1); +	nlm_cop2_disable_irqrestore(mflags); +	return IRQ_HANDLED; +} + +struct irqaction fmn_irqaction = { +	.handler = fmn_message_handler, +	.flags = IRQF_PERCPU, +	.name = "fmn", +}; + +void xlr_percpu_fmn_init(void) +{ +	struct xlr_fmn_info *cpu_fmn_info; +	int *bucket_sizes; +	uint32_t flags; +	int id; + +	BUG_ON(nlm_thread_id() != 0); +	id = nlm_core_id(); + +	bucket_sizes = xlr_board_fmn_config.bucket_size; +	cpu_fmn_info = &xlr_board_fmn_config.cpu[id]; +	flags = nlm_cop2_enable_irqsave(); + +	/* Setup bucket sizes for the core. */ +	nlm_write_c2_bucksize(0, bucket_sizes[id * 8 + 0]); +	nlm_write_c2_bucksize(1, bucket_sizes[id * 8 + 1]); +	nlm_write_c2_bucksize(2, bucket_sizes[id * 8 + 2]); +	nlm_write_c2_bucksize(3, bucket_sizes[id * 8 + 3]); +	nlm_write_c2_bucksize(4, bucket_sizes[id * 8 + 4]); +	nlm_write_c2_bucksize(5, bucket_sizes[id * 8 + 5]); +	nlm_write_c2_bucksize(6, bucket_sizes[id * 8 + 6]); +	nlm_write_c2_bucksize(7, bucket_sizes[id * 8 + 7]); + +	/* +	 * For sending FMN messages, we need credits on the destination +	 * bucket. Program the credits this core has on the 128 possible +	 * destination buckets. +	 * We cannot use a loop here, because the the first argument has +	 * to be a constant integer value. +	 */ +	COP2_CC_INIT_CPU_DEST(0, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(1, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(2, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(3, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(4, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(5, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(6, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(7, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(8, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(9, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(10, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(11, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(12, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(13, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(14, cpu_fmn_info->credit_config); +	COP2_CC_INIT_CPU_DEST(15, cpu_fmn_info->credit_config); + +	/* enable FMN interrupts on this CPU */ +	nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1); +	nlm_cop2_disable_irqrestore(flags); +} + + +/* + * Register a FMN message handler with respect to the source station id + * @stnid: source station id + * @action: Handler function pointer + */ +int nlm_register_fmn_handler(int start_stnid, int end_stnid, +	void (*action)(int, int, int, int, struct nlm_fmn_msg *, void *), +	void *arg) +{ +	int sstnid; + +	for (sstnid = start_stnid; sstnid <= end_stnid; sstnid++) { +		msg_handlers[sstnid].arg = arg; +		smp_wmb(); +		msg_handlers[sstnid].action = action; +	} +	pr_debug("Registered FMN msg handler for stnid %d-%d\n", +			start_stnid, end_stnid); +	return 0; +} + +void nlm_setup_fmn_irq(void) +{ +	uint32_t flags; + +	/* setup irq only once */ +	setup_irq(IRQ_FMN, &fmn_irqaction); + +	flags = nlm_cop2_enable_irqsave(); +	nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1); +	nlm_cop2_disable_irqrestore(flags); +} diff --git a/arch/mips/netlogic/xlr/platform-flash.c b/arch/mips/netlogic/xlr/platform-flash.c new file mode 100644 index 00000000000..6d3c727e0ef --- /dev/null +++ b/arch/mips/netlogic/xlr/platform-flash.c @@ -0,0 +1,220 @@ +/* + * Copyright 2011, Netlogic Microsystems. + * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/resource.h> +#include <linux/spi/flash.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/physmap.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/xlr/iomap.h> +#include <asm/netlogic/xlr/flash.h> +#include <asm/netlogic/xlr/bridge.h> +#include <asm/netlogic/xlr/gpio.h> +#include <asm/netlogic/xlr/xlr.h> + +/* + * Default NOR partition layout + */ +static struct mtd_partition xlr_nor_parts[] = { +	{ +		.name = "User FS", +		.offset = 0x800000, +		.size	= MTDPART_SIZ_FULL, +	} +}; + +/* + * Default NAND partition layout + */ +static struct mtd_partition xlr_nand_parts[] = { +	{ +		.name	= "Root Filesystem", +		.offset = 64 * 64 * 2048, +		.size	= 432 * 64 * 2048, +	}, +	{ +		.name	= "Home Filesystem", +		.offset = MTDPART_OFS_APPEND, +		.size	= MTDPART_SIZ_FULL, +	}, +}; + +/* Use PHYSMAP flash for NOR */ +struct physmap_flash_data xlr_nor_data = { +	.width		= 2, +	.parts		= xlr_nor_parts, +	.nr_parts	= ARRAY_SIZE(xlr_nor_parts), +}; + +static struct resource xlr_nor_res[] = { +	{ +		.flags	= IORESOURCE_MEM, +	}, +}; + +static struct platform_device xlr_nor_dev = { +	.name	= "physmap-flash", +	.dev	= { +		.platform_data	= &xlr_nor_data, +	}, +	.num_resources	= ARRAY_SIZE(xlr_nor_res), +	.resource	= xlr_nor_res, +}; + +const char *xlr_part_probes[] = { "cmdlinepart", NULL }; + +/* + * Use "gen_nand" driver for NAND flash + * + * There seems to be no way to store a private pointer containing + * platform specific info in gen_nand drivier. We will use a global + * struct for now, since we currently have only one NAND chip per board. + */ +struct xlr_nand_flash_priv { +	int cs; +	uint64_t flash_mmio; +}; + +static struct xlr_nand_flash_priv nand_priv; + +static void xlr_nand_ctrl(struct mtd_info *mtd, int cmd, +		unsigned int ctrl) +{ +	if (ctrl & NAND_CLE) +		nlm_write_reg(nand_priv.flash_mmio, +			FLASH_NAND_CLE(nand_priv.cs), cmd); +	else if (ctrl & NAND_ALE) +		nlm_write_reg(nand_priv.flash_mmio, +			FLASH_NAND_ALE(nand_priv.cs), cmd); +} + +struct platform_nand_data xlr_nand_data = { +	.chip = { +		.nr_chips	= 1, +		.nr_partitions	= ARRAY_SIZE(xlr_nand_parts), +		.chip_delay	= 50, +		.partitions	= xlr_nand_parts, +		.part_probe_types = xlr_part_probes, +	}, +	.ctrl = { +		.cmd_ctrl	= xlr_nand_ctrl, +	}, +}; + +static struct resource xlr_nand_res[] = { +	{ +		.flags		= IORESOURCE_MEM, +	}, +}; + +static struct platform_device xlr_nand_dev = { +	.name		= "gen_nand", +	.id		= -1, +	.num_resources	= ARRAY_SIZE(xlr_nand_res), +	.resource	= xlr_nand_res, +	.dev		= { +		.platform_data	= &xlr_nand_data, +	} +}; + +/* + * XLR/XLS supports upto 8 devices on its FLASH interface. The value in + * FLASH_BAR (on the MEM/IO bridge) gives the base for mapping all the + * flash devices. + * Under this, each flash device has an offset and size given by the + * CSBASE_ADDR and CSBASE_MASK registers for the device. + * + * The CSBASE_ registers are expected to be setup by the bootloader. + */ +static void setup_flash_resource(uint64_t flash_mmio, +	uint64_t flash_map_base, int cs, struct resource *res) +{ +	u32 base, mask; + +	base = nlm_read_reg(flash_mmio, FLASH_CSBASE_ADDR(cs)); +	mask = nlm_read_reg(flash_mmio, FLASH_CSADDR_MASK(cs)); + +	res->start = flash_map_base + ((unsigned long)base << 16); +	res->end = res->start + (mask + 1) * 64 * 1024; +} + +static int __init xlr_flash_init(void) +{ +	uint64_t gpio_mmio, flash_mmio, flash_map_base; +	u32 gpio_resetcfg, flash_bar; +	int cs, boot_nand, boot_nor; + +	/* Flash address bits 39:24 is in bridge flash BAR */ +	flash_bar = nlm_read_reg(nlm_io_base, BRIDGE_FLASH_BAR); +	flash_map_base = (flash_bar & 0xffff0000) << 8; + +	gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); +	flash_mmio = nlm_mmio_base(NETLOGIC_IO_FLASH_OFFSET); + +	/* Get the chip reset config */ +	gpio_resetcfg = nlm_read_reg(gpio_mmio, GPIO_PWRON_RESET_CFG_REG); + +	/* Check for boot flash type */ +	boot_nor = boot_nand = 0; +	if (nlm_chip_is_xls()) { +		/* On XLS, check boot from NAND bit (GPIO reset reg bit 16) */ +		if (gpio_resetcfg & (1 << 16)) +			boot_nand = 1; + +		/* check boot from PCMCIA, (GPIO reset reg bit 15 */ +		if ((gpio_resetcfg & (1 << 15)) == 0) +			boot_nor = 1;	/* not set, booted from NOR */ +	} else { /* XLR */ +		/* check boot from PCMCIA (bit 16 in GPIO reset on XLR) */ +		if ((gpio_resetcfg & (1 << 16)) == 0) +			boot_nor = 1;	/* not set, booted from NOR */ +	} + +	/* boot flash at chip select 0 */ +	cs = 0; + +	if (boot_nand) { +		nand_priv.cs = cs; +		nand_priv.flash_mmio = flash_mmio; +		setup_flash_resource(flash_mmio, flash_map_base, cs, +			 xlr_nand_res); + +		/* Initialize NAND flash at CS 0 */ +		nlm_write_reg(flash_mmio, FLASH_CSDEV_PARM(cs), +				FLASH_NAND_CSDEV_PARAM); +		nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMA(cs), +				FLASH_NAND_CSTIME_PARAMA); +		nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMB(cs), +				FLASH_NAND_CSTIME_PARAMB); + +		pr_info("ChipSelect %d: NAND Flash %pR\n", cs, xlr_nand_res); +		return platform_device_register(&xlr_nand_dev); +	} + +	if (boot_nor) { +		setup_flash_resource(flash_mmio, flash_map_base, cs, +			xlr_nor_res); +		pr_info("ChipSelect %d: NOR Flash %pR\n", cs, xlr_nor_res); +		return platform_device_register(&xlr_nor_dev); +	} +	return 0; +} + +arch_initcall(xlr_flash_init); diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c new file mode 100644 index 00000000000..4785932af24 --- /dev/null +++ b/arch/mips/netlogic/xlr/platform.c @@ -0,0 +1,250 @@ +/* + * Copyright 2011, Netlogic Microsystems. + * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/resource.h> +#include <linux/serial_8250.h> +#include <linux/serial_reg.h> +#include <linux/i2c.h> +#include <linux/usb/ehci_pdriver.h> +#include <linux/usb/ohci_pdriver.h> + +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/xlr/iomap.h> +#include <asm/netlogic/xlr/pic.h> +#include <asm/netlogic/xlr/xlr.h> + +static unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) +{ +	uint64_t uartbase; +	unsigned int value; + +	/* 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) +		value ^= 0xF0; +	else if (offset == UART_MCR) +		value ^= 0x3; + +	return value; +} + +static void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) +{ +	uint64_t uartbase; + +	/* sign extend to 64 bits, if needed */ +	uartbase = (uint64_t)(long)p->membase; + +	/* See XLR/XLS errata */ +	if (offset == UART_MSR) +		value ^= 0xF0; +	else if (offset == UART_MCR) +		value ^= 0x3; + +	nlm_write_reg(uartbase, offset, value); +} + +#define PORT(_irq)					\ +	{						\ +		.irq		= _irq,			\ +		.regshift	= 2,			\ +		.iotype		= UPIO_MEM32,		\ +		.flags		= (UPF_SKIP_TEST |	\ +			 UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF),\ +		.uartclk	= PIC_CLK_HZ,		\ +		.type		= PORT_16550A,		\ +		.serial_in	= nlm_xlr_uart_in,	\ +		.serial_out	= nlm_xlr_uart_out,	\ +	} + +static struct plat_serial8250_port xlr_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 = xlr_uart_data, +	}, +}; + +static int __init nlm_uart_init(void) +{ +	unsigned long uartbase; + +	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); + +	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); +} + +arch_initcall(nlm_uart_init); + +#ifdef CONFIG_USB +/* Platform USB devices, only on XLS chips */ +static u64 xls_usb_dmamask = ~(u32)0; +#define USB_PLATFORM_DEV(n, i, irq)					\ +	{								\ +		.name		= n,					\ +		.id		= i,					\ +		.num_resources	= 2,					\ +		.dev		= {					\ +			.dma_mask	= &xls_usb_dmamask,		\ +			.coherent_dma_mask = 0xffffffff,		\ +		},							\ +		.resource	= (struct resource[]) {			\ +			{						\ +				.flags = IORESOURCE_MEM,		\ +			},						\ +			{						\ +				.start	= irq,				\ +				.end	= irq,				\ +				.flags = IORESOURCE_IRQ,		\ +			},						\ +		},							\ +	} + +static struct usb_ehci_pdata xls_usb_ehci_pdata = { +	.caps_offset	= 0, +}; + +static struct usb_ohci_pdata xls_usb_ohci_pdata; + +static struct platform_device xls_usb_ehci_device = +			 USB_PLATFORM_DEV("ehci-platform", 0, PIC_USB_IRQ); +static struct platform_device xls_usb_ohci_device_0 = +			 USB_PLATFORM_DEV("ohci-platform", 1, PIC_USB_IRQ); +static struct platform_device xls_usb_ohci_device_1 = +			 USB_PLATFORM_DEV("ohci-platform", 2, PIC_USB_IRQ); + +static struct platform_device *xls_platform_devices[] = { +	&xls_usb_ehci_device, +	&xls_usb_ohci_device_0, +	&xls_usb_ohci_device_1, +}; + +int xls_platform_usb_init(void) +{ +	uint64_t usb_mmio, gpio_mmio; +	unsigned long memres; +	uint32_t val; + +	if (!nlm_chip_is_xls()) +		return 0; + +	gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); +	usb_mmio  = nlm_mmio_base(NETLOGIC_IO_USB_1_OFFSET); + +	/* Clear Rogue Phy INTs */ +	nlm_write_reg(usb_mmio, 49, 0x10000000); +	/* Enable all interrupts */ +	nlm_write_reg(usb_mmio, 50, 0x1f000000); + +	/* Enable ports */ +	nlm_write_reg(usb_mmio,	 1, 0x07000500); + +	val = nlm_read_reg(gpio_mmio, 21); +	if (((val >> 22) & 0x01) == 0) { +		pr_info("Detected USB Device mode - Not supported!\n"); +		nlm_write_reg(usb_mmio,	 0, 0x01000000); +		return 0; +	} + +	pr_info("Detected USB Host mode - Adding XLS USB devices.\n"); +	/* Clear reset, host mode */ +	nlm_write_reg(usb_mmio,	 0, 0x02000000); + +	/* Memory resource for various XLS usb ports */ +	usb_mmio = nlm_mmio_base(NETLOGIC_IO_USB_0_OFFSET); +	memres = CPHYSADDR((unsigned long)usb_mmio); +	xls_usb_ehci_device.resource[0].start = memres; +	xls_usb_ehci_device.resource[0].end = memres + 0x400 - 1; +	xls_usb_ehci_device.dev.platform_data = &xls_usb_ehci_pdata; + +	memres += 0x400; +	xls_usb_ohci_device_0.resource[0].start = memres; +	xls_usb_ohci_device_0.resource[0].end = memres + 0x400 - 1; +	xls_usb_ohci_device_0.dev.platform_data = &xls_usb_ohci_pdata; + +	memres += 0x400; +	xls_usb_ohci_device_1.resource[0].start = memres; +	xls_usb_ohci_device_1.resource[0].end = memres + 0x400 - 1; +	xls_usb_ohci_device_1.dev.platform_data = &xls_usb_ohci_pdata; + +	return platform_add_devices(xls_platform_devices, +				ARRAY_SIZE(xls_platform_devices)); +} + +arch_initcall(xls_platform_usb_init); +#endif + +#ifdef CONFIG_I2C +static struct i2c_board_info nlm_i2c_board_info1[] __initdata = { +	/* All XLR boards have this RTC and Max6657 Temp Chip */ +	[0] = { +		.type	= "ds1374", +		.addr	= 0x68 +	}, +	[1] = { +		.type	= "lm90", +		.addr	= 0x4c +	}, +}; + +static struct resource i2c_resources[] = { +	[0] = { +		.start	= 0,	/* filled at init */ +		.end	= 0, +		.flags	= IORESOURCE_MEM, +	}, +}; + +static struct platform_device nlm_xlr_i2c_1 = { +	.name		= "xlr-i2cbus", +	.id		= 1, +	.num_resources	= 1, +	.resource	= i2c_resources, +}; + +static int __init nlm_i2c_init(void) +{ +	int err = 0; +	unsigned int offset; + +	/* I2C bus 0 does not have any useful devices, configure only bus 1 */ +	offset = NETLOGIC_IO_I2C_1_OFFSET; +	nlm_xlr_i2c_1.resource[0].start = CPHYSADDR(nlm_mmio_base(offset)); +	nlm_xlr_i2c_1.resource[0].end = nlm_xlr_i2c_1.resource[0].start + 0xfff; + +	platform_device_register(&nlm_xlr_i2c_1); + +	err = i2c_register_board_info(1, nlm_i2c_board_info1, +				ARRAY_SIZE(nlm_i2c_board_info1)); +	if (err < 0) +		pr_err("nlm-i2c: cannot register board I2C devices\n"); +	return err; +} + +arch_initcall(nlm_i2c_init); +#endif diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c new file mode 100644 index 00000000000..d118b9aa764 --- /dev/null +++ b/arch/mips/netlogic/xlr/setup.c @@ -0,0 +1,210 @@ +/* + * 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/idle.h> +#include <asm/reboot.h> +#include <asm/time.h> +#include <asm/bootinfo.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> +#include <asm/netlogic/xlr/fmn.h> + +uint64_t nlm_io_base = DEFAULT_NETLOGIC_IO_BASE; +struct psb_info nlm_prom_info; + +/* default to uniprocessor */ +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 nlm_linux_exit(void) +{ +	uint64_t gpiobase; + +	gpiobase = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); +	/* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */ +	nlm_write_reg(gpiobase, GPIO_SWRESET_REG, 1); +	for ( ; ; ) +		cpu_wait(); +} + +void __init plat_mem_setup(void) +{ +	_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 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 */ +} + +void nlm_percpu_init(int hwcpuid) +{ +	if (hwcpuid % 4 == 0) +		xlr_percpu_fmn_init(); +} + +static void __init build_arcs_cmdline(int *argv) +{ +	int i, remain, len; +	char *arg; + +	remain = sizeof(arcs_cmdline) - 1; +	arcs_cmdline[0] = '\0'; +	for (i = 0; argv[i] != 0; i++) { +		arg = (char *)(long)argv[i]; +		len = strlen(arg); +		if (len + 1 > remain) +			break; +		strcat(arcs_cmdline, arg); +		strcat(arcs_cmdline, " "); +		remain -=  len + 1; +	} + +	/* Add the default options here */ +	if ((strstr(arcs_cmdline, "console=")) == NULL) { +		arg = "console=ttyS0,38400 "; +		len = strlen(arg); +		if (len > remain) +			goto fail; +		strcat(arcs_cmdline, arg); +		remain -= len; +	} +#ifdef CONFIG_BLK_DEV_INITRD +	if ((strstr(arcs_cmdline, "rdinit=")) == NULL) { +		arg = "rdinit=/sbin/init "; +		len = strlen(arg); +		if (len > remain) +			goto fail; +		strcat(arcs_cmdline, arg); +		remain -= len; +	} +#endif +	return; +fail: +	panic("Cannot add %s, command line too big!", arg); +} + +static void prom_add_memory(void) +{ +	struct nlm_boot_mem_map *bootm; +	u64 start, size; +	u64 pref_backup = 512;	/* avoid pref walking beyond end */ +	int i; + +	bootm = (void *)(long)nlm_prom_info.psb_mem_map; +	for (i = 0; i < bootm->nr_map; i++) { +		if (bootm->map[i].type != BOOT_MEM_RAM) +			continue; +		start = bootm->map[i].addr; +		size   = bootm->map[i].size; + +		/* Work around for using bootloader mem */ +		if (i == 0 && start == 0 && size == 0x0c000000) +			size = 0x0ff00000; + +		add_memory_region(start, size - pref_backup, BOOT_MEM_RAM); +	} +} + +static void nlm_init_node(void) +{ +	struct nlm_soc_info *nodep; + +	nodep = nlm_current_node(); +	nodep->picbase = nlm_mmio_base(NETLOGIC_IO_PIC_OFFSET); +	nodep->ebase = read_c0_ebase() & (~((1 << 12) - 1)); +	spin_lock_init(&nodep->piclock); +} + +void __init prom_init(void) +{ +	int *argv, *envp;		/* passed as 32 bit ptrs */ +	struct psb_info *prom_infop; +	void *reset_vec; +#ifdef CONFIG_SMP +	int i; +#endif + +	/* truncate to 32 bit and sign extend all args */ +	argv = (int *)(long)(int)fw_arg1; +	envp = (int *)(long)(int)fw_arg2; +	prom_infop = (struct psb_info *)(long)(int)fw_arg3; + +	nlm_prom_info = *prom_infop; +	nlm_init_node(); + +	/* Update reset entry point with CPU init code */ +	reset_vec = (void *)CKSEG1ADDR(RESET_VEC_PHYS); +	memset(reset_vec, 0, RESET_VEC_SIZE); +	memcpy(reset_vec, (void *)nlm_reset_entry, +			(nlm_reset_entry_end - nlm_reset_entry)); + +	build_arcs_cmdline(argv); +	prom_add_memory(); + +#ifdef CONFIG_SMP +	for (i = 0; i < 32; i++) +		if (nlm_prom_info.online_cpu_map & (1 << i)) +			cpumask_set_cpu(i, &nlm_cpumask); +	nlm_wakeup_secondary_cpus(); +	register_smp_ops(&nlm_smp_ops); +#endif +	xlr_board_info_setup(); +	xlr_percpu_fmn_init(); +} diff --git a/arch/mips/netlogic/xlr/wakeup.c b/arch/mips/netlogic/xlr/wakeup.c new file mode 100644 index 00000000000..d61cba1e9c6 --- /dev/null +++ b/arch/mips/netlogic/xlr/wakeup.c @@ -0,0 +1,85 @@ +/* + * 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/delay.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/xlr/iomap.h> +#include <asm/netlogic/xlr/pic.h> + +int xlr_wakeup_secondary_cpus(void) +{ +	struct nlm_soc_info *nodep; +	unsigned int i, j, boot_cpu; +	volatile u32 *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY); + +	/* +	 *  In case of RMI boot, hit with NMI to get the cores +	 *  from bootloader to linux code. +	 */ +	nodep = nlm_get_node(0); +	boot_cpu = hard_smp_processor_id(); +	nlm_set_nmi_handler(nlm_rmiboot_preboot); +	for (i = 0; i < NR_CPUS; i++) { +		if (i == boot_cpu || !cpumask_test_cpu(i, &nlm_cpumask)) +			continue; +		nlm_pic_send_ipi(nodep->picbase, i, 1, 1); /* send NMI */ +	} + +	/* Fill up the coremask early */ +	nodep->coremask = 1; +	for (i = 1; i < nlm_cores_per_node(); i++) { +		for (j = 1000000; j > 0; j--) { +			if (cpu_ready[i * NLM_THREADS_PER_CORE]) +				break; +			udelay(10); +		} +		if (j != 0) +			nodep->coremask |= (1u << i); +		else +			pr_err("Failed to wakeup core %d\n", i); +	} + +	return 0; +}  | 
