1/*-
2 * Copyright (c) 2013-2014 Ruslan Bukin <br@bsdpad.com>
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
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/11/sys/arm/samsung/exynos/exynos5_mp.c 307344 2016-10-15 08:27:54Z mmel $");
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 <vm/vm.h>
37#include <vm/pmap.h>
38
39#include <machine/cpu.h>
40#include <machine/smp.h>
41#include <machine/fdt.h>
42#include <machine/intr.h>
43
44#define	EXYNOS_CHIPID		0x10000000
45
46#define	EXYNOS5250_SOC_ID	0x43520000
47#define	EXYNOS5420_SOC_ID	0xE5420000
48#define	EXYNOS5_SOC_ID_MASK	0xFFFFF000
49
50#define	EXYNOS_SYSRAM		0x02020000
51#define	EXYNOS5420_SYSRAM_NS	(EXYNOS_SYSRAM + 0x53000 + 0x1c)
52
53#define	EXYNOS_PMU_BASE		0x10040000
54#define	CORE_CONFIG(n)		(0x2000 + (0x80 * (n)))
55#define	CORE_STATUS(n)		(CORE_CONFIG(n) + 0x4)
56#define	CORE_PWR_EN		0x3
57
58static int
59exynos_get_soc_id(void)
60{
61	bus_addr_t chipid;
62	int reg;
63
64	if (bus_space_map(fdtbus_bs_tag, EXYNOS_CHIPID,
65		0x1000, 0, &chipid) != 0)
66		panic("Couldn't map chipid\n");
67	reg = bus_space_read_4(fdtbus_bs_tag, chipid, 0x0);
68	bus_space_unmap(fdtbus_bs_tag, chipid, 0x1000);
69
70	return (reg & EXYNOS5_SOC_ID_MASK);
71}
72
73void
74platform_mp_setmaxid(void)
75{
76
77	if (exynos_get_soc_id() == EXYNOS5420_SOC_ID)
78		mp_ncpus = 4;
79	else
80		mp_ncpus = 2;
81
82	mp_maxid = mp_ncpus - 1;
83}
84
85void
86platform_mp_start_ap(void)
87{
88	bus_addr_t sysram, pmu;
89	int err, i, j;
90	int status;
91	int reg;
92
93	err = bus_space_map(fdtbus_bs_tag, EXYNOS_PMU_BASE, 0x20000, 0, &pmu);
94	if (err != 0)
95		panic("Couldn't map pmu\n");
96
97	if (exynos_get_soc_id() == EXYNOS5420_SOC_ID)
98		reg = EXYNOS5420_SYSRAM_NS;
99	else
100		reg = EXYNOS_SYSRAM;
101
102	err = bus_space_map(fdtbus_bs_tag, reg, 0x100, 0, &sysram);
103	if (err != 0)
104		panic("Couldn't map sysram\n");
105
106	/* Give power to CPUs */
107	for (i = 1; i < mp_ncpus; i++) {
108		bus_space_write_4(fdtbus_bs_tag, pmu, CORE_CONFIG(i),
109		    CORE_PWR_EN);
110
111		for (j = 10; j >= 0; j--) {
112			status = bus_space_read_4(fdtbus_bs_tag, pmu,
113			    CORE_STATUS(i));
114			if ((status & CORE_PWR_EN) == CORE_PWR_EN)
115				break;
116			DELAY(10);
117			if (j == 0)
118				printf("Can't power on CPU%d\n", i);
119		}
120	}
121
122	bus_space_write_4(fdtbus_bs_tag, sysram, 0x0,
123	    pmap_kextract((vm_offset_t)mpentry));
124
125	dcache_wbinv_poc_all();
126
127	dsb();
128	sev();
129	bus_space_unmap(fdtbus_bs_tag, sysram, 0x100);
130	bus_space_unmap(fdtbus_bs_tag, pmu, 0x20000);
131}
132