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