bcm283x_platform.c revision 1.50 1 /* $NetBSD: bcm283x_platform.c,v 1.50 2025/09/06 21:02:40 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2017 Jared D. McNeill <jmcneill (at) 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 <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: bcm283x_platform.c,v 1.50 2025/09/06 21:02:40 thorpej Exp $");
31
32 #include "opt_arm_debug.h"
33 #include "opt_bcm283x.h"
34 #include "opt_cpuoptions.h"
35 #include "opt_ddb.h"
36 #include "opt_evbarm_boardtype.h"
37 #include "opt_kgdb.h"
38 #include "opt_fdt.h"
39 #include "opt_rpi.h"
40 #include "opt_vcprop.h"
41
42 #include "sdhc.h"
43 #include "bcmsdhost.h"
44 #include "bcmdwctwo.h"
45 #include "bcmspi.h"
46 #include "bsciic.h"
47 #include "plcom.h"
48 #include "com.h"
49 #include "genfb.h"
50 #include "ukbd.h"
51
52 #include <sys/param.h>
53 #include <sys/bus.h>
54 #include <sys/cpu.h>
55 #include <sys/device.h>
56 #include <sys/endian.h>
57 #include <sys/kmem.h>
58 #include <sys/termios.h>
59
60 #include <net/if_ether.h>
61
62 #include <prop/proplib.h>
63
64 #include <dev/fdt/fdtvar.h>
65 #include <dev/fdt/fdt_platform.h>
66
67 #include <uvm/uvm_extern.h>
68
69 #include <machine/bootconfig.h>
70
71 #include <arm/armreg.h>
72 #include <arm/cpufunc.h>
73
74 #include <libfdt.h>
75
76 #include <arm/broadcom/bcm2835reg.h>
77 #include <arm/broadcom/bcm2835var.h>
78 #include <arm/broadcom/bcm283x_platform.h>
79 #include <arm/broadcom/bcm2835_intr.h>
80 #include <arm/broadcom/bcm2835_mbox.h>
81 #include <arm/broadcom/bcm2835_pmwdogvar.h>
82
83 #include <evbarm/dev/plcomreg.h>
84 #include <evbarm/dev/plcomvar.h>
85 #include <evbarm/fdt/machdep.h>
86
87 #include <dev/ic/ns16550reg.h>
88 #include <dev/ic/comreg.h>
89
90 #include <evbarm/rpi/vcio.h>
91 #include <evbarm/rpi/vcpm.h>
92 #include <evbarm/rpi/vcprop.h>
93
94 #include <arm/fdt/arm_fdtvar.h>
95
96 #include <arm/cortex/gtmr_var.h>
97
98 #if NGENFB > 0
99 #include <dev/videomode/videomode.h>
100 #include <dev/videomode/edidvar.h>
101 #include <dev/wscons/wsconsio.h>
102 #endif
103
104 #if NUKBD > 0
105 #include <dev/usb/ukbdvar.h>
106 #endif
107
108 #ifdef DDB
109 #include <machine/db_machdep.h>
110 #include <ddb/db_sym.h>
111 #include <ddb/db_extern.h>
112 #endif
113
114 #define RPI_CPU_MAX 4
115
116 void bcm2835_platform_early_putchar(char c);
117 void bcm2835_aux_platform_early_putchar(char c);
118 void bcm2836_platform_early_putchar(char c);
119 void bcm2837_platform_early_putchar(char c);
120 void bcm2711_platform_early_putchar(char c);
121
122 extern void bcmgenfb_set_console_dev(device_t dev);
123 void bcmgenfb_set_ioctl(int(*)(void *, void *, u_long, void *, int, struct lwp *));
124 extern void bcmgenfb_ddb_trap_callback(int where);
125 static int rpi_ioctl(void *, void *, u_long, void *, int, lwp_t *);
126
127 extern struct bus_space arm_generic_bs_tag;
128 extern struct bus_space arm_generic_a4x_bs_tag;
129
130 /* Prototypes for all the bus_space structure functions */
131 bs_protos(arm_generic);
132 bs_protos(arm_generic_a4x);
133 bs_protos(bcm2835);
134 bs_protos(bcm2835_a4x);
135 bs_protos(bcm2836);
136 bs_protos(bcm2836_a4x);
137 bs_protos(bcm2711);
138 bs_protos(bcm2711_a4x);
139
140 struct bus_space bcm2835_bs_tag;
141 struct bus_space bcm2835_a4x_bs_tag;
142 struct bus_space bcm2836_bs_tag;
143 struct bus_space bcm2836_a4x_bs_tag;
144 struct bus_space bcm2711_bs_tag;
145 struct bus_space bcm2711_a4x_bs_tag;
146
147 static paddr_t bcm2835_bus_to_phys(bus_addr_t);
148 static paddr_t bcm2836_bus_to_phys(bus_addr_t);
149 static paddr_t bcm2711_bus_to_phys(bus_addr_t);
150
151 #ifdef VERBOSE_INIT_ARM
152 #define VPRINTF(...) printf(__VA_ARGS__)
153 #else
154 #define VPRINTF(...) __nothing
155 #endif
156
157 static paddr_t
158 bcm2835_bus_to_phys(bus_addr_t ba)
159 {
160
161 /* Attempt to find the PA device mapping */
162 if (ba >= BCM283X_PERIPHERALS_BASE_BUS &&
163 ba < BCM283X_PERIPHERALS_BASE_BUS + BCM283X_PERIPHERALS_SIZE)
164 return BCM2835_PERIPHERALS_BUS_TO_PHYS(ba);
165
166 return ba & ~BCM2835_BUSADDR_CACHE_MASK;
167 }
168
169 static paddr_t
170 bcm2836_bus_to_phys(bus_addr_t ba)
171 {
172
173 /* Attempt to find the PA device mapping */
174 if (ba >= BCM283X_PERIPHERALS_BASE_BUS &&
175 ba < BCM283X_PERIPHERALS_BASE_BUS + BCM283X_PERIPHERALS_SIZE)
176 return BCM2836_PERIPHERALS_BUS_TO_PHYS(ba);
177
178 if (ba >= BCM2836_ARM_LOCAL_BASE &&
179 ba < BCM2836_ARM_LOCAL_BASE + BCM2836_ARM_LOCAL_SIZE)
180 return ba;
181
182 return ba & ~BCM2835_BUSADDR_CACHE_MASK;
183 }
184
185 static paddr_t
186 bcm2711_bus_to_phys(bus_addr_t ba)
187 {
188
189 /* Attempt to find the PA device mapping */
190 if (ba >= BCM283X_PERIPHERALS_BASE_BUS &&
191 ba < BCM283X_PERIPHERALS_BASE_BUS + BCM283X_PERIPHERALS_SIZE)
192 return BCM2711_PERIPHERALS_BUS_TO_PHYS(ba);
193
194 if (ba >= BCM2711_SCB_BASE_BUS &&
195 ba < BCM2711_SCB_BASE_BUS + BCM2711_SCB_SIZE)
196 return BCM2711_SCB_BUS_TO_PHYS(ba);
197
198 if (ba >= BCM2711_ARM_LOCAL_BASE_BUS &&
199 ba < BCM2711_ARM_LOCAL_BASE_BUS + BCM2711_ARM_LOCAL_SIZE)
200 return BCM2711_ARM_LOCAL_BUS_TO_PHYS(ba);
201
202 return ba & ~BCM2835_BUSADDR_CACHE_MASK;
203 }
204
205 int
206 bcm2835_bs_map(void *t, bus_addr_t ba, bus_size_t size, int flag,
207 bus_space_handle_t *bshp)
208 {
209 const paddr_t pa = bcm2835_bus_to_phys(ba);
210
211 return bus_space_map(&arm_generic_bs_tag, pa, size, flag, bshp);
212 }
213
214 paddr_t
215 bcm2835_bs_mmap(void *t, bus_addr_t ba, off_t offset, int prot, int flags)
216 {
217 const paddr_t pa = bcm2835_bus_to_phys(ba);
218
219 return bus_space_mmap(&arm_generic_bs_tag, pa, offset, prot, flags);
220 }
221
222 paddr_t
223 bcm2835_a4x_bs_mmap(void *t, bus_addr_t ba, off_t offset, int prot, int flags)
224 {
225
226 return bcm2835_bs_mmap(t, ba, 4 * offset, prot, flags);
227 }
228
229 int
230 bcm2836_bs_map(void *t, bus_addr_t ba, bus_size_t size, int flag,
231 bus_space_handle_t *bshp)
232 {
233 const paddr_t pa = bcm2836_bus_to_phys(ba);
234
235 return bus_space_map(&arm_generic_bs_tag, pa, size, flag, bshp);
236 }
237
238 paddr_t
239 bcm2836_bs_mmap(void *t, bus_addr_t ba, off_t offset, int prot, int flags)
240 {
241 const paddr_t pa = bcm2836_bus_to_phys(ba);
242
243 return bus_space_mmap(&arm_generic_bs_tag, pa, offset, prot, flags);
244 }
245
246 paddr_t
247 bcm2836_a4x_bs_mmap(void *t, bus_addr_t ba, off_t offset, int prot, int flags)
248 {
249
250 return bcm2836_bs_mmap(t, ba, 4 * offset, prot, flags);
251 }
252
253 int
254 bcm2711_bs_map(void *t, bus_addr_t ba, bus_size_t size, int flag,
255 bus_space_handle_t *bshp)
256 {
257 const paddr_t pa = bcm2711_bus_to_phys(ba);
258
259 return bus_space_map(&arm_generic_bs_tag, pa, size, flag, bshp);
260 }
261
262 paddr_t
263 bcm2711_bs_mmap(void *t, bus_addr_t ba, off_t offset, int prot, int flags)
264 {
265 const paddr_t pa = bcm2711_bus_to_phys(ba);
266
267 return bus_space_mmap(&arm_generic_bs_tag, pa, offset, prot, flags);
268 }
269
270 paddr_t
271 bcm2711_a4x_bs_mmap(void *t, bus_addr_t ba, off_t offset, int prot, int flags)
272 {
273
274 return bcm2711_bs_mmap(t, ba, 4 * offset, prot, flags);
275 }
276
277 #if defined(SOC_BCM2835)
278 static const struct pmap_devmap *
279 bcm2835_platform_devmap(void)
280 {
281 static const struct pmap_devmap devmap[] = {
282 DEVMAP_ENTRY(BCM2835_PERIPHERALS_VBASE, BCM2835_PERIPHERALS_BASE,
283 BCM283X_PERIPHERALS_SIZE), /* 16Mb */
284
285 DEVMAP_ENTRY_END
286 };
287
288 return devmap;
289 }
290 #endif
291
292 #if defined(SOC_BCM2836)
293 static const struct pmap_devmap *
294 bcm2836_platform_devmap(void)
295 {
296 static const struct pmap_devmap devmap[] = {
297 DEVMAP_ENTRY(BCM2836_PERIPHERALS_VBASE, BCM2836_PERIPHERALS_BASE,
298 BCM283X_PERIPHERALS_SIZE), /* 16Mb */
299 DEVMAP_ENTRY(BCM2836_ARM_LOCAL_VBASE, BCM2836_ARM_LOCAL_BASE,
300 BCM2836_ARM_LOCAL_SIZE),
301 #if defined(MULTIPROCESSOR) && defined(__aarch64__)
302 /* for fdt cpu spin-table */
303 DEVMAP_ENTRY(BCM2836_ARM_SMP_VBASE, BCM2836_ARM_SMP_BASE,
304 BCM2836_ARM_SMP_SIZE),
305 #endif
306 DEVMAP_ENTRY_END
307 };
308
309 return devmap;
310 }
311
312 static const struct pmap_devmap *
313 bcm2711_platform_devmap(void)
314 {
315 static const struct pmap_devmap devmap[] = {
316 DEVMAP_ENTRY(BCM2711_PERIPHERALS_VBASE, BCM2711_PERIPHERALS_BASE,
317 BCM283X_PERIPHERALS_SIZE), /* 16Mb */
318 DEVMAP_ENTRY(BCM2711_ARM_LOCAL_VBASE, BCM2711_ARM_LOCAL_BASE,
319 BCM2711_ARM_LOCAL_SIZE),
320 #if defined(MULTIPROCESSOR) && defined(__aarch64__)
321 /* for fdt cpu spin-table */
322 DEVMAP_ENTRY(BCM2711_ARM_SMP_VBASE, BCM2836_ARM_SMP_BASE,
323 BCM2836_ARM_SMP_SIZE),
324 #endif
325 DEVMAP_ENTRY_END
326 };
327
328 return devmap;
329 }
330 #endif
331
332 /*
333 * Macros to translate between physical and virtual for a subset of the
334 * kernel address space. *Not* for general use.
335 */
336
337 #ifndef RPI_FB_WIDTH
338 #define RPI_FB_WIDTH 1280
339 #endif
340 #ifndef RPI_FB_HEIGHT
341 #define RPI_FB_HEIGHT 720
342 #endif
343
344 int uart_clk = BCM2835_UART0_CLK;
345 int core_clk;
346
347 static struct {
348 struct vcprop_buffer_hdr vb_hdr;
349 struct vcprop_tag_clockrate vbt_uartclockrate;
350 struct vcprop_tag_clockrate vbt_vpuclockrate;
351 struct vcprop_tag end;
352 } vb_uart __cacheline_aligned = {
353 .vb_hdr = {
354 .vpb_len = htole32(sizeof(vb_uart)),
355 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
356 },
357 .vbt_uartclockrate = {
358 .tag = {
359 .vpt_tag = htole32(VCPROPTAG_GET_CLOCKRATE),
360 .vpt_len =
361 htole32(VCPROPTAG_LEN(vb_uart.vbt_uartclockrate)),
362 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
363 },
364 .id = htole32(VCPROP_CLK_UART)
365 },
366 .vbt_vpuclockrate = {
367 .tag = {
368 .vpt_tag = htole32(VCPROPTAG_GET_CLOCKRATE),
369 .vpt_len = htole32(VCPROPTAG_LEN(vb_uart.vbt_vpuclockrate)),
370 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
371 },
372 .id = htole32(VCPROP_CLK_CORE)
373 },
374 .end = {
375 .vpt_tag = htole32(VCPROPTAG_NULL)
376 }
377 };
378
379 static struct {
380 struct vcprop_buffer_hdr vb_hdr;
381 struct vcprop_tag_fwrev vbt_fwrev;
382 struct vcprop_tag_boardmodel vbt_boardmodel;
383 struct vcprop_tag_boardrev vbt_boardrev;
384 struct vcprop_tag_macaddr vbt_macaddr;
385 struct vcprop_tag_memory vbt_memory;
386 struct vcprop_tag_boardserial vbt_serial;
387 struct vcprop_tag_dmachan vbt_dmachan;
388 struct vcprop_tag_cmdline vbt_cmdline;
389 struct vcprop_tag_clockrate vbt_emmcclockrate;
390 struct vcprop_tag_clockrate vbt_armclockrate;
391 struct vcprop_tag_clockrate vbt_vpuclockrate;
392 struct vcprop_tag_clockrate vbt_emmc2clockrate;
393 struct vcprop_tag end;
394 } vb __cacheline_aligned = {
395 .vb_hdr = {
396 .vpb_len = htole32(sizeof(vb)),
397 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
398 },
399 .vbt_fwrev = {
400 .tag = {
401 .vpt_tag = htole32(VCPROPTAG_GET_FIRMWAREREV),
402 .vpt_len = htole32(VCPROPTAG_LEN(vb.vbt_fwrev)),
403 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
404 },
405 },
406 .vbt_boardmodel = {
407 .tag = {
408 .vpt_tag = htole32(VCPROPTAG_GET_BOARDMODEL),
409 .vpt_len = htole32(VCPROPTAG_LEN(vb.vbt_boardmodel)),
410 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
411 },
412 },
413 .vbt_boardrev = {
414 .tag = {
415 .vpt_tag = htole32(VCPROPTAG_GET_BOARDREVISION),
416 .vpt_len = htole32(VCPROPTAG_LEN(vb.vbt_boardrev)),
417 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
418 },
419 },
420 .vbt_macaddr = {
421 .tag = {
422 .vpt_tag = htole32(VCPROPTAG_GET_MACADDRESS),
423 .vpt_len = htole32(VCPROPTAG_LEN(vb.vbt_macaddr)),
424 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
425 },
426 },
427 .vbt_memory = {
428 .tag = {
429 .vpt_tag = htole32(VCPROPTAG_GET_ARMMEMORY),
430 .vpt_len = htole32(VCPROPTAG_LEN(vb.vbt_memory)),
431 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
432 },
433 },
434 .vbt_serial = {
435 .tag = {
436 .vpt_tag = htole32(VCPROPTAG_GET_BOARDSERIAL),
437 .vpt_len = htole32(VCPROPTAG_LEN(vb.vbt_serial)),
438 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
439 },
440 },
441 .vbt_dmachan = {
442 .tag = {
443 .vpt_tag = htole32(VCPROPTAG_GET_DMACHAN),
444 .vpt_len = htole32(VCPROPTAG_LEN(vb.vbt_dmachan)),
445 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
446 },
447 },
448 .vbt_cmdline = {
449 .tag = {
450 .vpt_tag = htole32(VCPROPTAG_GET_CMDLINE),
451 .vpt_len = htole32(VCPROPTAG_LEN(vb.vbt_cmdline)),
452 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
453 },
454 },
455 .vbt_emmcclockrate = {
456 .tag = {
457 .vpt_tag = htole32(VCPROPTAG_GET_CLOCKRATE),
458 .vpt_len = htole32(VCPROPTAG_LEN(vb.vbt_emmcclockrate)),
459 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
460 },
461 .id = htole32(VCPROP_CLK_EMMC)
462 },
463 .vbt_armclockrate = {
464 .tag = {
465 .vpt_tag = htole32(VCPROPTAG_GET_CLOCKRATE),
466 .vpt_len = htole32(VCPROPTAG_LEN(vb.vbt_armclockrate)),
467 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
468 },
469 .id = htole32(VCPROP_CLK_ARM)
470 },
471 .vbt_vpuclockrate = {
472 .tag = {
473 .vpt_tag = htole32(VCPROPTAG_GET_CLOCKRATE),
474 .vpt_len = htole32(VCPROPTAG_LEN(vb.vbt_vpuclockrate)),
475 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
476 },
477 .id = htole32(VCPROP_CLK_CORE)
478 },
479 .vbt_emmc2clockrate = {
480 .tag = {
481 .vpt_tag = htole32(VCPROPTAG_GET_CLOCKRATE),
482 .vpt_len =
483 htole32(VCPROPTAG_LEN(vb.vbt_emmc2clockrate)),
484 .vpt_rcode = htole32(VCPROPTAG_REQUEST)
485 },
486 .id = htole32(VCPROP_CLK_EMMC2)
487 },
488 .end = {
489 .vpt_tag = htole32(VCPROPTAG_NULL)
490 }
491 };
492
493 #if NGENFB > 0
494 static struct {
495 struct vcprop_buffer_hdr vb_hdr;
496 struct vcprop_tag_edidblock vbt_edid;
497 struct vcprop_tag end;
498 } vb_edid __cacheline_aligned = {
499 .vb_hdr = {
500 .vpb_len = htole32(sizeof(vb_edid)),
501 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
502 },
503 .vbt_edid = {
504 .tag = {
505 .vpt_tag = htole32(VCPROPTAG_GET_EDID_BLOCK),
506 .vpt_len = htole32(VCPROPTAG_LEN(vb_edid.vbt_edid)),
507 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
508 },
509 .blockno = htole32(0),
510 },
511 .end = {
512 .vpt_tag = htole32(VCPROPTAG_NULL)
513 }
514 };
515
516 static struct {
517 struct vcprop_buffer_hdr vb_hdr;
518 struct vcprop_tag_fbres vbt_res;
519 struct vcprop_tag_fbres vbt_vres;
520 struct vcprop_tag_fbdepth vbt_depth;
521 struct vcprop_tag_fbalpha vbt_alpha;
522 struct vcprop_tag_allocbuf vbt_allocbuf;
523 struct vcprop_tag_blankscreen vbt_blank;
524 struct vcprop_tag_fbpitch vbt_pitch;
525 struct vcprop_tag end;
526 } vb_setfb __cacheline_aligned = {
527 .vb_hdr = {
528 .vpb_len = htole32(sizeof(vb_setfb)),
529 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
530 },
531 .vbt_res = {
532 .tag = {
533 .vpt_tag = htole32(VCPROPTAG_SET_FB_RES),
534 .vpt_len = htole32(VCPROPTAG_LEN(vb_setfb.vbt_res)),
535 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
536 },
537 .width = htole32(0),
538 .height = htole32(0),
539 },
540 .vbt_vres = {
541 .tag = {
542 .vpt_tag = htole32(VCPROPTAG_SET_FB_VRES),
543 .vpt_len = htole32(VCPROPTAG_LEN(vb_setfb.vbt_vres)),
544 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
545 },
546 .width = htole32(0),
547 .height = htole32(0),
548 },
549 .vbt_depth = {
550 .tag = {
551 .vpt_tag = htole32(VCPROPTAG_SET_FB_DEPTH),
552 .vpt_len = htole32(VCPROPTAG_LEN(vb_setfb.vbt_depth)),
553 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
554 },
555 .bpp = htole32(32),
556 },
557 .vbt_alpha = {
558 .tag = {
559 .vpt_tag = htole32(VCPROPTAG_SET_FB_ALPHA_MODE),
560 .vpt_len = htole32(VCPROPTAG_LEN(vb_setfb.vbt_alpha)),
561 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
562 },
563 .state = htole32(VCPROP_ALPHA_IGNORED),
564 },
565 .vbt_allocbuf = {
566 .tag = {
567 .vpt_tag = htole32(VCPROPTAG_ALLOCATE_BUFFER),
568 .vpt_len =
569 htole32(VCPROPTAG_LEN(vb_setfb.vbt_allocbuf)),
570 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
571 },
572 .address = htole32(PAGE_SIZE), /* alignment */
573 },
574 .vbt_blank = {
575 .tag = {
576 .vpt_tag = htole32(VCPROPTAG_BLANK_SCREEN),
577 .vpt_len = htole32(VCPROPTAG_LEN(vb_setfb.vbt_blank)),
578 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
579 },
580 .state = htole32(VCPROP_BLANK_OFF),
581 },
582 .vbt_pitch = {
583 .tag = {
584 .vpt_tag = htole32(VCPROPTAG_GET_FB_PITCH),
585 .vpt_len = htole32(VCPROPTAG_LEN(vb_setfb.vbt_pitch)),
586 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
587 },
588 },
589 .end = {
590 .vpt_tag = htole32(VCPROPTAG_NULL),
591 },
592 };
593
594 #endif
595
596 static int rpi_video_on = WSDISPLAYIO_VIDEO_ON;
597
598 #if defined(RPI_HWCURSOR)
599 #define CURSOR_BITMAP_SIZE (64 * 8)
600 #define CURSOR_ARGB_SIZE (64 * 64 * 4)
601 static uint32_t hcursor = 0;
602 static bus_addr_t pcursor = 0;
603 static uint32_t *cmem = NULL;
604 static int cursor_x = 0, cursor_y = 0, hot_x = 0, hot_y = 0, cursor_on = 0;
605 static uint32_t cursor_cmap[4];
606 static uint8_t cursor_mask[8 * 64], cursor_bitmap[8 * 64];
607 #endif
608
609 u_int
610 bcm283x_clk_get_rate_uart(void)
611 {
612
613 if (vcprop_tag_success_p(&vb_uart.vbt_uartclockrate.tag))
614 return le32toh(vb_uart.vbt_uartclockrate.rate);
615 return 0;
616 }
617
618 u_int
619 bcm283x_clk_get_rate_vpu(void)
620 {
621
622 if (vcprop_tag_success_p(&vb.vbt_vpuclockrate.tag) &&
623 vb.vbt_vpuclockrate.rate != 0) {
624 return le32toh(vb.vbt_vpuclockrate.rate);
625 }
626 return 0;
627 }
628
629 u_int
630 bcm283x_clk_get_rate_emmc(void)
631 {
632
633 if (vcprop_tag_success_p(&vb.vbt_emmcclockrate.tag) &&
634 vb.vbt_emmcclockrate.rate != 0) {
635 return le32toh(vb.vbt_emmcclockrate.rate);
636 }
637 return 0;
638 }
639
640 u_int
641 bcm283x_clk_get_rate_emmc2(void)
642 {
643
644 if (vcprop_tag_success_p(&vb.vbt_emmc2clockrate.tag) &&
645 vb.vbt_emmc2clockrate.rate != 0) {
646 return le32toh(vb.vbt_emmc2clockrate.rate);
647 }
648 return 0;
649 }
650
651
652
653 static void
654 bcm283x_uartinit(bus_space_tag_t iot, bus_space_handle_t ioh)
655 {
656 uint32_t res;
657
658 bcm2835_mbox_write(iot, ioh, BCMMBOX_CHANARM2VC,
659 KERN_VTOPHYS((vaddr_t)&vb_uart));
660
661 bcm2835_mbox_read(iot, ioh, BCMMBOX_CHANARM2VC, &res);
662
663 /*
664 * RPI4 has Cortex A72 processors which do speculation, so
665 * we need to invalidate the cache for an updates done by
666 * the firmware
667 */
668 cpu_dcache_inv_range((vaddr_t)&vb_uart, sizeof(vb_uart));
669
670 if (vcprop_tag_success_p(&vb_uart.vbt_uartclockrate.tag))
671 uart_clk = le32toh(vb_uart.vbt_uartclockrate.rate);
672 if (vcprop_tag_success_p(&vb_uart.vbt_vpuclockrate.tag))
673 core_clk = le32toh(vb_uart.vbt_vpuclockrate.rate);
674 }
675
676 #if defined(SOC_BCM2835)
677 static void
678 bcm2835_uartinit(void)
679 {
680 const paddr_t pa = BCM2835_PERIPHERALS_BUS_TO_PHYS(BCM2835_ARMMBOX_BASE);
681 const bus_space_tag_t iot = &bcm2835_bs_tag;
682 const bus_space_handle_t ioh = BCM2835_IOPHYSTOVIRT(pa);
683
684 bcm283x_uartinit(iot, ioh);
685 }
686 #endif
687
688 #if defined(SOC_BCM2836)
689 static void
690 bcm2836_uartinit(void)
691 {
692 const paddr_t pa = BCM2836_PERIPHERALS_BUS_TO_PHYS(BCM2835_ARMMBOX_BASE);
693 const bus_space_tag_t iot = &bcm2836_bs_tag;
694 const bus_space_handle_t ioh = BCM2835_IOPHYSTOVIRT(pa);
695
696 bcm283x_uartinit(iot, ioh);
697 }
698
699 static void
700 bcm2711_uartinit(void)
701 {
702 const paddr_t pa = BCM2711_PERIPHERALS_BUS_TO_PHYS(BCM2835_ARMMBOX_BASE);
703 const bus_space_tag_t iot = &bcm2711_bs_tag;
704 const bus_space_handle_t ioh = BCM2711_IOPHYSTOVIRT(pa);
705
706 bcm283x_uartinit(iot, ioh);
707 }
708 #endif
709
710 #define BCM283x_MINIMUM_SPLIT (128U * 1024 * 1024)
711
712 static size_t bcm283x_memorysize;
713
714 static void
715 bcm283x_bootparams(bus_space_tag_t iot, bus_space_handle_t ioh)
716 {
717 uint32_t res;
718
719 bcm2835_mbox_write(iot, ioh, BCMMBOX_CHANPM, (
720 #if (NSDHC > 0)
721 (1 << VCPM_POWER_SDCARD) |
722 #endif
723 #if (NPLCOM > 0)
724 (1 << VCPM_POWER_UART0) |
725 #endif
726 #if (NBCMDWCTWO > 0)
727 (1 << VCPM_POWER_USB) |
728 #endif
729 #if (NBSCIIC > 0)
730 (1 << VCPM_POWER_I2C0) | (1 << VCPM_POWER_I2C1) |
731 /* (1 << VCPM_POWER_I2C2) | */
732 #endif
733 #if (NBCMSPI > 0)
734 (1 << VCPM_POWER_SPI) |
735 #endif
736 0) << 4);
737
738 bcm2835_mbox_write(iot, ioh, BCMMBOX_CHANARM2VC,
739 KERN_VTOPHYS((vaddr_t)&vb));
740
741 bcm2835_mbox_read(iot, ioh, BCMMBOX_CHANARM2VC, &res);
742
743 /*
744 * RPI4 has Cortex A72 processors which do speculation, so
745 * we need to invalidate the cache for an updates done by
746 * the firmware
747 */
748 cpu_dcache_inv_range((vaddr_t)&vb, sizeof(vb));
749
750 if (!vcprop_buffer_success_p(&vb.vb_hdr)) {
751 bootconfig.dramblocks = 1;
752 bootconfig.dram[0].address = 0x0;
753 bootconfig.dram[0].pages = atop(BCM283x_MINIMUM_SPLIT);
754 return;
755 }
756
757 struct vcprop_tag_memory *vptp_mem = &vb.vbt_memory;
758 if (vcprop_tag_success_p(&vptp_mem->tag)) {
759 size_t n = vcprop_tag_resplen(&vptp_mem->tag) /
760 sizeof(struct vcprop_memory);
761
762 bcm283x_memorysize = 0;
763 bootconfig.dramblocks = 0;
764
765 for (int i = 0; i < n && i < DRAM_BLOCKS; i++) {
766 bootconfig.dram[i].address =
767 le32toh(vptp_mem->mem[i].base);
768 bootconfig.dram[i].pages =
769 atop(le32toh(vptp_mem->mem[i].size));
770 bootconfig.dramblocks++;
771
772 bcm283x_memorysize += le32toh(vptp_mem->mem[i].size);
773 }
774 }
775
776 if (vcprop_tag_success_p(&vb.vbt_armclockrate.tag))
777 curcpu()->ci_data.cpu_cc_freq =
778 le32toh(vb.vbt_armclockrate.rate);
779
780 #ifdef VERBOSE_INIT_ARM
781 if (vcprop_tag_success_p(&vb.vbt_memory.tag))
782 printf("%s: memory size %zu\n", __func__,
783 bcm283x_memorysize);
784 if (vcprop_tag_success_p(&vb.vbt_armclockrate.tag))
785 printf("%s: arm clock %d\n", __func__,
786 le32toh(vb.vbt_armclockrate.rate));
787 if (vcprop_tag_success_p(&vb.vbt_vpuclockrate.tag))
788 printf("%s: vpu clock %d\n", __func__,
789 le32toh(vb.vbt_vpuclockrate.rate));
790 if (vcprop_tag_success_p(&vb.vbt_emmcclockrate.tag))
791 printf("%s: emmc clock %d\n", __func__,
792 le32toh(vb.vbt_emmcclockrate.rate));
793 if (vcprop_tag_success_p(&vb.vbt_emmc2clockrate.tag))
794 printf("%s: emmc2 clock %d\n", __func__,
795 le32toh(vb.vbt_emmcclockrate.rate));
796 if (vcprop_tag_success_p(&vb.vbt_fwrev.tag))
797 printf("%s: firmware rev %x\n", __func__,
798 le32toh(vb.vbt_fwrev.rev));
799 if (vcprop_tag_success_p(&vb.vbt_boardmodel.tag))
800 printf("%s: board model %x\n", __func__,
801 le32toh(vb.vbt_boardmodel.model));
802 if (vcprop_tag_success_p(&vb.vbt_macaddr.tag))
803 printf("%s: mac-address %" PRIx64 "\n", __func__,
804 le64toh(vb.vbt_macaddr.addr));
805 if (vcprop_tag_success_p(&vb.vbt_boardrev.tag))
806 printf("%s: board rev %x\n", __func__,
807 le32toh(vb.vbt_boardrev.rev));
808 if (vcprop_tag_success_p(&vb.vbt_serial.tag))
809 printf("%s: board serial %" PRIx64 "\n", __func__,
810 le64toh(vb.vbt_serial.sn));
811 if (vcprop_tag_success_p(&vb.vbt_dmachan.tag))
812 printf("%s: DMA channel mask 0x%08x\n", __func__,
813 le32toh(vb.vbt_dmachan.mask));
814
815 if (vcprop_tag_success_p(&vb.vbt_cmdline.tag))
816 printf("%s: cmdline %s\n", __func__,
817 vb.vbt_cmdline.cmdline);
818 #endif
819 }
820
821 #if defined(SOC_BCM2835)
822 static void
823 bcm2835_bootparams(void)
824 {
825 const paddr_t pa = BCM2835_PERIPHERALS_BUS_TO_PHYS(BCM2835_ARMMBOX_BASE);
826 const bus_space_tag_t iot = &bcm2835_bs_tag;
827 const bus_space_handle_t ioh = BCM2835_IOPHYSTOVIRT(pa);
828
829 bcm283x_bootparams(iot, ioh);
830 }
831 #endif
832
833 #if defined(SOC_BCM2836)
834 static void
835 bcm2836_bootparams(void)
836 {
837 const paddr_t pa = BCM2836_PERIPHERALS_BUS_TO_PHYS(BCM2835_ARMMBOX_BASE);
838 const bus_space_tag_t iot = &bcm2836_bs_tag;
839 const bus_space_handle_t ioh = BCM2835_IOPHYSTOVIRT(pa);
840
841 bcm283x_bootparams(iot, ioh);
842 }
843
844 static void
845 bcm2711_bootparams(void)
846 {
847 const paddr_t pa = BCM2711_PERIPHERALS_BUS_TO_PHYS(BCM2835_ARMMBOX_BASE);
848 const bus_space_tag_t iot = &bcm2711_bs_tag;
849 const bus_space_handle_t ioh = BCM2711_IOPHYSTOVIRT(pa);
850
851 bcm283x_bootparams(iot, ioh);
852 }
853
854 #if defined(MULTIPROCESSOR)
855 static int
856 cpu_enable_bcm2836(int phandle)
857 {
858 bus_space_tag_t iot = &bcm2836_bs_tag;
859 bus_space_handle_t ioh = BCM2836_ARM_LOCAL_VBASE;
860 uint64_t mpidr;
861
862 fdtbus_get_reg64(phandle, 0, &mpidr, NULL);
863
864 const u_int cpuno = __SHIFTOUT(mpidr, MPIDR_AFF0);
865
866 bus_space_write_4(iot, ioh, BCM2836_LOCAL_MAILBOX3_SETN(cpuno),
867 KERN_VTOPHYS((vaddr_t)cpu_mpstart));
868
869 return 0;
870 }
871 ARM_CPU_METHOD(bcm2836, "brcm,bcm2836-smp", cpu_enable_bcm2836);
872 #endif
873
874 #endif /* SOC_BCM2836 */
875
876 #if NGENFB > 0
877 static bool
878 rpi_fb_parse_mode(const char *s, uint32_t *pwidth, uint32_t *pheight)
879 {
880 char *x;
881
882 if (strncmp(s, "disable", 7) == 0)
883 return false;
884
885 x = strchr(s, 'x');
886 if (x) {
887 *pwidth = strtoul(s, NULL, 10);
888 *pheight = strtoul(x + 1, NULL, 10);
889 }
890
891 return true;
892 }
893
894 #define RPI_EDIDSIZE 1024
895
896 static bool
897 rpi_fb_get_edid_mode(uint32_t *pwidth, uint32_t *pheight)
898 {
899 struct edid_info ei;
900 uint32_t res;
901 int error;
902
903 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_edid,
904 sizeof(vb_edid), &res);
905 if (error) {
906 printf("%s: mbox request failed (%d)\n", __func__, error);
907 return false;
908 }
909
910 if (!vcprop_buffer_success_p(&vb_edid.vb_hdr) ||
911 !vcprop_tag_success_p(&vb_edid.vbt_edid.tag) ||
912 vb_edid.vbt_edid.status != 0)
913 return false;
914
915 uint8_t *edid_data = kmem_alloc(RPI_EDIDSIZE, KM_SLEEP);
916
917 memset(edid_data, 0, RPI_EDIDSIZE);
918 memcpy(edid_data, vb_edid.vbt_edid.data,
919 sizeof(vb_edid.vbt_edid.data));
920 edid_parse(edid_data, &ei);
921 #ifdef VERBOSE_INIT_ARM
922 edid_print(&ei);
923 #endif
924
925 if (ei.edid_preferred_mode) {
926 *pwidth = ei.edid_preferred_mode->hdisplay;
927 *pheight = ei.edid_preferred_mode->vdisplay;
928 }
929
930 kmem_free(edid_data, RPI_EDIDSIZE);
931
932 return true;
933 }
934
935 /*
936 * Initialize framebuffer console.
937 *
938 * Some notes about boot parameters:
939 * - If "fb=disable" is present, ignore framebuffer completely.
940 * - If "fb=<width>x<height> is present, use the specified mode.
941 * - If "console=fb" is present, attach framebuffer to console.
942 */
943 static bool
944 rpi_fb_init(prop_dictionary_t dict, void *aux)
945 {
946 uint32_t width = 0, height = 0;
947 uint32_t res;
948 char *ptr;
949 int integer;
950 int error;
951 bool is_bgr = true;
952
953 if (get_bootconf_option(boot_args, "fb",
954 BOOTOPT_TYPE_STRING, &ptr)) {
955 if (rpi_fb_parse_mode(ptr, &width, &height) == false)
956 return false;
957 }
958 if (width == 0 || height == 0) {
959 rpi_fb_get_edid_mode(&width, &height);
960 }
961 if (width == 0 || height == 0) {
962 width = RPI_FB_WIDTH;
963 height = RPI_FB_HEIGHT;
964 }
965
966 vb_setfb.vbt_res.width = htole32(width);
967 vb_setfb.vbt_res.height = htole32(height);
968 vb_setfb.vbt_vres.width = htole32(width);
969 vb_setfb.vbt_vres.height = htole32(height);
970 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_setfb,
971 sizeof(vb_setfb), &res);
972 if (error) {
973 printf("%s: mbox request failed (%d)\n", __func__, error);
974 return false;
975 }
976
977 if (!vcprop_buffer_success_p(&vb_setfb.vb_hdr) ||
978 !vcprop_tag_success_p(&vb_setfb.vbt_res.tag) ||
979 !vcprop_tag_success_p(&vb_setfb.vbt_vres.tag) ||
980 !vcprop_tag_success_p(&vb_setfb.vbt_depth.tag) ||
981 !vcprop_tag_success_p(&vb_setfb.vbt_allocbuf.tag) ||
982 !vcprop_tag_success_p(&vb_setfb.vbt_blank.tag) ||
983 !vcprop_tag_success_p(&vb_setfb.vbt_pitch.tag)) {
984 printf("%s: prop tag failed\n", __func__);
985 return false;
986 }
987
988 #ifdef VERBOSE_INIT_ARM
989 printf("%s: addr = 0x%x size = %d\n", __func__,
990 le32toh(vb_setfb.vbt_allocbuf.address),
991 le32toh(vb_setfb.vbt_allocbuf.size));
992 printf("%s: depth = %d\n", __func__, le32toh(vb_setfb.vbt_depth.bpp));
993 printf("%s: pitch = %d\n", __func__,
994 le32toh(vb_setfb.vbt_pitch.linebytes));
995 printf("%s: width = %d height = %d\n", __func__,
996 le32toh(vb_setfb.vbt_res.width), le32toh(vb_setfb.vbt_res.height));
997 printf("%s: vwidth = %d vheight = %d\n", __func__,
998 le32toh(vb_setfb.vbt_vres.width),
999 le32toh(vb_setfb.vbt_vres.height));
1000 #endif
1001
1002 if (vb_setfb.vbt_allocbuf.address == 0 ||
1003 vb_setfb.vbt_allocbuf.size == 0 ||
1004 vb_setfb.vbt_res.width == 0 ||
1005 vb_setfb.vbt_res.height == 0 ||
1006 vb_setfb.vbt_vres.width == 0 ||
1007 vb_setfb.vbt_vres.height == 0 ||
1008 vb_setfb.vbt_pitch.linebytes == 0) {
1009 printf("%s: failed to set mode %ux%u\n", __func__,
1010 width, height);
1011 return false;
1012 }
1013
1014 prop_dictionary_set_uint32(dict, "width",
1015 le32toh(vb_setfb.vbt_res.width));
1016 prop_dictionary_set_uint32(dict, "height",
1017 le32toh(vb_setfb.vbt_res.height));
1018 prop_dictionary_set_uint8(dict, "depth",
1019 le32toh(vb_setfb.vbt_depth.bpp));
1020 prop_dictionary_set_uint16(dict, "linebytes",
1021 le32toh(vb_setfb.vbt_pitch.linebytes));
1022 prop_dictionary_set_uint32(dict, "address",
1023 le32toh(vb_setfb.vbt_allocbuf.address));
1024
1025 /*
1026 * Old firmware uses BGR. New firmware uses RGB. The get and set
1027 * pixel order mailbox properties don't seem to work. The firmware
1028 * adds a kernel cmdline option bcm2708_fb.fbswap=<0|1>, so use it
1029 * to determine pixel order. 0 means BGR, 1 means RGB.
1030 *
1031 * See https://github.com/raspberrypi/linux/issues/514
1032 */
1033 if (get_bootconf_option(boot_args, "bcm2708_fb.fbswap",
1034 BOOTOPT_TYPE_INT, &integer)) {
1035 is_bgr = integer == 0;
1036 }
1037 prop_dictionary_set_bool(dict, "is_bgr", is_bgr);
1038
1039 /* if "genfb.type=<n>" is passed in cmdline, override wsdisplay type */
1040 if (get_bootconf_option(boot_args, "genfb.type",
1041 BOOTOPT_TYPE_INT, &integer)) {
1042 prop_dictionary_set_uint32(dict, "wsdisplay_type", integer);
1043 }
1044
1045 #if defined(RPI_HWCURSOR)
1046 struct fdt_attach_args *faa = aux;
1047 bus_space_handle_t hc;
1048
1049 hcursor = rpi_alloc_mem(CURSOR_ARGB_SIZE, PAGE_SIZE,
1050 MEM_FLAG_L1_NONALLOCATING | MEM_FLAG_HINT_PERMALOCK);
1051 pcursor = rpi_lock_mem(hcursor);
1052 #ifdef RPI_IOCTL_DEBUG
1053 printf("hcursor: %08x\n", hcursor);
1054 printf("pcursor: %08x\n", (uint32_t)pcursor);
1055 printf("fb: %08x\n", (uint32_t)vb_setfb.vbt_allocbuf.address);
1056 #endif
1057 if (bus_space_map(faa->faa_bst, pcursor, CURSOR_ARGB_SIZE,
1058 BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_PREFETCHABLE, &hc) != 0) {
1059 printf("couldn't map cursor memory\n");
1060 } else {
1061 int i, j, k;
1062
1063 cmem = bus_space_vaddr(faa->faa_bst, hc);
1064 k = 0;
1065 for (j = 0; j < 64; j++) {
1066 for (i = 0; i < 64; i++) {
1067 cmem[i + k] =
1068 ((i & 8) ^ (j & 8)) ? 0xa0ff0000 : 0xa000ff00;
1069 }
1070 k += 64;
1071 }
1072 cpu_dcache_wb_range((vaddr_t)cmem, CURSOR_ARGB_SIZE);
1073 rpi_fb_initcursor(pcursor, 0, 0);
1074 #ifdef RPI_IOCTL_DEBUG
1075 rpi_fb_movecursor(600, 400, 1);
1076 #else
1077 rpi_fb_movecursor(cursor_x, cursor_y, cursor_on);
1078 #endif
1079 }
1080 #endif
1081
1082 return true;
1083 }
1084
1085
1086 #if defined(RPI_HWCURSOR)
1087 static int
1088 rpi_fb_do_cursor(struct wsdisplay_cursor *cur)
1089 {
1090 int pos = 0;
1091 int shape = 0;
1092
1093 if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
1094 if (cursor_on != cur->enable) {
1095 cursor_on = cur->enable;
1096 pos = 1;
1097 }
1098 }
1099 if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
1100
1101 hot_x = cur->hot.x;
1102 hot_y = cur->hot.y;
1103 pos = 1;
1104 shape = 1;
1105 }
1106 if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
1107
1108 cursor_x = cur->pos.x;
1109 cursor_y = cur->pos.y;
1110 pos = 1;
1111 }
1112 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
1113 int i;
1114 uint32_t val;
1115
1116 for (i = 0; i < uimin(cur->cmap.count, 3); i++) {
1117 val = (cur->cmap.red[i] << 16 ) |
1118 (cur->cmap.green[i] << 8) |
1119 (cur->cmap.blue[i] ) |
1120 0xff000000;
1121 cursor_cmap[i + cur->cmap.index + 2] = val;
1122 }
1123 shape = 1;
1124 }
1125 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
1126 int err;
1127
1128 err = copyin(cur->mask, cursor_mask, CURSOR_BITMAP_SIZE);
1129 err += copyin(cur->image, cursor_bitmap, CURSOR_BITMAP_SIZE);
1130 if (err != 0)
1131 return EFAULT;
1132 shape = 1;
1133 }
1134 if (shape) {
1135 int i, j, idx;
1136 uint8_t mask;
1137
1138 for (i = 0; i < CURSOR_BITMAP_SIZE; i++) {
1139 mask = 0x01;
1140 for (j = 0; j < 8; j++) {
1141 idx = ((cursor_mask[i] & mask) ? 2 : 0) |
1142 ((cursor_bitmap[i] & mask) ? 1 : 0);
1143 cmem[i * 8 + j] = cursor_cmap[idx];
1144 mask = mask << 1;
1145 }
1146 }
1147 /* just in case */
1148 cpu_dcache_wb_range((vaddr_t)cmem, CURSOR_ARGB_SIZE);
1149 rpi_fb_initcursor(pcursor, hot_x, hot_y);
1150 }
1151 if (pos) {
1152 rpi_fb_movecursor(cursor_x, cursor_y, cursor_on);
1153 }
1154 return 0;
1155 }
1156 #endif
1157
1158 static int
1159 rpi_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, lwp_t *l)
1160 {
1161
1162 switch (cmd) {
1163 case WSDISPLAYIO_SVIDEO:
1164 {
1165 int d = *(int *)data;
1166 if (d == rpi_video_on)
1167 return 0;
1168 rpi_video_on = d;
1169 rpi_fb_set_video(d);
1170 #if defined(RPI_HWCURSOR)
1171 rpi_fb_movecursor(cursor_x, cursor_y,
1172 d ? cursor_on : 0);
1173 #endif
1174 }
1175 return 0;
1176 case WSDISPLAYIO_GVIDEO:
1177 *(int *)data = rpi_video_on;
1178 return 0;
1179 #if defined(RPI_HWCURSOR)
1180 case WSDISPLAYIO_GCURPOS:
1181 {
1182 struct wsdisplay_curpos *cp = (void *)data;
1183
1184 cp->x = cursor_x;
1185 cp->y = cursor_y;
1186 }
1187 return 0;
1188 case WSDISPLAYIO_SCURPOS:
1189 {
1190 struct wsdisplay_curpos *cp = (void *)data;
1191
1192 cursor_x = cp->x;
1193 cursor_y = cp->y;
1194 rpi_fb_movecursor(cursor_x, cursor_y, cursor_on);
1195 }
1196 return 0;
1197 case WSDISPLAYIO_GCURMAX:
1198 {
1199 struct wsdisplay_curpos *cp = (void *)data;
1200
1201 cp->x = 64;
1202 cp->y = 64;
1203 }
1204 return 0;
1205 case WSDISPLAYIO_SCURSOR:
1206 {
1207 struct wsdisplay_cursor *cursor = (void *)data;
1208
1209 return rpi_fb_do_cursor(cursor);
1210 }
1211 #endif
1212 default:
1213 return EPASSTHROUGH;
1214 }
1215 }
1216
1217 #endif
1218
1219 SYSCTL_SETUP(sysctl_machdep_rpi, "sysctl machdep subtree setup (rpi)")
1220 {
1221 sysctl_createv(clog, 0, NULL, NULL,
1222 CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
1223 NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
1224
1225 sysctl_createv(clog, 0, NULL, NULL,
1226 CTLFLAG_PERMANENT|CTLFLAG_READONLY,
1227 CTLTYPE_INT, "firmware_revision", NULL, NULL, 0,
1228 &vb.vbt_fwrev.rev, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL);
1229
1230 sysctl_createv(clog, 0, NULL, NULL,
1231 CTLFLAG_PERMANENT|CTLFLAG_READONLY,
1232 CTLTYPE_INT, "board_model", NULL, NULL, 0,
1233 &vb.vbt_boardmodel.model, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL);
1234
1235 sysctl_createv(clog, 0, NULL, NULL,
1236 CTLFLAG_PERMANENT|CTLFLAG_READONLY,
1237 CTLTYPE_INT, "board_revision", NULL, NULL, 0,
1238 &vb.vbt_boardrev.rev, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL);
1239
1240 sysctl_createv(clog, 0, NULL, NULL,
1241 CTLFLAG_PERMANENT|CTLFLAG_READONLY|CTLFLAG_HEX|CTLFLAG_PRIVATE,
1242 CTLTYPE_QUAD, "serial", NULL, NULL, 0,
1243 &vb.vbt_serial.sn, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL);
1244 }
1245
1246 #if defined(SOC_BCM2835)
1247 static void
1248 bcm2835_platform_bootstrap(void)
1249 {
1250
1251 bcm2835_bs_tag = arm_generic_bs_tag;
1252 bcm2835_a4x_bs_tag = arm_generic_a4x_bs_tag;
1253
1254 bcm2835_bs_tag.bs_map = bcm2835_bs_map;
1255 bcm2835_bs_tag.bs_mmap = bcm2835_bs_mmap;
1256 bcm2835_a4x_bs_tag.bs_map = bcm2835_bs_map;
1257 bcm2835_a4x_bs_tag.bs_mmap = bcm2835_a4x_bs_mmap;
1258
1259 fdtbus_set_decoderegprop(false);
1260
1261 bcm2835_uartinit();
1262
1263 bcm2835_bootparams();
1264 }
1265 #endif
1266
1267 #if defined(SOC_BCM2836)
1268 static void
1269 bcm2836_platform_bootstrap(void)
1270 {
1271
1272 bcm2836_bs_tag = arm_generic_bs_tag;
1273 bcm2836_a4x_bs_tag = arm_generic_a4x_bs_tag;
1274
1275 bcm2836_bs_tag.bs_map = bcm2836_bs_map;
1276 bcm2836_bs_tag.bs_mmap = bcm2836_bs_mmap;
1277 bcm2836_a4x_bs_tag.bs_map = bcm2836_bs_map;
1278 bcm2836_a4x_bs_tag.bs_mmap = bcm2836_a4x_bs_mmap;
1279
1280 fdtbus_set_decoderegprop(false);
1281
1282 bcm2836_uartinit();
1283
1284 bcm2836_bootparams();
1285
1286 #ifdef MULTIPROCESSOR
1287 arm_cpu_max = RPI_CPU_MAX;
1288 arm_fdt_cpu_bootstrap();
1289 #endif
1290 }
1291
1292 static void
1293 bcm2711_platform_bootstrap(void)
1294 {
1295
1296 bcm2711_bs_tag = arm_generic_bs_tag;
1297 bcm2711_a4x_bs_tag = arm_generic_a4x_bs_tag;
1298
1299 bcm2711_bs_tag.bs_map = bcm2711_bs_map;
1300 bcm2711_bs_tag.bs_mmap = bcm2711_bs_mmap;
1301 bcm2711_a4x_bs_tag.bs_map = bcm2711_bs_map;
1302 bcm2711_a4x_bs_tag.bs_mmap = bcm2711_a4x_bs_mmap;
1303
1304 fdtbus_set_decoderegprop(false);
1305
1306 bcm2711_uartinit();
1307
1308 bcm2711_bootparams();
1309
1310 #ifdef MULTIPROCESSOR
1311 arm_cpu_max = RPI_CPU_MAX;
1312 arm_fdt_cpu_bootstrap();
1313 #endif
1314 }
1315 #endif
1316
1317 #if defined(SOC_BCM2835)
1318 static void
1319 bcm2835_platform_init_attach_args(struct fdt_attach_args *faa)
1320 {
1321
1322 faa->faa_bst = &bcm2835_bs_tag;
1323 }
1324 #endif
1325
1326 #if defined(SOC_BCM2836)
1327 static void
1328 bcm2836_platform_init_attach_args(struct fdt_attach_args *faa)
1329 {
1330
1331 faa->faa_bst = &bcm2836_bs_tag;
1332 }
1333
1334 static void
1335 bcm2711_platform_init_attach_args(struct fdt_attach_args *faa)
1336 {
1337
1338 faa->faa_bst = &bcm2711_bs_tag;
1339 }
1340 #endif
1341
1342
1343 static void __noasan
1344 bcm283x_platform_early_putchar(vaddr_t va, paddr_t pa, char c)
1345 {
1346 volatile uint32_t *uartaddr =
1347 cpu_earlydevice_va_p() ?
1348 (volatile uint32_t *)va :
1349 (volatile uint32_t *)pa;
1350
1351 while ((le32toh(uartaddr[PL01XCOM_FR / 4]) & PL01X_FR_TXFF) != 0)
1352 continue;
1353
1354 uartaddr[PL01XCOM_DR / 4] = htole32(c);
1355
1356 while ((le32toh(uartaddr[PL01XCOM_FR / 4]) & PL01X_FR_TXFE) == 0)
1357 continue;
1358 }
1359
1360 static void __noasan
1361 bcm283x_aux_platform_early_putchar(vaddr_t va, paddr_t pa, char c)
1362 {
1363 volatile uint32_t *uartaddr =
1364 cpu_earlydevice_va_p() ?
1365 (volatile uint32_t *)va :
1366 (volatile uint32_t *)pa;
1367
1368 while ((le32toh(uartaddr[com_lsr]) & LSR_TXRDY) == 0)
1369 continue;
1370
1371 uartaddr[com_data] = htole32(c);
1372 }
1373
1374 void __noasan
1375 bcm2835_platform_early_putchar(char c)
1376 {
1377 paddr_t pa = BCM2835_PERIPHERALS_BUS_TO_PHYS(BCM2835_UART0_BASE);
1378 vaddr_t va = BCM2835_IOPHYSTOVIRT(pa);
1379
1380 bcm283x_platform_early_putchar(va, pa, c);
1381 }
1382
1383 void __noasan
1384 bcm2835_aux_platform_early_putchar(char c)
1385 {
1386 paddr_t pa = BCM2835_PERIPHERALS_BUS_TO_PHYS(BCM2835_AUX_UART_BASE);
1387 vaddr_t va = BCM2835_IOPHYSTOVIRT(pa);
1388
1389 bcm283x_aux_platform_early_putchar(va, pa, c);
1390 }
1391
1392 void __noasan
1393 bcm2836_platform_early_putchar(char c)
1394 {
1395 paddr_t pa = BCM2836_PERIPHERALS_BUS_TO_PHYS(BCM2835_UART0_BASE);
1396 vaddr_t va = BCM2835_IOPHYSTOVIRT(pa);
1397
1398 bcm283x_platform_early_putchar(va, pa, c);
1399 }
1400
1401 void __noasan
1402 bcm2837_platform_early_putchar(char c)
1403 {
1404 paddr_t pa = BCM2836_PERIPHERALS_BUS_TO_PHYS(BCM2835_AUX_UART_BASE);
1405 vaddr_t va = BCM2835_IOPHYSTOVIRT(pa);
1406
1407 bcm283x_aux_platform_early_putchar(va, pa, c);
1408 }
1409
1410 void __noasan
1411 bcm2711_platform_early_putchar(char c)
1412 {
1413 paddr_t pa = BCM2711_PERIPHERALS_BUS_TO_PHYS(BCM2835_AUX_UART_BASE);
1414 vaddr_t va = BCM2711_IOPHYSTOVIRT(pa);
1415
1416 bcm283x_aux_platform_early_putchar(va, pa, c);
1417 }
1418
1419 #define BCM283x_REF_FREQ 19200000
1420
1421 static void
1422 bcm283x_platform_device_register(device_t dev, void *aux)
1423 {
1424 prop_dictionary_t dict = device_properties(dev);
1425
1426 if (device_is_a(dev, "bcmdmac") &&
1427 vcprop_tag_success_p(&vb.vbt_dmachan.tag)) {
1428 prop_dictionary_set_uint32(dict,
1429 "chanmask", le32toh(vb.vbt_dmachan.mask));
1430 }
1431 #if NSDHC > 0
1432 if (booted_device == NULL &&
1433 device_is_a(dev, "ld") &&
1434 device_is_a(device_parent(dev), "sdmmc")) {
1435 booted_partition = 0;
1436 booted_device = dev;
1437 }
1438 #endif
1439 if ((device_is_a(dev, "usmsc") ||
1440 device_is_a(dev, "mue") ||
1441 device_is_a(dev, "genet")) &&
1442 vcprop_tag_success_p(&vb.vbt_macaddr.tag)) {
1443 const uint64_t addr = le64toh(vb.vbt_macaddr.addr);
1444 const uint8_t enaddr[ETHER_ADDR_LEN] = {
1445 (addr >> 0) & 0xff, (addr >> 8) & 0xff,
1446 (addr >> 16) & 0xff, (addr >> 24) & 0xff,
1447 (addr >> 32) & 0xff, (addr >> 40) & 0xff
1448 };
1449
1450 prop_dictionary_set_data(dict, "mac-address", enaddr,
1451 ETHER_ADDR_LEN);
1452 }
1453
1454 #if NGENFB > 0
1455 if (device_is_a(dev, "genfb")) {
1456 char *ptr;
1457
1458 bcmgenfb_set_console_dev(dev);
1459 bcmgenfb_set_ioctl(&rpi_ioctl);
1460 #ifdef DDB
1461 db_trap_callback = bcmgenfb_ddb_trap_callback;
1462 #endif
1463 if (rpi_fb_init(dict, aux) == false)
1464 return;
1465 if (get_bootconf_option(boot_args, "console",
1466 BOOTOPT_TYPE_STRING, &ptr) && strncmp(ptr, "fb", 2) == 0) {
1467 prop_dictionary_set_bool(dict, "is_console", true);
1468 #if NUKBD > 0
1469 /* allow ukbd to be the console keyboard */
1470 ukbd_cnattach();
1471 #endif
1472 } else {
1473 prop_dictionary_set_bool(dict, "is_console", false);
1474 }
1475 }
1476 #endif
1477 }
1478
1479 static u_int
1480 bcm283x_platform_uart_freq(void)
1481 {
1482
1483 /*
1484 * We are safe to access stdout phandle - consinit did before
1485 * calling fp_uart_freq
1486 */
1487 const int phandle = fdtbus_get_stdout_phandle();
1488
1489 static const struct device_compatible_entry aux_compat_data[] = {
1490 { .compat = "brcm,bcm2835-aux-uart" },
1491 DEVICE_COMPAT_EOL
1492 };
1493
1494 if (of_compatible_match(phandle, aux_compat_data))
1495 return core_clk * 2;
1496
1497 return uart_clk;
1498 }
1499
1500 #if defined(SOC_BCM2835)
1501 static const struct fdt_platform bcm2835_platform = {
1502 .fp_devmap = bcm2835_platform_devmap,
1503 .fp_bootstrap = bcm2835_platform_bootstrap,
1504 .fp_init_attach_args = bcm2835_platform_init_attach_args,
1505 .fp_device_register = bcm283x_platform_device_register,
1506 .fp_reset = bcm2835_system_reset,
1507 .fp_delay = bcm2835_tmr_delay,
1508 .fp_uart_freq = bcm283x_platform_uart_freq,
1509 };
1510
1511 FDT_PLATFORM(bcm2835, "brcm,bcm2835", &bcm2835_platform);
1512 #endif
1513
1514 #if defined(SOC_BCM2836)
1515
1516 static const struct fdt_platform bcm2836_platform = {
1517 .fp_devmap = bcm2836_platform_devmap,
1518 .fp_bootstrap = bcm2836_platform_bootstrap,
1519 .fp_init_attach_args = bcm2836_platform_init_attach_args,
1520 .fp_device_register = bcm283x_platform_device_register,
1521 .fp_reset = bcm2835_system_reset,
1522 .fp_delay = gtmr_delay,
1523 .fp_uart_freq = bcm283x_platform_uart_freq,
1524 .fp_mpstart = arm_fdt_cpu_mpstart,
1525 };
1526
1527 static const struct fdt_platform bcm2837_platform = {
1528 .fp_devmap = bcm2836_platform_devmap,
1529 .fp_bootstrap = bcm2836_platform_bootstrap,
1530 .fp_init_attach_args = bcm2836_platform_init_attach_args,
1531 .fp_device_register = bcm283x_platform_device_register,
1532 .fp_reset = bcm2835_system_reset,
1533 .fp_delay = gtmr_delay,
1534 .fp_uart_freq = bcm283x_platform_uart_freq,
1535 .fp_mpstart = arm_fdt_cpu_mpstart,
1536 };
1537
1538 static const struct fdt_platform bcm2711_platform = {
1539 .fp_devmap = bcm2711_platform_devmap,
1540 .fp_bootstrap = bcm2711_platform_bootstrap,
1541 .fp_init_attach_args = bcm2711_platform_init_attach_args,
1542 .fp_device_register = bcm283x_platform_device_register,
1543 .fp_reset = bcm2835_system_reset,
1544 .fp_delay = gtmr_delay,
1545 .fp_uart_freq = bcm283x_platform_uart_freq,
1546 .fp_mpstart = arm_fdt_cpu_mpstart,
1547 };
1548
1549 FDT_PLATFORM(bcm2836, "brcm,bcm2836", &bcm2836_platform);
1550 FDT_PLATFORM(bcm2837, "brcm,bcm2837", &bcm2837_platform);
1551 FDT_PLATFORM(bcm2711, "brcm,bcm2711", &bcm2711_platform);
1552 #endif
1553