1263698Sganbold/*-
2263698Sganbold * Copyright (c) 2014 Ganbold Tsagaankhuu <ganbold@freebsd.org>
3263698Sganbold * All rights reserved.
4263698Sganbold *
5263698Sganbold * Redistribution and use in source and binary forms, with or without
6263698Sganbold * modification, are permitted provided that the following conditions
7263698Sganbold * are met:
8263698Sganbold * 1. Redistributions of source code must retain the above copyright
9263698Sganbold *    notice, this list of conditions and the following disclaimer.
10263698Sganbold * 2. Redistributions in binary form must reproduce the above copyright
11263698Sganbold *    notice, this list of conditions and the following disclaimer in the
12263698Sganbold *    documentation and/or other materials provided with the distribution.
13263698Sganbold *
14263698Sganbold * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15263698Sganbold * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16263698Sganbold * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17263698Sganbold * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18263698Sganbold * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19263698Sganbold * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20263698Sganbold * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21263698Sganbold * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22263698Sganbold * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23263698Sganbold * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24263698Sganbold */
25263698Sganbold
26263698Sganbold#include <sys/cdefs.h>
27263698Sganbold__FBSDID("$FreeBSD: releng/10.2/sys/arm/allwinner/a20/a20_mp.c 266337 2014-05-17 18:53:36Z ian $");
28263698Sganbold#include <sys/param.h>
29263698Sganbold#include <sys/systm.h>
30263698Sganbold#include <sys/bus.h>
31263698Sganbold#include <sys/kernel.h>
32263698Sganbold#include <sys/lock.h>
33263698Sganbold#include <sys/mutex.h>
34263698Sganbold#include <sys/smp.h>
35263698Sganbold
36263698Sganbold#include <machine/smp.h>
37263698Sganbold#include <machine/fdt.h>
38263698Sganbold#include <machine/intr.h>
39263698Sganbold
40263698Sganbold#define	CPUCFG_BASE		0x01c25c00
41263698Sganbold#define	CPUCFG_SIZE		0x400
42263698Sganbold
43263698Sganbold#define	CPU0_RST_CTL		0x40
44263698Sganbold#define	CPU0_CTL		0x44
45263698Sganbold#define	CPU0_STATUS		0x48
46263698Sganbold#define	CPU1_RST_CTL		0x80
47263698Sganbold#define	CPU1_CTL		0x84
48263698Sganbold#define	CPU1_STATUS		0x88
49263698Sganbold#define	CPUCFG_GENCTL		0x184
50263698Sganbold#define	CPUCFG_P_REG0		0x1a4
51263698Sganbold#define	CPU1_PWR_CLAMP		0x1b0
52263698Sganbold#define	CPU1_PWROFF_REG		0x1b4
53263698Sganbold#define	CPUCFG_DBGCTL0		0x1e0
54263698Sganbold#define	CPUCFG_DBGCTL1		0x1e4
55263698Sganbold
56263698Sganboldvoid
57263698Sganboldplatform_mp_init_secondary(void)
58263698Sganbold{
59263698Sganbold
60263698Sganbold	gic_init_secondary();
61263698Sganbold}
62263698Sganbold
63263698Sganboldvoid
64263698Sganboldplatform_mp_setmaxid(void)
65263698Sganbold{
66263698Sganbold	int ncpu;
67263698Sganbold
68263698Sganbold	if (mp_ncpus != 0)
69263698Sganbold		return;
70263698Sganbold
71263698Sganbold	/* Read current CP15 Cache Size ID Register */
72263698Sganbold	__asm __volatile("mrc p15, 1, %0, c9, c0, 2" : "=r" (ncpu));
73263698Sganbold	ncpu = ((ncpu >> 24) & 0x3) + 1;
74263698Sganbold
75263698Sganbold	mp_ncpus = ncpu;
76263698Sganbold	mp_maxid = ncpu - 1;
77263698Sganbold}
78263698Sganbold
79263698Sganboldint
80263698Sganboldplatform_mp_probe(void)
81263698Sganbold{
82263698Sganbold
83263698Sganbold	if (mp_ncpus == 0)
84263698Sganbold		platform_mp_setmaxid();
85263698Sganbold
86263698Sganbold	return (mp_ncpus > 1);
87263698Sganbold}
88263698Sganbold
89263698Sganboldvoid
90263698Sganboldplatform_mp_start_ap(void)
91263698Sganbold{
92263698Sganbold	bus_space_handle_t cpucfg;
93263698Sganbold
94263698Sganbold	uint32_t val;
95263698Sganbold
96263698Sganbold	if (bus_space_map(fdtbus_bs_tag, CPUCFG_BASE, CPUCFG_SIZE, 0,
97263698Sganbold	    &cpucfg) != 0)
98263698Sganbold		panic("Couldn't map the CPUCFG\n");
99263698Sganbold
100263698Sganbold	cpu_idcache_wbinv_all();
101263698Sganbold	cpu_l2cache_wbinv_all();
102263698Sganbold
103263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_P_REG0,
104263698Sganbold	    pmap_kextract((vm_offset_t)mpentry));
105263698Sganbold
106263698Sganbold	/*
107263698Sganbold	 * Assert nCOREPORESET low and set L1RSTDISABLE low.
108263698Sganbold	 * Ensure DBGPWRDUP is set to LOW to prevent any external
109263698Sganbold	 * debug access to the processor.
110263698Sganbold	 */
111263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_RST_CTL, 0);
112263698Sganbold
113263698Sganbold	/* Set L1RSTDISABLE low */
114263698Sganbold	val = bus_space_read_4(fdtbus_bs_tag, cpucfg, CPUCFG_GENCTL);
115263698Sganbold	val &= ~(1 << 1);
116263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_GENCTL, val);
117263698Sganbold
118263698Sganbold	/* Set DBGPWRDUP low */
119263698Sganbold	val = bus_space_read_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1);
120263698Sganbold	val &= ~(1 << 1);
121263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1, val);
122263698Sganbold
123263698Sganbold	/* Release power clamp */
124263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0xff);
125263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x7f);
126263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x3f);
127263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x1f);
128263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x0f);
129263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x07);
130263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x03);
131263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x01);
132263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x00);
133263698Sganbold	DELAY(10000);
134263698Sganbold
135263698Sganbold	/* Clear power-off gating */
136263698Sganbold	val = bus_space_read_4(fdtbus_bs_tag, cpucfg, CPU1_PWROFF_REG);
137263698Sganbold	val &= ~(1 << 0);
138263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWROFF_REG, val);
139263698Sganbold	DELAY(1000);
140263698Sganbold
141263698Sganbold	/* De-assert cpu core reset */
142263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_RST_CTL, 3);
143263698Sganbold
144263698Sganbold	/* Assert DBGPWRDUP signal */
145263698Sganbold	val = bus_space_read_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1);
146263698Sganbold	val |= (1 << 1);
147263698Sganbold	bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1, val);
148263698Sganbold
149263698Sganbold	armv7_sev();
150263698Sganbold	bus_space_unmap(fdtbus_bs_tag, cpucfg, CPUCFG_SIZE);
151263698Sganbold}
152263698Sganbold
153263698Sganboldvoid
154263698Sganboldplatform_ipi_send(cpuset_t cpus, u_int ipi)
155263698Sganbold{
156263698Sganbold
157263698Sganbold	pic_ipi_send(cpus, ipi);
158263698Sganbold}
159