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