wakeup.c 6.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
/*
 * 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/threads.h>

#include <asm/asm.h>
#include <asm/asm-offsets.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/string.h>

#include <asm/netlogic/haldefs.h>
#include <asm/netlogic/common.h>
#include <asm/netlogic/mips-extns.h>

#include <asm/netlogic/xlp-hal/iomap.h>
#include <asm/netlogic/xlp-hal/xlp.h>
50
#include <asm/netlogic/xlp-hal/pic.h>
51 52
#include <asm/netlogic/xlp-hal/sys.h>

53
static int xlp_wakeup_core(uint64_t sysbase, int node, int core)
54
{
55
	uint32_t coremask, value;
56
	int count, resetreg;
57

58
	coremask = (1 << core);
59

60 61 62 63 64 65
	/* Enable CPU clock in case of 8xx/3xx */
	if (!cpu_is_xlpii()) {
		value = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL);
		value &= ~coremask;
		nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, value);
	}
66

67 68 69 70 71 72 73
	/* 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);
	}

74
	/* Remove CPU Reset */
75 76
	resetreg = cpu_is_xlp9xx() ? SYS_9XX_CPU_RESET : SYS_CPU_RESET;
	value = nlm_read_sys_reg(sysbase, resetreg);
77
	value &= ~coremask;
78 79 80 81 82
	nlm_write_sys_reg(sysbase, resetreg, value);

	/* We are done on 9XX */
	if (cpu_is_xlp9xx())
		return 1;
83

84
	/* Poll for CPU to mark itself coherent on other type of XLP */
85 86 87 88
	count = 100000;
	do {
		value = nlm_read_sys_reg(sysbase, SYS_CPU_NONCOHERENT_MODE);
	} while ((value & coremask) != 0 && --count > 0);
89

90 91 92
	return count != 0;
}

93 94 95 96 97
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;

98
	count = 0x800000;
99 100 101
	do {
		notready = nlm_threads_per_core;
		for (i = 0; i < nlm_threads_per_core; i++)
102
			if (cpu_ready[cpu + i] || (cpu + i) == bootcpu)
103 104 105 106 107 108
				--notready;
	} while (notready != 0 && --count > 0);

	return count != 0;
}

109 110
static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask)
{
111
	struct nlm_soc_info *nodep;
112
	uint64_t syspcibase, fusebase;
113
	uint32_t syscoremask, mask, fusemask;
114
	int core, n, cpu, ncores;
115

116
	for (n = 0; n < NLM_NR_NODES; n++) {
117 118 119 120 121 122 123 124 125 126 127 128 129 130
		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);
		}
131

132
		/* read cores in reset from SYS */
133
		nodep = nlm_get_node(n);
134

135 136 137
		if (cpu_is_xlp9xx()) {
			fusebase = nlm_get_fuse_regbase(n);
			fusemask = nlm_read_reg(fusebase, FUSE_9XX_DEVCFG6);
138 139 140 141 142 143 144 145 146
			switch (read_c0_prid() & PRID_IMP_MASK) {
			case PRID_IMP_NETLOGIC_XLP5XX:
				mask = 0xff;
				break;
			case PRID_IMP_NETLOGIC_XLP9XX:
			default:
				mask = 0xfffff;
				break;
			}
147 148 149
		} else {
			fusemask = nlm_read_sys_reg(nodep->sysbase,
						SYS_EFUSE_DEVICE_CFG_STATUS0);
150
			switch (read_c0_prid() & PRID_IMP_MASK) {
151 152 153 154 155 156 157 158 159 160 161
			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;
			}
162 163 164 165 166 167 168 169
		}

		/*
		 * 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;

170
		pr_info("Node %d - SYS/FUSE coremask %x\n", n, syscoremask);
171 172
		ncores = nlm_cores_per_node();
		for (core = 0; core < ncores; core++) {
173 174 175 176
			/* we will be on node 0 core 0 */
			if (n == 0 && core == 0)
				continue;

177 178 179
			/* see if the core exists */
			if ((syscoremask & (1 << core)) == 0)
				continue;
180

181
			/* see if at least the first hw thread is enabled */
182
			cpu = (n * ncores + core) * NLM_THREADS_PER_CORE;
183
			if (!cpumask_test_cpu(cpu, wakeup_mask))
184
				continue;
185

186
			/* wake up the core */
187 188 189 190 191 192
			if (!xlp_wakeup_core(nodep->sysbase, n, core))
				continue;

			/* core is up */
			nodep->coremask |= 1u << core;

193
			/* spin until the hw threads sets their ready */
194 195
			if (!wait_for_cpus(cpu, 0))
				pr_err("Node %d : timeout core %d\n", n, core);
196
		}
197 198 199
	}
}

200
void xlp_wakeup_secondary_cpus()
201
{
202 203 204 205 206
	/*
	 * In case of u-boot, the secondaries are in reset
	 * first wakeup core 0 threads
	 */
	xlp_boot_core0_siblings();
207 208
	if (!wait_for_cpus(0, 0))
		pr_err("Node 0 : timeout core 0\n");
209 210

	/* now get other cores out of reset */
211
	xlp_enable_secondary_cores(&nlm_cpumask);
212
}