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