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