1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 /*
30  * This file contains facilities for runtime determination of address space
31  * mappings for use in DMA/mailbox interactions.  This is only used for the
32  * arm64 SoC because the 32-bit SoC used the same mappings.
33  */
34 
35 #include <sys/types.h>
36 #include <sys/systm.h>
37 
38 #include <dev/ofw/openfirm.h>
39 #include <dev/ofw/ofw_bus.h>
40 #include <dev/ofw/ofw_bus_subr.h>
41 
42 #include <machine/bus.h>
43 
44 #include <arm/broadcom/bcm2835/bcm2835_vcbus.h>
45 
46 /*
47  * This structure describes mappings that need to take place when transforming
48  * ARM core addresses into vcbus addresses for use with the DMA/mailbox
49  * interfaces.  Currently, we only deal with peripheral/SDRAM address spaces
50  * here.
51  *
52  * The SDRAM address space is consistently mapped starting at 0 and extends to
53  * the size of the installed SDRAM.
54  *
55  * Peripherals are mapped further up at spots that vary per-SOC.
56  */
57 struct bcm283x_memory_mapping {
58 	vm_paddr_t	armc_start;
59 	vm_paddr_t	armc_size;
60 	vm_paddr_t	vcbus_start;
61 };
62 
63 static struct bcm283x_memory_mapping bcm2835_memmap[] = {
64 	{
65 		/* SDRAM */
66 		.armc_start = 0x00000000,
67 		.armc_size = BCM2835_ARM_IO_BASE,
68 		.vcbus_start = BCM2835_VCBUS_SDRAM_BASE,
69 	},
70 	{
71 		/* Peripherals */
72 		.armc_start = BCM2835_ARM_IO_BASE,
73 		.armc_size  = BCM28XX_ARM_IO_SIZE,
74 		.vcbus_start = BCM2835_VCBUS_IO_BASE,
75 	},
76 	{ 0, 0, 0 },
77 };
78 
79 static struct bcm283x_memory_mapping bcm2836_memmap[] = {
80 	{
81 		/* SDRAM */
82 		.armc_start = 0x00000000,
83 		.armc_size = BCM2836_ARM_IO_BASE,
84 		.vcbus_start = BCM2836_VCBUS_SDRAM_BASE,
85 	},
86 	{
87 		/* Peripherals */
88 		.armc_start = BCM2836_ARM_IO_BASE,
89 		.armc_size  = BCM28XX_ARM_IO_SIZE,
90 		.vcbus_start = BCM2836_VCBUS_IO_BASE,
91 	},
92 	{ 0, 0, 0 },
93 };
94 
95 static struct bcm283x_memory_mapping bcm2837_memmap[] = {
96 	{
97 		/* SDRAM */
98 		.armc_start = 0x00000000,
99 		.armc_size = BCM2837_ARM_IO_BASE,
100 		.vcbus_start = BCM2837_VCBUS_SDRAM_BASE,
101 	},
102 	{
103 		/* Peripherals */
104 		.armc_start = BCM2837_ARM_IO_BASE,
105 		.armc_size  = BCM28XX_ARM_IO_SIZE,
106 		.vcbus_start = BCM2837_VCBUS_IO_BASE,
107 	},
108 	{ 0, 0, 0 },
109 };
110 
111 /*
112  * The BCM2838 supports up to 4GB of SDRAM, but unfortunately we can still only
113  * map the first 1GB into the "legacy master view" (vcbus) address space.  Thus,
114  * peripherals can still only access the lower end of SDRAM.  For this reason,
115  * we also capture the main-peripheral busdma restriction below.
116  */
117 static struct bcm283x_memory_mapping bcm2838_memmap[] = {
118 	{
119 		/* SDRAM */
120 		.armc_start = 0x00000000,
121 		.armc_size = 0x40000000,
122 		.vcbus_start = BCM2838_VCBUS_SDRAM_BASE,
123 	},
124 	{
125 		/* Main peripherals */
126 		.armc_start = BCM2838_ARM_IO_BASE,
127 		.armc_size = BCM28XX_ARM_IO_SIZE,
128 		.vcbus_start = BCM2838_VCBUS_IO_BASE,
129 	},
130 	{ 0, 0, 0 },
131 };
132 
133 static struct bcm283x_memory_soc_cfg {
134 	struct bcm283x_memory_mapping	*memmap;
135 	const char			*soc_compat;
136 	bus_addr_t			 busdma_lowaddr;
137 } bcm283x_memory_configs[] = {
138 	/* Legacy */
139 	{
140 		.memmap = bcm2835_memmap,
141 		.soc_compat = "raspberrypi,model-b",
142 		.busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT,
143 	},
144 	/* Modern */
145 	{
146 		.memmap = bcm2835_memmap,
147 		.soc_compat = "brcm,bcm2835",
148 		.busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT,
149 	},
150 	/* Legacy */
151 	{
152 		.memmap = bcm2836_memmap,
153 		.soc_compat = "brcm,bcm2709",
154 		.busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT,
155 	},
156 	/* Modern */
157 	{
158 		.memmap = bcm2836_memmap,
159 		.soc_compat = "brcm,bcm2836",
160 		.busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT,
161 	},
162 	{
163 		.memmap = bcm2837_memmap,
164 		.soc_compat = "brcm,bcm2837",
165 		.busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT,
166 	},
167 	{
168 		.memmap = bcm2838_memmap,
169 		.soc_compat = "brcm,bcm2711",
170 		.busdma_lowaddr = BCM2838_PERIPH_MAXADDR,
171 	},
172 	{
173 		.memmap = bcm2838_memmap,
174 		.soc_compat = "brcm,bcm2838",
175 		.busdma_lowaddr = BCM2838_PERIPH_MAXADDR,
176 	},
177 };
178 
179 static struct bcm283x_memory_soc_cfg *booted_soc_memcfg;
180 
181 static struct bcm283x_memory_soc_cfg *
182 bcm283x_get_current_memcfg(void)
183 {
184 	phandle_t root;
185 	int i;
186 
187 	/* We'll cache it once we decide, because it won't change per-boot. */
188 	if (booted_soc_memcfg != NULL)
189 		return (booted_soc_memcfg);
190 
191 	KASSERT(nitems(bcm283x_memory_configs) != 0,
192 	    ("No SOC memory configurations enabled!"));
193 
194 	root = OF_finddevice("/");
195 	for (i = 0; i < nitems(bcm283x_memory_configs); ++i) {
196 		booted_soc_memcfg = &bcm283x_memory_configs[i];
197 		if (bootverbose)
198 			printf("Checking root against %s\n",
199 			    booted_soc_memcfg->soc_compat);
200 		if (ofw_bus_node_is_compatible(root,
201 		    booted_soc_memcfg->soc_compat))
202 			return (booted_soc_memcfg);
203 	}
204 
205 	/*
206 	 * The kernel doesn't fit the board; we can't really make a reasonable
207 	 * guess, as these SOC are different enough that something will blow up
208 	 * later.
209 	 */
210 	panic("No suitable SOC memory configuration found.");
211 }
212 
213 #define	BCM283X_MEMMAP_ISTERM(ent)	\
214     ((ent)->armc_start == 0 && (ent)->armc_size == 0 && \
215     (ent)->vcbus_start == 0)
216 
217 vm_paddr_t
218 bcm283x_armc_to_vcbus(vm_paddr_t pa)
219 {
220 	struct bcm283x_memory_soc_cfg *cfg;
221 	struct bcm283x_memory_mapping *map, *ment;
222 
223 	/* Guaranteed not NULL if we haven't panicked yet. */
224 	cfg = bcm283x_get_current_memcfg();
225 	map = cfg->memmap;
226 	for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) {
227 		if (pa >= ment->armc_start &&
228 		    pa < ment->armc_start + ment->armc_size) {
229 			return (pa - ment->armc_start) + ment->vcbus_start;
230 		}
231 	}
232 
233 	/*
234 	 * Assume 1:1 mapping for anything else, but complain about it on
235 	 * verbose boots.
236 	 */
237 	if (bootverbose)
238 		printf("bcm283x_vcbus: No armc -> vcbus mapping found: %jx\n",
239 		    (uintmax_t)pa);
240 	return (pa);
241 }
242 
243 vm_paddr_t
244 bcm283x_vcbus_to_armc(vm_paddr_t vca)
245 {
246 	struct bcm283x_memory_soc_cfg *cfg;
247 	struct bcm283x_memory_mapping *map, *ment;
248 
249 	/* Guaranteed not NULL if we haven't panicked yet. */
250 	cfg = bcm283x_get_current_memcfg();
251 	map = cfg->memmap;
252 	for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) {
253 		if (vca >= ment->vcbus_start &&
254 		    vca < ment->vcbus_start + ment->armc_size) {
255 			return (vca - ment->vcbus_start) + ment->armc_start;
256 		}
257 	}
258 
259 	/*
260 	 * Assume 1:1 mapping for anything else, but complain about it on
261 	 * verbose boots.
262 	 */
263 	if (bootverbose)
264 		printf("bcm283x_vcbus: No vcbus -> armc mapping found: %jx\n",
265 		    (uintmax_t)vca);
266 	return (vca);
267 }
268 
269 bus_addr_t
270 bcm283x_dmabus_peripheral_lowaddr(void)
271 {
272 	struct bcm283x_memory_soc_cfg *cfg;
273 
274 	cfg = bcm283x_get_current_memcfg();
275 	return (cfg->busdma_lowaddr);
276 }
277