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
52 extern struct bus_space arm_generic_bs_tag;
53
54 static uint32_t
rk3066_mpstart_pa(void)55 rk3066_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
66 static int
rk3066_map(int phandle,bus_space_tag_t bst,bus_space_handle_t * pbsh,bus_size_t * psize)67 rk3066_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
81 static int
rk3066_smp_enable(int cpus_phandle,u_int cpuno)82 rk3066_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
141 static int
cpu_enable_rk3066(int phandle)142 cpu_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
155 ARM_CPU_METHOD(rk3066, "rockchip,rk3066-smp", cpu_enable_rk3066);
156