1/* $NetBSD: rk3066_smp.c,v 1.2 2021/11/13 15:17:22 jmcneill Exp $ */
2
3/*-
4 * Copyright (c) 2021 Jared McNeill <jmcneill@invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include "opt_soc.h"
30#include "opt_multiprocessor.h"
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: rk3066_smp.c,v 1.2 2021/11/13 15:17:22 jmcneill Exp $");
34
35#include <sys/param.h>
36#include <sys/bus.h>
37#include <sys/cpu.h>
38#include <sys/device.h>
39
40#include <dev/fdt/fdtvar.h>
41#include <arm/fdt/arm_fdtvar.h>
42
43#include <uvm/uvm_extern.h>
44
45#define	PMU_PWRDN_CON		0x0008
46#define	PMU_PWRDN_ST		0x000c
47
48#define	SRAM_ENTRY_PA		0x0008
49#define	SRAM_DOORBELL		0x0004
50#define	SRAM_DOORBELL_MAGIC	0xdeadbeaf
51
52extern struct bus_space arm_generic_bs_tag;
53
54static uint32_t
55rk3066_mpstart_pa(void)
56{
57	bool ok __diagused;
58	paddr_t pa;
59
60	ok = pmap_extract(pmap_kernel(), (vaddr_t)cpu_mpstart, &pa);
61	KASSERT(ok);
62
63	return (uint32_t)pa;
64}
65
66static int
67rk3066_map(int phandle, bus_space_tag_t bst, bus_space_handle_t *pbsh,
68    bus_size_t *psize)
69{
70	bus_addr_t addr;
71	int error;
72
73	error = fdtbus_get_reg(phandle, 0, &addr, psize);
74	if (error != 0) {
75		return error;
76	}
77
78	return bus_space_map(bst, addr, *psize, 0, pbsh);
79}
80
81static int
82rk3066_smp_enable(int cpus_phandle, u_int cpuno)
83{
84	bus_space_tag_t bst = &arm_generic_bs_tag;
85	bus_space_handle_t bsh_sram, bsh_pmu;
86	bus_size_t sz_sram, sz_pmu;
87	uint32_t val;
88	int error;
89
90	const int sram_phandle =
91	    of_find_bycompat(OF_peer(0), "rockchip,rk3066-smp-sram");
92	if (sram_phandle == -1) {
93		printf("%s: missing rockchip,rk3066-smp-sram node\n",
94		    __func__);
95		return ENXIO;
96	}
97
98	const int pmu_phandle = fdtbus_get_phandle(cpus_phandle,
99	    "rockchip,pmu");
100	if (pmu_phandle == -1) {
101		printf("%s: missing rockchip,pmu xref\n", __func__);
102		return ENXIO;
103	}
104
105	error = rk3066_map(sram_phandle, bst, &bsh_sram, &sz_sram);
106	if (error != 0) {
107		return error;
108	}
109
110	error = rk3066_map(pmu_phandle, bst, &bsh_pmu, &sz_pmu);
111	if (error != 0) {
112		bus_space_unmap(bst, bsh_pmu, sz_pmu);
113		return error;
114	}
115
116	/* Enable the A17 core's power domain */
117	val = bus_space_read_4(bst, bsh_pmu, PMU_PWRDN_CON);
118	val &= ~__BIT(cpuno);
119	bus_space_write_4(bst, bsh_pmu, PMU_PWRDN_CON, val);
120
121	/* Wait for the A17 core to power on */
122	do {
123		val = bus_space_read_4(bst, bsh_pmu, PMU_PWRDN_ST);
124	} while ((val & __BIT(cpuno)) != 0);
125
126	delay(2000);
127
128	/* Set wake vector */
129	bus_space_write_4(bst, bsh_sram, SRAM_ENTRY_PA, rk3066_mpstart_pa());
130	/* Notify boot rom that we are ready to start */
131	bus_space_write_4(bst, bsh_sram, SRAM_DOORBELL, SRAM_DOORBELL_MAGIC);
132	dsb();
133	sev();
134
135	bus_space_unmap(bst, bsh_pmu, sz_pmu);
136	bus_space_unmap(bst, bsh_sram, sz_sram);
137
138	return 0;
139}
140
141static int
142cpu_enable_rk3066(int phandle)
143{
144	uint64_t mpidr;
145
146	fdtbus_get_reg64(phandle, 0, &mpidr, NULL);
147
148	const u_int cpuno = __SHIFTOUT(mpidr, MPIDR_AFF0);
149
150	cpu_dcache_wbinv_all();
151
152	return rk3066_smp_enable(OF_parent(phandle), cpuno);
153}
154
155ARM_CPU_METHOD(rk3066, "rockchip,rk3066-smp", cpu_enable_rk3066);
156