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