/* $NetBSD: machdep.c,v 1.2 2026/06/16 23:37:49 rkujawa Exp $ */ /* * Copyright (c) 2012, 2014, 2024, 2026 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Radoslaw Kujawa. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright 2001, 2002 Wasabi Systems, Inc. * All rights reserved. * * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (C) 1995, 1996 Wolfgang Solfrank. * Copyright (C) 1995, 1996 TooLs GmbH. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent bootstrap for the ACube Sam460ex (AMCC 460EX). * * Modeled on evbppc/walnut/machdep.c and evbppc/obs405/obs600_machdep.c. */ #include __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.2 2026/06/16 23:37:49 rkujawa Exp $"); #include "opt_ddb.h" #include "opt_sam460ex.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "com.h" #include "ukbd.h" #if NUKBD > 0 #include #endif #if (NCOM > 0) #include #include #include #ifndef CONADDR #define CONADDR AMCC460EX_UART0_BASE #endif #ifndef CONSPEED #define CONSPEED B115200 #endif #ifndef CONMODE /* 8N1 */ #define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) #endif #endif /* NCOM */ #ifndef SAM460EX_MEMSIZE #define SAM460EX_MEMSIZE (512 * 1024 * 1024) #endif #ifndef SAM460EX_CPU_FREQ #define SAM460EX_CPU_FREQ (1150 * 1000 * 1000) #endif #ifndef SAM460EX_OPB_FREQ #define SAM460EX_OPB_FREQ (115 * 1000 * 1000) #endif #define TLB_PG_SIZE (16 * 1024 * 1024) /* Boot loader handoff, for later FDT parsing */ paddr_t sam460ex_fdt_pa; uint32_t sam460ex_epapr_magic; void initppc(vaddr_t, vaddr_t, paddr_t, uint32_t); /* * Polled early console on UART0. * VA 0xef600300 covered by the locore. */ static void earlycons_putc(dev_t dev, int c) { volatile uint8_t *uart = (volatile uint8_t *)AMCC460EX_UART0_BASE; while ((uart[5] & 0x20) == 0) /* LSR.THRE */ ; uart[0] = c; } static int earlycons_getc(dev_t dev) { volatile uint8_t *uart = (volatile uint8_t *)AMCC460EX_UART0_BASE; while ((uart[5] & 0x01) == 0) /* LSR.DR */ ; return uart[0]; } static struct consdev earlycons = { .cn_putc = earlycons_putc, .cn_getc = earlycons_getc, .cn_pollc = nullcnpollc, .cn_dev = NODEV, .cn_pri = CN_INTERNAL, }; void initppc(vaddr_t startkernel, vaddr_t endkernel, paddr_t fdt_pa, uint32_t magic) { u_int memsize; vaddr_t va; cn_tab = &earlycons; sam460ex_fdt_pa = fdt_pa; sam460ex_epapr_magic = magic; /* Disable all external interrupts */ mtdcr(DCR_UIC0_BASE + DCR_UIC_ER, 0); mtdcr(DCR_UIC1_BASE + DCR_UIC_ER, 0); mtdcr(DCR_UIC2_BASE + DCR_UIC_ER, 0); mtdcr(DCR_UIC3_BASE + DCR_UIC_ER, 0); memsize = SAM460EX_MEMSIZE; #ifdef SAM460EX_FDT if (sam460ex_fdt_parse(fdt_pa)) { if (sam460ex_fdt_info.fi_memsize != 0) memsize = sam460ex_fdt_info.fi_memsize; } else printf("sam460ex: no valid FDT at %#lx, using defaults\n", (u_long)fdt_pa); /* Record the value actually used so cpu_startup() agrees. */ sam460ex_fdt_info.fi_memsize = memsize; #endif /* Slots 0/1 hold the TS=0 identity entries pinned by locore */ ppc44x_tlb_boot_reserved(2); /* * locore TS=0 RAM identity entry covers the first 256MB */ for (paddr_t pa = 0x10000000; pa < memsize; pa += 0x10000000) ppc44x_tlb_reserve_ts0(pa); /* Linear map kernel memory (TS=1, KERNEL_PID) */ for (va = 0; va < endkernel; va += TLB_PG_SIZE) ppc4xx_tlb_reserve(va, va, TLB_PG_SIZE, TLB_EX); /* * Map the on-chip peripherals */ ppc44x_tlb_reserve((uint64_t)AMCC460EX_OPB_PA_HIGH << 32 | 0xef000000, 0xef000000, TLB_PG_SIZE, TLB_I | TLB_G); /* * PCIX host bridge windows */ for (va = 0; va < AMCC460EX_PCIX0_MEM_SIZE; va += TLB_PG_SIZE) ppc44x_tlb_reserve( (uint64_t)AMCC460EX_PCIX0_MEM_PLBA_H << 32 | (AMCC460EX_PCIX0_MEM_BASE + va), SAM460EX_PCIMEM_VA + va, TLB_PG_SIZE, TLB_I | TLB_G); ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIX0_IO_PA_HIGH << 32 | AMCC460EX_PCIX0_IO_PLBA, SAM460EX_PCIIO_VA, TLB_PG_SIZE, TLB_I | TLB_G); ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIX0_CFG_PA_HIGH << 32 | (AMCC460EX_PCIX0_CFG_PLBA & ~(TLB_PG_SIZE - 1)), SAM460EX_PCICFG_VA, TLB_PG_SIZE, TLB_I | TLB_G); /* * PCIe root complex windows */ ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIE_CFG_PA_HIGH << 32 | AMCC460EX_PCIE0_CFG_PLBA, SAM460EX_PCIE0CFG_VA, TLB_PG_SIZE, TLB_I | TLB_G); ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIE_CFG_PA_HIGH << 32 | AMCC460EX_PCIE1_CFG_PLBA, SAM460EX_PCIE1CFG_VA, TLB_PG_SIZE, TLB_I | TLB_G); ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIE_MEM_PA_HIGH << 32 | AMCC460EX_PCIE0_MEM_PLBA, SAM460EX_PCIE0MEM_VA, TLB_PG_SIZE, TLB_I | TLB_G); ppc44x_tlb_reserve((uint64_t)AMCC460EX_PCIE_MEM_PA_HIGH << 32 | AMCC460EX_PCIE1_MEM_PLBA, SAM460EX_PCIE1MEM_VA, TLB_PG_SIZE, TLB_I | TLB_G); /* * AHB peripherals (USB OTG/OHCI/EHCI) behind the PLB-AHB * bridge. */ ppc44x_tlb_reserve((uint64_t)AMCC460EX_AHB_PA_HIGH << 32 | AMCC460EX_AHB_BASE, SAM460EX_AHB_VA, TLB_PG_SIZE, TLB_I | TLB_G); mtspr(SPR_TCR, 0); /* disable all timers */ ibm40x_memsize_init(memsize, startkernel); ibm4xx_init(startkernel, endkernel, pic_ext_intr); #ifdef DDB if (boothowto & RB_KDB) Debugger(); #endif } /* * UART input clock for the console and com devices. */ uint32_t sam460ex_com_freq(void) { #ifdef SAM460EX_FDT if (sam460ex_fdt_info.fi_uart_freq != 0) return sam460ex_fdt_info.fi_uart_freq; #endif return AMCC460EX_COM_FREQ; } void consinit(void) { #if (NCOM > 0) com_opb_cnattach(sam460ex_com_freq(), CONADDR, CONSPEED, CONMODE); #endif } /* * Parse /chosen/bootargs. */ static char bootspec_buf[64]; /* "console=fb" in bootargs makes the SM502 wsdisplay the console */ bool sam460ex_console_fb; static void parse_bootargs(const char *args) { const char *cp = args; #define BA_DELIM(c) ((c) == ' ' || (c) == '"') while (*cp != '\0') { if (BA_DELIM(*cp)) { cp++; continue; } if (*cp == '-') { for (cp++; *cp != '\0' && !BA_DELIM(*cp); cp++) BOOT_FLAG(*cp, boothowto); } else if (strncmp(cp, "root=", 5) == 0) { char *bp = bootspec_buf; for (cp += 5; *cp != '\0' && !BA_DELIM(*cp) && bp < &bootspec_buf[sizeof(bootspec_buf) - 1]; ) *bp++ = *cp++; *bp = '\0'; if (bootspec_buf[0] != '\0') { bootspec = bootspec_buf; booted_method = "bootargs/root"; } } else if (strncmp(cp, "console=fb", 10) == 0) { sam460ex_console_fb = true; cp += 10; } else { while (*cp != '\0' && !BA_DELIM(*cp)) cp++; } } #undef BA_DELIM } /* * Machine dependent startup code. */ void cpu_startup(void) { prop_number_t pn; uint32_t cpu_freq = SAM460EX_CPU_FREQ; uint32_t opb_freq = SAM460EX_OPB_FREQ; uint32_t memsize = SAM460EX_MEMSIZE; ibm4xx_cpu_startup("ACube Sam460ex (AMCC 460EX)"); #ifdef SAM460EX_FDT /* * The timebase runs at the CPU clock; "processor-frequency" * feeds delay() and the DEC reload value. */ if (sam460ex_fdt_info.fi_timebase_freq != 0) cpu_freq = sam460ex_fdt_info.fi_timebase_freq; else if (sam460ex_fdt_info.fi_cpu_freq != 0) cpu_freq = sam460ex_fdt_info.fi_cpu_freq; if (sam460ex_fdt_info.fi_opb_freq != 0) opb_freq = sam460ex_fdt_info.fi_opb_freq; if (sam460ex_fdt_info.fi_memsize != 0) memsize = sam460ex_fdt_info.fi_memsize; printf("sam460ex: fdt cpu %u Hz, opb %u Hz, uart %u Hz, mem %u MB\n", cpu_freq, opb_freq, sam460ex_fdt_info.fi_uart_freq, memsize / (1024 * 1024)); if (sam460ex_fdt_info.fi_bootargs != NULL) { printf("bootargs: %s\n", sam460ex_fdt_info.fi_bootargs); parse_bootargs(sam460ex_fdt_info.fi_bootargs); } #endif #if NUKBD > 0 if (sam460ex_console_fb) { ukbd_cnattach(); } #endif /* * Set up the board props */ board_info_init(); pn = prop_number_create_integer(cpu_freq); KASSERT(pn != NULL); if (prop_dictionary_set(board_properties, "processor-frequency", pn) == false) panic("setting processor-frequency"); prop_object_release(pn); pn = prop_number_create_integer(opb_freq); KASSERT(pn != NULL); if (prop_dictionary_set(board_properties, "opb-frequency", pn) == false) panic("setting opb-frequency"); prop_object_release(pn); pn = prop_number_create_integer(memsize); KASSERT(pn != NULL); if (prop_dictionary_set(board_properties, "mem-size", pn) == false) panic("setting mem-size"); prop_object_release(pn); #ifdef SAM460EX_FDT /* * EMAC MAC addresses from the device tree filled by U-Boot */ for (int i = 0; i < SAM460EX_NEMAC; i++) { char propname[16]; prop_data_t pd; if (!sam460ex_fdt_info.fi_enaddr_valid[i]) continue; snprintf(propname, sizeof(propname), "emac%d-mac-addr", i); pd = prop_data_create_data_nocopy( sam460ex_fdt_info.fi_enaddr[i], 6); KASSERT(pd != NULL); if (prop_dictionary_set(board_properties, propname, pd) == false) panic("setting %s", propname); prop_object_release(pd); snprintf(propname, sizeof(propname), "emac%d-mii-phy", i); pn = prop_number_create_integer(i); KASSERT(pn != NULL); if (prop_dictionary_set(board_properties, propname, pn) == false) panic("setting %s", propname); prop_object_release(pn); } #endif calc_delayconst(); /* * Now that we have VM, malloc is OK */ bus_space_mallocok(); fake_mapiodev = 0; } /* * PCI interrupt routing and slot policy for the on-chip PLB-PCIX * bridge (see powerpc/ibm4xx/pci/pcix.c). * * XXX: On the Sam460ex every PCI intr pin is wired to UIC1 bit 0? */ int ibm4xx_pci_bus_maxdevs(void *v, int busno) { return 16; } /* * Board interrupt routing for the PCI-X slot. Unlike the AMCC Canyonlands * design (where the SoC's external IRQ2 / UIC1 bit 0 is the PCI INT), the * Sam460ex wire-ORs all PCI INTx through its FPGA onto UIC1 bit 3 = irq 35 */ #define SAM460EX_PCI_INTR_IRQ 32 /* TEMP, see above; correct value is 35? */ int ibm4xx_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) { *ihp = SAM460EX_PCI_INTR_IRQ; return 0; } void ibm4xx_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz, int *iline) { *iline = SAM460EX_PCI_INTR_IRQ; } #define UIC_DUMP(n, base) \ blen += snprintf(buf + blen, sizeof(buf) - blen, \ "uic%d SR=%08x MSR=%08x ER=%08x PR=%08x TR=%08x\n", (n), \ (unsigned int)mfdcr((base) + DCR_UIC_SR), \ (unsigned int)mfdcr((base) + DCR_UIC_MSR), \ (unsigned int)mfdcr((base) + DCR_UIC_ER), \ (unsigned int)mfdcr((base) + DCR_UIC_PR), \ (unsigned int)mfdcr((base) + DCR_UIC_TR)) static int sysctl_machdep_uicregs(SYSCTLFN_ARGS) { struct sysctlnode node; char buf[400]; int blen = 0; UIC_DUMP(0, DCR_UIC0_BASE); UIC_DUMP(1, DCR_UIC1_BASE); UIC_DUMP(2, DCR_UIC2_BASE); UIC_DUMP(3, DCR_UIC3_BASE); node = *rnode; node.sysctl_data = buf; node.sysctl_size = strlen(buf) + 1; return sysctl_lookup(SYSCTLFN_CALL(&node)); } #undef UIC_DUMP SYSCTL_SETUP(sysctl_machdep_uicregs_setup, "sam460ex UIC register dump") { sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_STRING, "uicregs", SYSCTL_DESCR("UIC0-3 SR/MSR/ER/PR/TR (interrupt debug)"), sysctl_machdep_uicregs, 0, NULL, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL); }