armadaxp_mp.c revision 239277
1/*-
2 * Copyright (c) 2011 Semihalf.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/arm/mv/armadaxp/armadaxp_mp.c 239277 2012-08-15 05:15:49Z gonzo $
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/bus.h>
32#include <sys/lock.h>
33#include <sys/mutex.h>
34#include <sys/smp.h>
35
36#include <machine/smp.h>
37#include <machine/fdt.h>
38
39#include <arm/mv/mvwin.h>
40
41static int platform_get_ncpus(void);
42
43#define MV_AXP_CPU_DIVCLK_BASE		(MV_BASE + 0x18700)
44#define CPU_DIVCLK_CTRL0		0x00
45#define CPU_DIVCLK_CTRL2_RATIO_FULL0	0x08
46#define CPU_DIVCLK_CTRL2_RATIO_FULL1	0x0c
47
48#define MV_COHERENCY_FABRIC_BASE	(MV_MBUS_BRIDGE_BASE + 0x200)
49#define COHER_FABRIC_CTRL		0x00
50#define COHER_FABRIC_CONF		0x04
51
52#define CPU_PMU(x)			(MV_BASE + 0x22100 + (0x100 * (x)))
53#define CPU_PMU_BOOT			0x24
54
55#define MP				(MV_BASE + 0x20800)
56#define MP_SW_RESET(x)			((x) * 8)
57
58#define CPU_RESUME_CONTROL		(0x20988)
59
60/* Coherency Fabric registers */
61static uint32_t
62read_coher_fabric(uint32_t reg)
63{
64
65	return (bus_space_read_4(fdtbus_bs_tag, MV_COHERENCY_FABRIC_BASE, reg));
66}
67
68static void
69write_coher_fabric(uint32_t reg, uint32_t val)
70{
71
72	bus_space_write_4(fdtbus_bs_tag, MV_COHERENCY_FABRIC_BASE, reg, val);
73}
74
75/* Coherency Fabric registers */
76static uint32_t
77read_cpu_clkdiv(uint32_t reg)
78{
79
80	return (bus_space_read_4(fdtbus_bs_tag, MV_AXP_CPU_DIVCLK_BASE, reg));
81}
82
83static void
84write_cpu_clkdiv(uint32_t reg, uint32_t val)
85{
86
87	bus_space_write_4(fdtbus_bs_tag, MV_AXP_CPU_DIVCLK_BASE, reg, val);
88}
89
90void
91platform_mp_setmaxid(void)
92{
93
94	mp_maxid = 3;
95}
96
97int
98platform_mp_probe(void)
99{
100
101	mp_ncpus = platform_get_ncpus();
102
103	return (mp_ncpus > 1);
104}
105
106void
107platform_mp_init_secondary(void)
108{
109}
110
111void mpentry(void);
112void mptramp(void);
113
114static void
115initialize_coherency_fabric(void)
116{
117	uint32_t val, cpus, mask;
118
119	cpus = platform_get_ncpus();
120	mask = (1 << cpus) - 1;
121	val = read_coher_fabric(COHER_FABRIC_CTRL);
122	val |= (mask << 24);
123	write_coher_fabric(COHER_FABRIC_CTRL, val);
124
125	val = read_coher_fabric(COHER_FABRIC_CONF);
126	val |= (mask << 24);
127	write_coher_fabric(COHER_FABRIC_CONF, val);
128}
129
130
131void
132platform_mp_start_ap(void)
133{
134	uint32_t reg, *ptr, cpu_num;
135
136	/* Copy boot code to SRAM */
137	*((unsigned int*)(0xf1020240)) = 0xffff0101;
138	*((unsigned int*)(0xf1008500)) = 0xffff0003;
139
140	pmap_kenter_nocache(0x880f0000, 0xffff0000);
141	reg = 0x880f0000;
142
143	for (ptr = (uint32_t *)mptramp; ptr < (uint32_t *)mpentry;
144	    ptr++, reg += 4)
145		*((uint32_t *)reg) = *ptr;
146
147	if (mp_ncpus > 1) {
148		reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL0);
149		reg &= 0x00ffffff;
150		reg |= 0x01000000;
151		write_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL0, reg);
152	}
153	if (mp_ncpus > 2) {
154		reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1);
155		reg &= 0xff00ffff;
156		reg |= 0x00010000;
157		write_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1, reg);
158	}
159	if (mp_ncpus > 3) {
160		reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1);
161		reg &= 0x00ffffff;
162		reg |= 0x01000000;
163		write_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1, reg);
164	}
165
166	reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL0);
167	reg |= ((0x1 << (mp_ncpus - 1)) - 1) << 21;
168	write_cpu_clkdiv(CPU_DIVCLK_CTRL0, reg);
169	reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL0);
170	reg |= 0x01000000;
171	write_cpu_clkdiv(CPU_DIVCLK_CTRL0, reg);
172
173	DELAY(100);
174	reg &= ~(0xf << 21);
175	write_cpu_clkdiv(CPU_DIVCLK_CTRL0, reg);
176	DELAY(100);
177
178	bus_space_write_4(fdtbus_bs_tag, MV_BASE, CPU_RESUME_CONTROL, 0);
179
180	for (cpu_num = 1; cpu_num < mp_ncpus; cpu_num++ )
181		bus_space_write_4(fdtbus_bs_tag, CPU_PMU(cpu_num), CPU_PMU_BOOT,
182		    pmap_kextract(mpentry));
183
184	cpu_idcache_wbinv_all();
185
186	for (cpu_num = 1; cpu_num < mp_ncpus; cpu_num++ )
187		bus_space_write_4(fdtbus_bs_tag, MP, MP_SW_RESET(cpu_num), 0);
188
189	/* XXX: Temporary workaround for hangup after releasing AP's */
190	wmb();
191	DELAY(10);
192
193	initialize_coherency_fabric();
194}
195
196static int
197platform_get_ncpus(void)
198{
199
200	return ((read_coher_fabric(COHER_FABRIC_CONF) & 0xf) + 1);
201}
202
203void
204platform_ipi_send(cpuset_t cpus, u_int ipi)
205{
206
207	pic_ipi_send(cpus, ipi);
208}
209