machdep.c revision 1.1 1 /* $NetBSD: machdep.c,v 1.1 2026/06/16 21:51:20 rkujawa Exp $ */
2
3 /*
4 * Copyright (c) 2012, 2014, 2024, 2026 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Radoslaw Kujawa.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /*
32 * Copyright 2001, 2002 Wasabi Systems, Inc.
33 * All rights reserved.
34 *
35 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed for the NetBSD Project by
48 * Wasabi Systems, Inc.
49 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
50 * or promote products derived from this software without specific prior
51 * written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
55 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
57 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
58 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
59 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
60 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
61 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
62 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
63 * POSSIBILITY OF SUCH DAMAGE.
64 */
65 /*
66 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
67 * Copyright (C) 1995, 1996 TooLs GmbH.
68 * All rights reserved.
69 *
70 * Redistribution and use in source and binary forms, with or without
71 * modification, are permitted provided that the following conditions
72 * are met:
73 * 1. Redistributions of source code must retain the above copyright
74 * notice, this list of conditions and the following disclaimer.
75 * 2. Redistributions in binary form must reproduce the above copyright
76 * notice, this list of conditions and the following disclaimer in the
77 * documentation and/or other materials provided with the distribution.
78 * 3. All advertising materials mentioning features or use of this software
79 * must display the following acknowledgement:
80 * This product includes software developed by TooLs GmbH.
81 * 4. The name of TooLs GmbH may not be used to endorse or promote products
82 * derived from this software without specific prior written permission.
83 *
84 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
85 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
86 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
87 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
88 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
89 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
90 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
91 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
92 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
93 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
94 */
95
96 /*
97 * Machine-dependent bootstrap for the ACube Sam460ex (AMCC 460EX).
98 *
99 * Modeled on evbppc/walnut/machdep.c and evbppc/obs405/obs600_machdep.c.
100 */
101
102 #include <sys/cdefs.h>
103 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.1 2026/06/16 21:51:20 rkujawa Exp $");
104
105 #include "opt_ddb.h"
106 #include "opt_sam460ex.h"
107
108 #include <sys/param.h>
109 #include <sys/boot_flag.h>
110 #include <sys/bus.h>
111 #include <sys/device.h>
112 #include <sys/kernel.h>
113 #include <sys/reboot.h>
114 #include <sys/sysctl.h>
115 #include <sys/systm.h>
116
117 #include <dev/cons.h>
118
119 #include <prop/proplib.h>
120
121 #include <machine/sam460ex.h>
122
123 #include <powerpc/spr.h>
124 #include <powerpc/ibm4xx/spr.h>
125
126 #include <powerpc/ibm4xx/amcc460ex.h>
127 #include <powerpc/ibm4xx/cpu.h>
128 #include <powerpc/ibm4xx/dcr4xx.h>
129 #include <powerpc/ibm4xx/tlb.h>
130
131 #include <powerpc/ibm4xx/pci_machdep.h>
132 #include <dev/pci/pciconf.h>
133 #include <dev/pci/pcivar.h>
134
135 #include "com.h"
136 #include "ukbd.h"
137 #if NUKBD > 0
138 #include <dev/usb/ukbdvar.h>
139 #endif
140 #if (NCOM > 0)
141 #include <sys/termios.h>
142 #include <powerpc/ibm4xx/dev/comopbvar.h>
143 #include <dev/ic/comreg.h>
144
145 #ifndef CONADDR
146 #define CONADDR AMCC460EX_UART0_BASE
147 #endif
148 #ifndef CONSPEED
149 #define CONSPEED B115200
150 #endif
151 #ifndef CONMODE
152 /* 8N1 */
153 #define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8)
154 #endif
155 #endif /* NCOM */
156
157 #ifndef SAM460EX_MEMSIZE
158 #define SAM460EX_MEMSIZE (512 * 1024 * 1024)
159 #endif
160 #ifndef SAM460EX_CPU_FREQ
161 #define SAM460EX_CPU_FREQ (1150 * 1000 * 1000)
162 #endif
163 #ifndef SAM460EX_OPB_FREQ
164 #define SAM460EX_OPB_FREQ (115 * 1000 * 1000)
165 #endif
166
167 #define TLB_PG_SIZE (16 * 1024 * 1024)
168
169 /* Boot loader handoff, for later FDT parsing */
170 paddr_t sam460ex_fdt_pa;
171 uint32_t sam460ex_epapr_magic;
172
173 void initppc(vaddr_t, vaddr_t, paddr_t, uint32_t);
174
175 /*
176 * Polled early console on UART0.
177 * VA 0xef600300 covered by the locore.
178 */
179 static void
180 earlycons_putc(dev_t dev, int c)
181 {
182 volatile uint8_t *uart = (volatile uint8_t *)AMCC460EX_UART0_BASE;
183
184 while ((uart[5] & 0x20) == 0) /* LSR.THRE */
185 ;
186 uart[0] = c;
187 }
188
189 static int
190 earlycons_getc(dev_t dev)
191 {
192 volatile uint8_t *uart = (volatile uint8_t *)AMCC460EX_UART0_BASE;
193
194 while ((uart[5] & 0x01) == 0) /* LSR.DR */
195 ;
196 return uart[0];
197 }
198
199 static struct consdev earlycons = {
200 .cn_putc = earlycons_putc,
201 .cn_getc = earlycons_getc,
202 .cn_pollc = nullcnpollc,
203 .cn_dev = NODEV,
204 .cn_pri = CN_INTERNAL,
205 };
206
207 void
208 initppc(vaddr_t startkernel, vaddr_t endkernel, paddr_t fdt_pa,
209 uint32_t magic)
210 {
211 u_int memsize;
212 vaddr_t va;
213
214 cn_tab = &earlycons;
215
216 sam460ex_fdt_pa = fdt_pa;
217 sam460ex_epapr_magic = magic;
218
219 /* Disable all external interrupts */
220 mtdcr(DCR_UIC0_BASE + DCR_UIC_ER, 0);
221 mtdcr(DCR_UIC1_BASE + DCR_UIC_ER, 0);
222 mtdcr(DCR_UIC2_BASE + DCR_UIC_ER, 0);
223 mtdcr(DCR_UIC3_BASE + DCR_UIC_ER, 0);
224
225 memsize = SAM460EX_MEMSIZE;
226 #ifdef SAM460EX_FDT
227 if (sam460ex_fdt_parse(fdt_pa)) {
228 if (sam460ex_fdt_info.fi_memsize != 0)
229 memsize = sam460ex_fdt_info.fi_memsize;
230 } else
231 printf("sam460ex: no valid FDT at %#lx, using defaults\n",
232 (u_long)fdt_pa);
233 #endif
234
235 /* Slots 0/1 hold the TS=0 identity entries pinned by locore */
236 ppc44x_tlb_boot_reserved(2);
237
238 /*
239 * locore TS=0 RAM identity entry covers the first 256MB
240 */
241 for (paddr_t pa = 0x10000000; pa < memsize; pa += 0x10000000)
242 ppc44x_tlb_reserve_ts0(pa);
243
244 /* Linear map kernel memory (TS=1, KERNEL_PID) */
245 for (va = 0; va < endkernel; va += TLB_PG_SIZE)
246 ppc4xx_tlb_reserve(va, va, TLB_PG_SIZE, TLB_EX);
247
248 /*
249 * Map the on-chip peripherals
250 */
251 ppc44x_tlb_reserve((uint64_t)AMCC460EX_OPB_PA_HIGH << 32 | 0xef000000,
252 0xef000000, TLB_PG_SIZE, TLB_I | TLB_G);
253
254 /*
255 * PCIX host bridge windows
256 */
257 for (va = 0; va < AMCC460EX_PCIX0_MEM_SIZE; va += TLB_PG_SIZE)
258 ppc44x_tlb_reserve(
259 (uint64_t)AMCC460EX_PCIX0_MEM_PLBA_H << 32 |
260 (AMCC460EX_PCIX0_MEM_BASE + va),
261 SAM460EX_PCIMEM_VA + va, TLB_PG_SIZE, TLB_I | TLB_G);
262 ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIX0_IO_PA_HIGH << 32 |
263 AMCC460EX_PCIX0_IO_PLBA,
264 SAM460EX_PCIIO_VA, TLB_PG_SIZE, TLB_I | TLB_G);
265 ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIX0_CFG_PA_HIGH << 32 |
266 (AMCC460EX_PCIX0_CFG_PLBA & ~(TLB_PG_SIZE - 1)),
267 SAM460EX_PCICFG_VA, TLB_PG_SIZE, TLB_I | TLB_G);
268
269 /*
270 * PCIe root complex windows
271 */
272 ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIE_CFG_PA_HIGH << 32 |
273 AMCC460EX_PCIE0_CFG_PLBA,
274 SAM460EX_PCIE0CFG_VA, TLB_PG_SIZE, TLB_I | TLB_G);
275 ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIE_CFG_PA_HIGH << 32 |
276 AMCC460EX_PCIE1_CFG_PLBA,
277 SAM460EX_PCIE1CFG_VA, TLB_PG_SIZE, TLB_I | TLB_G);
278 ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIE_MEM_PA_HIGH << 32 |
279 AMCC460EX_PCIE0_MEM_PLBA,
280 SAM460EX_PCIE0MEM_VA, TLB_PG_SIZE, TLB_I | TLB_G);
281 ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIE_MEM_PA_HIGH << 32 |
282 AMCC460EX_PCIE1_MEM_PLBA,
283 SAM460EX_PCIE1MEM_VA, TLB_PG_SIZE, TLB_I | TLB_G);
284
285 /*
286 * AHB peripherals (USB OTG/OHCI/EHCI) behind the PLB-AHB
287 * bridge.
288 */
289 ppc44x_tlb_reserve((uint64_t)AMCC460EX_AHB_PA_HIGH << 32 |
290 AMCC460EX_AHB_BASE,
291 SAM460EX_AHB_VA, TLB_PG_SIZE, TLB_I | TLB_G);
292
293 mtspr(SPR_TCR, 0); /* disable all timers */
294
295 ibm40x_memsize_init(memsize, startkernel);
296 ibm4xx_init(startkernel, endkernel, pic_ext_intr);
297
298 #ifdef DDB
299 if (boothowto & RB_KDB)
300 Debugger();
301 #endif
302 }
303
304 void
305 consinit(void)
306 {
307
308 #if (NCOM > 0)
309 com_opb_cnattach(AMCC460EX_COM_FREQ, CONADDR, CONSPEED, CONMODE);
310 #endif
311 }
312
313 /*
314 * Parse /chosen/bootargs.
315 */
316 static char bootspec_buf[64];
317
318 /* "console=fb" in bootargs makes the SM502 wsdisplay the console */
319 bool sam460ex_console_fb;
320
321 static void
322 parse_bootargs(const char *args)
323 {
324 const char *cp = args;
325
326 #define BA_DELIM(c) ((c) == ' ' || (c) == '"')
327 while (*cp != '\0') {
328 if (BA_DELIM(*cp)) {
329 cp++;
330 continue;
331 }
332 if (*cp == '-') {
333 for (cp++; *cp != '\0' && !BA_DELIM(*cp); cp++)
334 BOOT_FLAG(*cp, boothowto);
335 } else if (strncmp(cp, "root=", 5) == 0) {
336 char *bp = bootspec_buf;
337
338 for (cp += 5; *cp != '\0' && !BA_DELIM(*cp) &&
339 bp < &bootspec_buf[sizeof(bootspec_buf) - 1]; )
340 *bp++ = *cp++;
341 *bp = '\0';
342 if (bootspec_buf[0] != '\0') {
343 bootspec = bootspec_buf;
344 booted_method = "bootargs/root";
345 }
346 } else if (strncmp(cp, "console=fb", 10) == 0) {
347 sam460ex_console_fb = true;
348 cp += 10;
349 } else {
350 while (*cp != '\0' && !BA_DELIM(*cp))
351 cp++;
352 }
353 }
354 #undef BA_DELIM
355 }
356
357 /*
358 * Machine dependent startup code.
359 */
360 void
361 cpu_startup(void)
362 {
363 prop_number_t pn;
364 uint32_t cpu_freq = SAM460EX_CPU_FREQ;
365 uint32_t opb_freq = SAM460EX_OPB_FREQ;
366 uint32_t memsize = SAM460EX_MEMSIZE;
367
368 ibm4xx_cpu_startup("ACube Sam460ex (AMCC 460EX)");
369
370 #ifdef SAM460EX_FDT
371 /*
372 * The timebase runs at the CPU clock; "processor-frequency"
373 * feeds delay() and the DEC reload value.
374 */
375 if (sam460ex_fdt_info.fi_timebase_freq != 0)
376 cpu_freq = sam460ex_fdt_info.fi_timebase_freq;
377 else if (sam460ex_fdt_info.fi_cpu_freq != 0)
378 cpu_freq = sam460ex_fdt_info.fi_cpu_freq;
379 if (sam460ex_fdt_info.fi_opb_freq != 0)
380 opb_freq = sam460ex_fdt_info.fi_opb_freq;
381 if (sam460ex_fdt_info.fi_memsize != 0)
382 memsize = sam460ex_fdt_info.fi_memsize;
383 if (sam460ex_fdt_info.fi_bootargs != NULL) {
384 printf("bootargs: %s\n", sam460ex_fdt_info.fi_bootargs);
385 parse_bootargs(sam460ex_fdt_info.fi_bootargs);
386 }
387 #endif
388
389 #if NUKBD > 0
390 if (sam460ex_console_fb) {
391 ukbd_cnattach();
392 }
393 #endif
394
395 /*
396 * Set up the board props
397 */
398 board_info_init();
399
400 pn = prop_number_create_integer(cpu_freq);
401 KASSERT(pn != NULL);
402 if (prop_dictionary_set(board_properties, "processor-frequency",
403 pn) == false)
404 panic("setting processor-frequency");
405 prop_object_release(pn);
406
407 pn = prop_number_create_integer(opb_freq);
408 KASSERT(pn != NULL);
409 if (prop_dictionary_set(board_properties, "opb-frequency", pn) ==
410 false)
411 panic("setting opb-frequency");
412 prop_object_release(pn);
413
414 pn = prop_number_create_integer(memsize);
415 KASSERT(pn != NULL);
416 if (prop_dictionary_set(board_properties, "mem-size", pn) == false)
417 panic("setting mem-size");
418 prop_object_release(pn);
419
420 #ifdef SAM460EX_FDT
421 /*
422 * EMAC MAC addresses from the device tree filled by U-Boot
423 */
424 for (int i = 0; i < SAM460EX_NEMAC; i++) {
425 char propname[16];
426 prop_data_t pd;
427
428 if (!sam460ex_fdt_info.fi_enaddr_valid[i])
429 continue;
430 snprintf(propname, sizeof(propname), "emac%d-mac-addr", i);
431 pd = prop_data_create_data_nocopy(
432 sam460ex_fdt_info.fi_enaddr[i], 6);
433 KASSERT(pd != NULL);
434 if (prop_dictionary_set(board_properties, propname, pd) ==
435 false)
436 panic("setting %s", propname);
437 prop_object_release(pd);
438
439 snprintf(propname, sizeof(propname), "emac%d-mii-phy", i);
440 pn = prop_number_create_integer(i);
441 KASSERT(pn != NULL);
442 if (prop_dictionary_set(board_properties, propname, pn) ==
443 false)
444 panic("setting %s", propname);
445 prop_object_release(pn);
446 }
447 #endif
448
449 calc_delayconst();
450
451 /*
452 * Now that we have VM, malloc is OK
453 */
454 bus_space_mallocok();
455 fake_mapiodev = 0;
456 }
457
458 /*
459 * PCI interrupt routing and slot policy for the on-chip PLB-PCIX
460 * bridge (see powerpc/ibm4xx/pci/pcix.c).
461 *
462 * XXX: On the Sam460ex every PCI intr pin is wired to UIC1 bit 0?
463 */
464 int
465 ibm4xx_pci_bus_maxdevs(void *v, int busno)
466 {
467 return 16;
468 }
469
470 /*
471 * Board interrupt routing for the PCI-X slot. Unlike the AMCC Canyonlands
472 * design (where the SoC's external IRQ2 / UIC1 bit 0 is the PCI INT), the
473 * Sam460ex wire-ORs all PCI INTx through its FPGA onto UIC1 bit 3 = irq 35
474 */
475 #define SAM460EX_PCI_INTR_IRQ 32 /* TEMP, see above; correct value is 35? */
476
477 int
478 ibm4xx_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
479 {
480 *ihp = SAM460EX_PCI_INTR_IRQ;
481 return 0;
482 }
483
484 void
485 ibm4xx_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz,
486 int *iline)
487 {
488 *iline = SAM460EX_PCI_INTR_IRQ;
489 }
490
491 #define UIC_DUMP(n, base) \
492 blen += snprintf(buf + blen, sizeof(buf) - blen, \
493 "uic%d SR=%08x MSR=%08x ER=%08x PR=%08x TR=%08x\n", (n), \
494 (unsigned int)mfdcr((base) + DCR_UIC_SR), \
495 (unsigned int)mfdcr((base) + DCR_UIC_MSR), \
496 (unsigned int)mfdcr((base) + DCR_UIC_ER), \
497 (unsigned int)mfdcr((base) + DCR_UIC_PR), \
498 (unsigned int)mfdcr((base) + DCR_UIC_TR))
499
500 static int
501 sysctl_machdep_uicregs(SYSCTLFN_ARGS)
502 {
503 struct sysctlnode node;
504 char buf[400];
505 int blen = 0;
506
507 UIC_DUMP(0, DCR_UIC0_BASE);
508 UIC_DUMP(1, DCR_UIC1_BASE);
509 UIC_DUMP(2, DCR_UIC2_BASE);
510 UIC_DUMP(3, DCR_UIC3_BASE);
511
512 node = *rnode;
513 node.sysctl_data = buf;
514 node.sysctl_size = strlen(buf) + 1;
515 return sysctl_lookup(SYSCTLFN_CALL(&node));
516 }
517 #undef UIC_DUMP
518
519 SYSCTL_SETUP(sysctl_machdep_uicregs_setup, "sam460ex UIC register dump")
520 {
521
522 sysctl_createv(clog, 0, NULL, NULL,
523 CTLFLAG_PERMANENT | CTLFLAG_READONLY,
524 CTLTYPE_STRING, "uicregs",
525 SYSCTL_DESCR("UIC0-3 SR/MSR/ER/PR/TR (interrupt debug)"),
526 sysctl_machdep_uicregs, 0, NULL, 0,
527 CTL_MACHDEP, CTL_CREATE, CTL_EOL);
528 }
529
530