Index: head/sys/dev/ofw/ofw_subr.c =================================================================== --- head/sys/dev/ofw/ofw_subr.c (revision 336244) +++ head/sys/dev/ofw/ofw_subr.c (revision 336245) @@ -1,246 +1,208 @@ /*- * Copyright (c) 2015 Ian Lepore * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. * * The initial ofw_reg_to_paddr() implementation has been copied from powerpc * ofw_machdep.c OF_decode_addr(). It was added by Marcel Moolenaar, who did not * assert copyright with the addition but still deserves credit for the work. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include static void get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip) { char type[64]; uint32_t addr, size; int pci, res; res = OF_getencprop(node, "#address-cells", &addr, sizeof(addr)); if (res == -1) addr = 2; res = OF_getencprop(node, "#size-cells", &size, sizeof(size)); if (res == -1) size = 1; pci = 0; if (addr == 3 && size == 2) { res = OF_getprop(node, "device_type", type, sizeof(type)); if (res != -1) { type[sizeof(type) - 1] = '\0'; if (strcmp(type, "pci") == 0 || strcmp(type, "pciex")== 0) pci = 1; } } if (addrp != NULL) *addrp = addr; if (sizep != NULL) *sizep = size; if (pcip != NULL) *pcip = pci; } int ofw_reg_to_paddr(phandle_t dev, int regno, bus_addr_t *paddr, bus_size_t *psize, pcell_t *ppci_hi) { pcell_t cell[32], pci_hi; uint64_t addr, raddr, baddr; uint64_t size, rsize; uint32_t c, nbridge, naddr, nsize; phandle_t bridge, parent; u_int spc, rspc; int pci, pcib, res; /* Sanity checking. */ if (dev == 0) return (EINVAL); bridge = OF_parent(dev); if (bridge == 0) return (EINVAL); if (regno < 0) return (EINVAL); if (paddr == NULL || psize == NULL) return (EINVAL); get_addr_props(bridge, &naddr, &nsize, &pci); res = OF_getencprop(dev, (pci) ? "assigned-addresses" : "reg", cell, sizeof(cell)); if (res == -1) return (ENXIO); if (res % sizeof(cell[0])) return (ENXIO); res /= sizeof(cell[0]); regno *= naddr + nsize; if (regno + naddr + nsize > res) return (EINVAL); pci_hi = pci ? cell[regno] : OFW_PADDR_NOT_PCI; spc = pci_hi & OFW_PCI_PHYS_HI_SPACEMASK; addr = 0; for (c = 0; c < naddr; c++) addr = ((uint64_t)addr << 32) | cell[regno++]; size = 0; for (c = 0; c < nsize; c++) size = ((uint64_t)size << 32) | cell[regno++]; /* * Map the address range in the bridge's decoding window as given * by the "ranges" property. If a node doesn't have such property * or the property is empty, we assume an identity mapping. The * standard says a missing property indicates no possible mapping. * This code is more liberal since the intended use is to get a * console running early, and a printf to warn of malformed data * is probably futile before the console is fully set up. */ parent = OF_parent(bridge); while (parent != 0) { get_addr_props(parent, &nbridge, NULL, &pcib); res = OF_getencprop(bridge, "ranges", cell, sizeof(cell)); if (res < 1) goto next; if (res % sizeof(cell[0])) return (ENXIO); /* Capture pci_hi if we just transitioned onto a PCI bus. */ if (pcib && pci_hi == OFW_PADDR_NOT_PCI) { pci_hi = cell[0]; spc = pci_hi & OFW_PCI_PHYS_HI_SPACEMASK; } res /= sizeof(cell[0]); regno = 0; while (regno < res) { rspc = (pci ? cell[regno] : OFW_PADDR_NOT_PCI) & OFW_PCI_PHYS_HI_SPACEMASK; if (rspc != spc) { regno += naddr + nbridge + nsize; continue; } raddr = 0; for (c = 0; c < naddr; c++) raddr = ((uint64_t)raddr << 32) | cell[regno++]; rspc = (pcib) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : OFW_PADDR_NOT_PCI; baddr = 0; for (c = 0; c < nbridge; c++) baddr = ((uint64_t)baddr << 32) | cell[regno++]; rsize = 0; for (c = 0; c < nsize; c++) rsize = ((uint64_t)rsize << 32) | cell[regno++]; if (addr < raddr || addr >= raddr + rsize) continue; addr = addr - raddr + baddr; if (rspc != OFW_PADDR_NOT_PCI) spc = rspc; } next: bridge = parent; parent = OF_parent(bridge); get_addr_props(bridge, &naddr, &nsize, &pci); } KASSERT(addr <= BUS_SPACE_MAXADDR, ("Bus address is too large: %jx", (uintmax_t)addr)); KASSERT(size <= BUS_SPACE_MAXSIZE, ("Bus size is too large: %jx", (uintmax_t)size)); *paddr = addr; *psize = size; if (ppci_hi != NULL) *ppci_hi = pci_hi; return (0); } -/* Parse cmd line args as env - copied from xlp_machdep. */ -/* XXX-BZ this should really be centrally provided for all (boot) code. */ -static void -_parse_bootargs(char *cmdline) -{ - char *n, *v; - - while ((v = strsep(&cmdline, " \n")) != NULL) { - if (*v == '\0') - continue; - if (*v == '-') { - while (*v != '\0') { - v++; - switch (*v) { - case 'a': boothowto |= RB_ASKNAME; break; - /* Someone should simulate that ;-) */ - case 'C': boothowto |= RB_CDROM; break; - case 'd': boothowto |= RB_KDB; break; - case 'D': boothowto |= RB_MULTIPLE; break; - case 'm': boothowto |= RB_MUTE; break; - case 'g': boothowto |= RB_GDB; break; - case 'h': boothowto |= RB_SERIAL; break; - case 'p': boothowto |= RB_PAUSE; break; - case 'r': boothowto |= RB_DFLTROOT; break; - case 's': boothowto |= RB_SINGLE; break; - case 'v': boothowto |= RB_VERBOSE; break; - } - } - } else { - n = strsep(&v, "="); - if (v == NULL) - kern_setenv(n, "1"); - else - kern_setenv(n, v); - } - } -} - /* * This is intended to be called early on, right after the OF system is * initialized, so pmap may not be up yet. */ int ofw_parse_bootargs(void) { phandle_t chosen; char buf[2048]; /* early stack supposedly big enough */ int err; chosen = OF_finddevice("/chosen"); if (chosen == -1) return (chosen); if ((err = OF_getprop(chosen, "bootargs", buf, sizeof(buf))) != -1) { - _parse_bootargs(buf); + boothowto |= boot_parse_cmdline(buf); return (0); } return (err); } Index: head/sys/mips/atheros/ar531x/ar5315_machdep.c =================================================================== --- head/sys/mips/atheros/ar531x/ar5315_machdep.c (revision 336244) +++ head/sys/mips/atheros/ar531x/ar5315_machdep.c (revision 336245) @@ -1,351 +1,319 @@ /*- * Copyright (c) 2016, Hiroki Mori * Copyright (c) 2009 Oleksandr Tymoshenko * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_ar531x.h" #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include extern char edata[], end[]; uint32_t ar711_base_mac[ETHER_ADDR_LEN]; /* 4KB static data aread to keep a copy of the bootload env until the dynamic kenv is setup */ char boot1_env[4096]; -/* - * We get a string in from Redboot with the all the arguments together, - * "foo=bar bar=baz". Split them up and save in kenv. - */ -static void -parse_argv(char *str) -{ - char *n, *v; - - while ((v = strsep(&str, " ")) != NULL) { - if (*v == '\0') - continue; - if (*v == '-') { - while (*v != '\0') { - v++; - switch (*v) { - case 'a': boothowto |= RB_ASKNAME; break; - case 'd': boothowto |= RB_KDB; break; - case 'g': boothowto |= RB_GDB; break; - case 's': boothowto |= RB_SINGLE; break; - case 'v': boothowto |= RB_VERBOSE; break; - } - } - } else { - n = strsep(&v, "="); - if (v == NULL) - kern_setenv(n, "1"); - else - kern_setenv(n, v); - } - } -} - void platform_cpu_init() { /* Nothing special */ } void platform_reset(void) { ar531x_device_reset(); /* Wait for reset */ while(1) ; } /* * Obtain the MAC address via the Redboot environment. */ static void ar5315_redboot_get_macaddr(void) { char *var; int count = 0; /* * "ethaddr" is passed via envp on RedBoot platforms * "kmac" is passed via argv on RouterBOOT platforms */ if ((var = kern_getenv("ethaddr")) != NULL || (var = kern_getenv("kmac")) != NULL) { count = sscanf(var, "%x%*c%x%*c%x%*c%x%*c%x%*c%x", &ar711_base_mac[0], &ar711_base_mac[1], &ar711_base_mac[2], &ar711_base_mac[3], &ar711_base_mac[4], &ar711_base_mac[5]); if (count < 6) memset(ar711_base_mac, 0, sizeof(ar711_base_mac)); freeenv(var); } } #if defined(SOC_VENDOR) || defined(SOC_MODEL) || defined(SOC_REV) static SYSCTL_NODE(_hw, OID_AUTO, soc, CTLFLAG_RD, 0, "System on Chip information"); #endif #if defined(SOC_VENDOR) static char hw_soc_vendor[] = SOC_VENDOR; SYSCTL_STRING(_hw_soc, OID_AUTO, vendor, CTLFLAG_RD, hw_soc_vendor, 0, "SoC vendor"); #endif #if defined(SOC_MODEL) static char hw_soc_model[] = SOC_MODEL; SYSCTL_STRING(_hw_soc, OID_AUTO, model, CTLFLAG_RD, hw_soc_model, 0, "SoC model"); #endif #if defined(SOC_REV) static char hw_soc_revision[] = SOC_REV; SYSCTL_STRING(_hw_soc, OID_AUTO, revision, CTLFLAG_RD, hw_soc_revision, 0, "SoC revision"); #endif #if defined(DEVICE_VENDOR) || defined(DEVICE_MODEL) || defined(DEVICE_REV) static SYSCTL_NODE(_hw, OID_AUTO, device, CTLFLAG_RD, 0, "Board information"); #endif #if defined(DEVICE_VENDOR) static char hw_device_vendor[] = DEVICE_VENDOR; SYSCTL_STRING(_hw_device, OID_AUTO, vendor, CTLFLAG_RD, hw_device_vendor, 0, "Board vendor"); #endif #if defined(DEVICE_MODEL) static char hw_device_model[] = DEVICE_MODEL; SYSCTL_STRING(_hw_device, OID_AUTO, model, CTLFLAG_RD, hw_device_model, 0, "Board model"); #endif #if defined(DEVICE_REV) static char hw_device_revision[] = DEVICE_REV; SYSCTL_STRING(_hw_device, OID_AUTO, revision, CTLFLAG_RD, hw_device_revision, 0, "Board revision"); #endif void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { uint64_t platform_counter_freq; int argc = 0, i; char **argv = NULL; #ifndef AR531X_ENV_UBOOT char **envp = NULL; #endif vm_offset_t kernend; /* * clear the BSS and SBSS segments, this should be first call in * the function */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); /* Initialize pcpu stuff */ mips_pcpu0_init(); /* * Until some more sensible abstractions for uboot/redboot * environment handling, we have to make this a compile-time * hack. The existing code handles the uboot environment * very incorrectly so we should just ignore initialising * the relevant pointers. */ #ifndef AR531X_ENV_UBOOT argc = a0; argv = (char**)a1; envp = (char**)a2; #endif /* * Protect ourselves from garbage in registers */ if (MIPS_IS_VALID_PTR(envp)) { for (i = 0; envp[i]; i += 2) { if (strcmp(envp[i], "memsize") == 0) realmem = btoc(strtoul(envp[i+1], NULL, 16)); } } ar5315_detect_sys_type(); // RedBoot SDRAM Detect is missing // ar531x_detect_mem_size(); /* * Just wild guess. RedBoot let us down and didn't reported * memory size */ if (realmem == 0) realmem = btoc(16*1024*1024); /* * Allow build-time override in case Redboot lies * or in other situations (eg where there's u-boot) * where there isn't (yet) a convienent method of * being told how much RAM is available. * * This happens on at least the Ubiquiti LS-SR71A * board, where redboot says there's 16mb of RAM * but in fact there's 32mb. */ #if defined(AR531X_REALMEM) realmem = btoc(AR531X_REALMEM); #endif /* phys_avail regions are in bytes */ phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); phys_avail[1] = ctob(realmem); dump_avail[0] = phys_avail[0]; dump_avail[1] = phys_avail[1] - phys_avail[0]; physmem = realmem; /* * ns8250 uart code uses DELAY so ticker should be inititalized * before cninit. And tick_init_params refers to hz, so * init_param1 * should be called first. */ init_param1(); boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */ // boothowto |= RB_VERBOSE; // boothowto |= (RB_SINGLE); /* Detect the system type - this is needed for subsequent chipset-specific calls */ ar531x_device_soc_init(); ar531x_detect_sys_frequency(); platform_counter_freq = ar531x_cpu_freq(); mips_timer_init_params(platform_counter_freq, 1); cninit(); init_static_kenv(boot1_env, sizeof(boot1_env)); printf("CPU platform: %s\n", ar5315_get_system_type()); printf("CPU Frequency=%d MHz\n", ar531x_cpu_freq() / 1000000); printf("CPU DDR Frequency=%d MHz\n", ar531x_ddr_freq() / 1000000); printf("CPU AHB Frequency=%d MHz\n", ar531x_ahb_freq() / 1000000); printf("platform frequency: %lld\n", platform_counter_freq); printf("arguments: \n"); printf(" a0 = %08x\n", a0); printf(" a1 = %08x\n", a1); printf(" a2 = %08x\n", a2); printf(" a3 = %08x\n", a3); /* * XXX this code is very redboot specific. */ printf("Cmd line:"); if (MIPS_IS_VALID_PTR(argv)) { for (i = 0; i < argc; i++) { printf(" %s", argv[i]); - parse_argv(argv[i]); + boothowto |= boot_parse_arg(argv[i]); } } else printf ("argv is invalid"); printf("\n"); printf("Environment:\n"); #if 0 if (MIPS_IS_VALID_PTR(envp)) { if (envp[0] && strchr(envp[0], '=') ) { char *env_val; // for (i = 0; envp[i]; i++) { env_val = strchr(envp[i], '='); /* Not sure if we correct to change data, but env in RAM */ *(env_val++) = '\0'; printf("= %s = %s\n", envp[i], env_val); kern_setenv(envp[i], env_val); } } else { for (i = 0; envp[i]; i+=2) { printf(" %s = %s\n", envp[i], envp[i+1]); kern_setenv(envp[i], envp[i+1]); } } } else printf ("envp is invalid\n"); #else printf ("envp skiped\n"); #endif /* Redboot if_are MAC address is in the environment */ ar5315_redboot_get_macaddr(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); ar531x_device_start(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } Index: head/sys/mips/atheros/ar71xx_machdep.c =================================================================== --- head/sys/mips/atheros/ar71xx_machdep.c (revision 336244) +++ head/sys/mips/atheros/ar71xx_machdep.c (revision 336245) @@ -1,484 +1,452 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2009 Oleksandr Tymoshenko * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_ar71xx.h" #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern char edata[], end[]; /* 4KB static data aread to keep a copy of the bootload env until the dynamic kenv is setup */ char boot1_env[4096]; -/* - * We get a string in from Redboot with the all the arguments together, - * "foo=bar bar=baz". Split them up and save in kenv. - */ -static void -parse_argv(char *str) -{ - char *n, *v; - - while ((v = strsep(&str, " ")) != NULL) { - if (*v == '\0') - continue; - if (*v == '-') { - while (*v != '\0') { - v++; - switch (*v) { - case 'a': boothowto |= RB_ASKNAME; break; - case 'd': boothowto |= RB_KDB; break; - case 'g': boothowto |= RB_GDB; break; - case 's': boothowto |= RB_SINGLE; break; - case 'v': boothowto |= RB_VERBOSE; break; - } - } - } else { - n = strsep(&v, "="); - if (v == NULL) - kern_setenv(n, "1"); - else - kern_setenv(n, v); - } - } -} - void platform_cpu_init() { /* Nothing special */ } void platform_reset(void) { ar71xx_device_stop(RST_RESET_FULL_CHIP); /* Wait for reset */ while(1) ; } /* * Obtain the MAC address via the Redboot environment. */ static int ar71xx_redboot_get_macaddr(void) { char *var; int count = 0, i; uint32_t macaddr[ETHER_ADDR_LEN]; uint8_t tmpmac[ETHER_ADDR_LEN]; /* * "ethaddr" is passed via envp on RedBoot platforms * "kmac" is passed via argv on RouterBOOT platforms */ if ((var = kern_getenv("ethaddr")) != NULL || (var = kern_getenv("kmac")) != NULL) { count = sscanf(var, "%x%*c%x%*c%x%*c%x%*c%x%*c%x", &macaddr[0], &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); if (count < 6) { memset(macaddr, 0, sizeof(macaddr)); } else { for (i = 0; i < ETHER_ADDR_LEN; i++) tmpmac[i] = macaddr[i] & 0xff; (void) ar71xx_mac_addr_init(ar71xx_board_mac_addr, tmpmac, 0, /* offset */ 0); /* is_local */ } freeenv(var); return (0); } return (-1); } #ifdef AR71XX_ENV_ROUTERBOOT /* * RouterBoot gives us the board memory in a command line argument. */ static int ar71xx_routerboot_get_mem(int argc, char **argv) { int i, board_mem; /* * Protect ourselves from garbage in registers. */ if (!MIPS_IS_VALID_PTR(argv)) return (0); for (i = 0; i < argc; i++) { if (argv[i] == NULL) continue; if (strncmp(argv[i], "mem=", 4) == 0) { if (sscanf(argv[i] + 4, "%dM", &board_mem) == 1) return (btoc(board_mem * 1024 * 1024)); } } return (0); } #endif /* * Handle initialising the MAC address from a specific EEPROM * offset. * * This is done during (very) early boot. * * hint.ar71xx.0.eeprom_mac_addr=
* hint.ar71xx.0.eeprom_mac_isascii=<0|1> */ static int ar71xx_platform_read_eeprom_mac(void) { long eeprom_mac_addr = 0; const char *mac; int i, readascii = 0; uint8_t macaddr[ETHER_ADDR_LEN]; if (resource_long_value("ar71xx", 0, "eeprom_mac_addr", &eeprom_mac_addr) != 0) return (-1); /* get a pointer to the EEPROM MAC address */ mac = (const char *) MIPS_PHYS_TO_KSEG1(eeprom_mac_addr); /* Check if it's ASCII or not */ if (resource_int_value("ar71xx", 0, "eeprom_mac_isascii", &readascii) == 0 && readascii == 1) { printf("ar71xx: Overriding MAC from EEPROM (ascii)\n"); for (i = 0; i < 6; i++) { macaddr[i] = strtol(&(mac[i*3]), NULL, 16); } } else { printf("ar71xx: Overriding MAC from EEPROM\n"); for (i = 0; i < 6; i++) { macaddr[i] = mac[i]; } } /* Set the default board MAC */ (void) ar71xx_mac_addr_init(ar71xx_board_mac_addr, macaddr, 0, /* offset */ 0); /* is_local */ printf("ar71xx: Board MAC: %6D\n", ar71xx_board_mac_addr, ":"); return (0); } /* * Populate a kenv hint for the given device based on the given * MAC address and offset. * * Returns 0 if ok, < 0 on error. */ static int ar71xx_platform_set_mac_hint(const char *dev, int unit, const uint8_t *macaddr, int offset, int islocal) { char macstr[32]; uint8_t lclmac[ETHER_ADDR_LEN]; char devstr[32]; /* Initialise the MAC address, plus/minus the offset */ if (ar71xx_mac_addr_init(lclmac, macaddr, offset, islocal) != 0) { return (-1); } /* Turn it into a string */ snprintf(macstr, 32, "%6D", lclmac, ":"); snprintf(devstr, 32, "hint.%s.%d.macaddr", dev, unit); printf(" %s => %s\n", devstr, macstr); /* Call setenv */ if (kern_setenv(devstr, macstr) != 0) { printf("%s: failed to set hint (%s => %s)\n", __func__, devstr, macstr); return (-1); } return (0); } /* * Iterate through the list of boot time hints that populate * a device MAC address hint based on the "board" MAC address. * * ar71xx_mac_map.X.devid= * ar71xx_mac_map.X.unitid= * ar71xx_mac_map.X.offset= * ar71xx_mac_map.X.is_local=<1 or 0> */ static int ar71xx_platform_check_mac_hints(void) { int i; const char *devid; int offset, is_local, unitid; for (i = 0; i < 8; i++) { if (resource_string_value("ar71xx_mac_map", i, "devid", &devid) != 0) break; if (resource_int_value("ar71xx_mac_map", i, "unitid", &unitid) != 0) break; if (resource_int_value("ar71xx_mac_map", i, "offset", &offset) != 0) break; if (resource_int_value("ar71xx_mac_map", i, "is_local", &is_local) != 0) break; printf("ar71xx: devid '%s.%d', MAC offset '%d'\n", devid, unitid, offset); (void) ar71xx_platform_set_mac_hint(devid, unitid, ar71xx_board_mac_addr, offset, is_local); } return (0); } extern char cpu_model[]; void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { uint64_t platform_counter_freq; int argc = 0, i; char **argv = NULL, **envp = NULL; vm_offset_t kernend; /* * clear the BSS and SBSS segments, this should be first call in * the function */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); /* Initialize pcpu stuff */ mips_pcpu0_init(); /* * Until some more sensible abstractions for uboot/redboot * environment handling, we have to make this a compile-time * hack. The existing code handles the uboot environment * very incorrectly so we should just ignore initialising * the relevant pointers. */ #ifndef AR71XX_ENV_UBOOT argc = a0; argv = (char**)a1; envp = (char**)a2; #endif /* * Protect ourselves from garbage in registers */ if (MIPS_IS_VALID_PTR(envp)) { for (i = 0; envp[i]; i += 2) { if (strcmp(envp[i], "memsize") == 0) realmem = btoc(strtoul(envp[i+1], NULL, 16)); else if (strcmp(envp[i], "bootverbose") == 0) bootverbose = btoc(strtoul(envp[i+1], NULL, 10)); } } bootverbose = 1; #ifdef AR71XX_ENV_ROUTERBOOT /* * RouterBoot informs the board memory as a command line argument. */ if (realmem == 0) realmem = ar71xx_routerboot_get_mem(argc, argv); #endif /* * Just wild guess. RedBoot let us down and didn't reported * memory size */ if (realmem == 0) realmem = btoc(32*1024*1024); /* * Allow build-time override in case Redboot lies * or in other situations (eg where there's u-boot) * where there isn't (yet) a convienent method of * being told how much RAM is available. * * This happens on at least the Ubiquiti LS-SR71A * board, where redboot says there's 16mb of RAM * but in fact there's 32mb. */ #if defined(AR71XX_REALMEM) realmem = btoc(AR71XX_REALMEM); #endif /* phys_avail regions are in bytes */ phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); phys_avail[1] = ctob(realmem); dump_avail[0] = 0; dump_avail[1] = phys_avail[1]; physmem = realmem; /* * ns8250 uart code uses DELAY so ticker should be inititalized * before cninit. And tick_init_params refers to hz, so * init_param1 * should be called first. */ init_param1(); /* Detect the system type - this is needed for subsequent chipset-specific calls */ ar71xx_detect_sys_type(); ar71xx_detect_sys_frequency(); platform_counter_freq = ar71xx_cpu_freq(); mips_timer_init_params(platform_counter_freq, 1); cninit(); init_static_kenv(boot1_env, sizeof(boot1_env)); printf("CPU platform: %s\n", ar71xx_get_system_type()); printf("CPU Frequency=%d MHz\n", u_ar71xx_cpu_freq / 1000000); printf("CPU DDR Frequency=%d MHz\n", u_ar71xx_ddr_freq / 1000000); printf("CPU AHB Frequency=%d MHz\n", u_ar71xx_ahb_freq / 1000000); printf("platform frequency: %lld MHz\n", platform_counter_freq / 1000000); printf("CPU reference clock: %d MHz\n", u_ar71xx_refclk / 1000000); printf("CPU MDIO clock: %d MHz\n", u_ar71xx_mdio_freq / 1000000); printf("arguments: \n"); printf(" a0 = %08x\n", a0); printf(" a1 = %08x\n", a1); printf(" a2 = %08x\n", a2); printf(" a3 = %08x\n", a3); strcpy(cpu_model, ar71xx_get_system_type()); /* * XXX this code is very redboot specific. */ printf("Cmd line:"); if (MIPS_IS_VALID_PTR(argv)) { for (i = 0; i < argc; i++) { printf(" %s", argv[i]); - parse_argv(argv[i]); + boothowto |= boot_parse_arg(argv[i]); } } else printf ("argv is invalid"); printf("\n"); printf("Environment:\n"); if (MIPS_IS_VALID_PTR(envp)) { for (i = 0; envp[i]; i+=2) { printf(" %s = %s\n", envp[i], envp[i+1]); kern_setenv(envp[i], envp[i+1]); } } else printf ("envp is invalid\n"); /* Platform setup */ init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); /* * Reset USB devices */ ar71xx_init_usb_peripheral(); /* * Reset internal ethernet switch, if one exists */ ar71xx_reset_ethernet_switch(); /* * Initialise the gmac driver. */ ar71xx_init_gmac(); /* Redboot if_arge MAC address is in the environment */ (void) ar71xx_redboot_get_macaddr(); /* Various other boards need things to come out of EEPROM */ (void) ar71xx_platform_read_eeprom_mac(); /* Initialise the MAC address hint map */ ar71xx_platform_check_mac_hints(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } Index: head/sys/mips/cavium/octeon_machdep.c =================================================================== --- head/sys/mips/cavium/octeon_machdep.c (revision 336244) +++ head/sys/mips/cavium/octeon_machdep.c (revision 336245) @@ -1,721 +1,697 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Wojciech A. Koszek * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__mips_n64) #define MAX_APP_DESC_ADDR 0xffffffffafffffff #else #define MAX_APP_DESC_ADDR 0xafffffff #endif struct octeon_feature_description { octeon_feature_t ofd_feature; const char *ofd_string; }; extern int *end; extern char cpu_model[]; extern char cpu_board[]; static char octeon_kenv[0x2000]; static const struct octeon_feature_description octeon_feature_descriptions[] = { { OCTEON_FEATURE_SAAD, "SAAD" }, { OCTEON_FEATURE_ZIP, "ZIP" }, { OCTEON_FEATURE_CRYPTO, "CRYPTO" }, { OCTEON_FEATURE_DORM_CRYPTO, "DORM_CRYPTO" }, { OCTEON_FEATURE_PCIE, "PCIE" }, { OCTEON_FEATURE_SRIO, "SRIO" }, { OCTEON_FEATURE_KEY_MEMORY, "KEY_MEMORY" }, { OCTEON_FEATURE_LED_CONTROLLER, "LED_CONTROLLER" }, { OCTEON_FEATURE_TRA, "TRA" }, { OCTEON_FEATURE_MGMT_PORT, "MGMT_PORT" }, { OCTEON_FEATURE_RAID, "RAID" }, { OCTEON_FEATURE_USB, "USB" }, { OCTEON_FEATURE_NO_WPTR, "NO_WPTR" }, { OCTEON_FEATURE_DFA, "DFA" }, { OCTEON_FEATURE_MDIO_CLAUSE_45, "MDIO_CLAUSE_45" }, { OCTEON_FEATURE_NPEI, "NPEI" }, { OCTEON_FEATURE_ILK, "ILK" }, { OCTEON_FEATURE_HFA, "HFA" }, { OCTEON_FEATURE_DFM, "DFM" }, { OCTEON_FEATURE_CIU2, "CIU2" }, { OCTEON_FEATURE_DICI_MODE, "DICI_MODE" }, { OCTEON_FEATURE_BIT_EXTRACTOR, "BIT_EXTRACTOR" }, { OCTEON_FEATURE_NAND, "NAND" }, { OCTEON_FEATURE_MMC, "MMC" }, { OCTEON_FEATURE_PKND, "PKND" }, { OCTEON_FEATURE_CN68XX_WQE, "CN68XX_WQE" }, { 0, NULL } }; static uint64_t octeon_get_ticks(void); static unsigned octeon_get_timecount(struct timecounter *tc); static void octeon_boot_params_init(register_t ptr); static void octeon_init_kenv(register_t ptr); static struct timecounter octeon_timecounter = { octeon_get_timecount, /* get_timecount */ 0, /* no poll_pps */ 0xffffffffu, /* octeon_mask */ 0, /* frequency */ "Octeon", /* name */ 900, /* quality (adjusted in code) */ }; void platform_cpu_init() { /* Nothing special yet */ } /* * Perform a board-level soft-reset. */ void platform_reset(void) { cvmx_write_csr(CVMX_CIU_SOFT_RST, 1); } /* * octeon_debug_symbol * * Does nothing. * Used to mark the point for simulator to begin tracing */ void octeon_debug_symbol(void) { } /* * octeon_ciu_reset * * Shutdown all CIU to IP2, IP3 mappings */ void octeon_ciu_reset(void) { uint64_t cvmctl; /* Disable all CIU interrupts by default */ cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2), 0); cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2+1), 0); cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2), 0); cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2+1), 0); #ifdef SMP /* Enable the MBOX interrupts. */ cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2+1), (1ull << (OCTEON_IRQ_MBOX0 - 8)) | (1ull << (OCTEON_IRQ_MBOX1 - 8))); #endif /* * Move the Performance Counter interrupt to OCTEON_PMC_IRQ */ cvmctl = mips_rd_cvmctl(); cvmctl &= ~(7 << 7); cvmctl |= (OCTEON_PMC_IRQ + 2) << 7; mips_wr_cvmctl(cvmctl); } static void octeon_memory_init(void) { vm_paddr_t phys_end; int64_t addr; unsigned i, j; phys_end = round_page(MIPS_KSEG0_TO_PHYS((vm_offset_t)&end)); if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) { /* Simulator we limit to 96 meg */ phys_avail[0] = phys_end; phys_avail[1] = 96 << 20; dump_avail[0] = phys_avail[0]; dump_avail[1] = phys_avail[1]; realmem = physmem = btoc(phys_avail[1] - phys_avail[0]); return; } /* * Allocate memory from bootmem 1MB at a time and merge * adjacent entries. */ i = 0; while (i < PHYS_AVAIL_ENTRIES) { /* * If there is less than 2MB of memory available in 128-byte * blocks, do not steal any more memory. We need to leave some * memory for the command queues to be allocated out of. */ if (cvmx_bootmem_available_mem(128) < 2 << 20) break; addr = cvmx_bootmem_phy_alloc(1 << 20, phys_end, ~(vm_paddr_t)0, PAGE_SIZE, 0); if (addr == -1) break; /* * The SDK needs to be able to easily map any memory that might * come to it e.g. in the form of an mbuf. Because on !n64 we * can't direct-map some addresses and we don't want to manage * temporary mappings within the SDK, don't feed memory that * can't be direct-mapped to the kernel. */ #if !defined(__mips_n64) if (!MIPS_DIRECT_MAPPABLE(addr + (1 << 20) - 1)) continue; #endif physmem += btoc(1 << 20); if (i > 0 && phys_avail[i - 1] == addr) { phys_avail[i - 1] += 1 << 20; continue; } phys_avail[i + 0] = addr; phys_avail[i + 1] = addr + (1 << 20); i += 2; } for (j = 0; j < i; j++) dump_avail[j] = phys_avail[j]; realmem = physmem; } void platform_start(__register_t a0, __register_t a1, __register_t a2 __unused, __register_t a3) { const struct octeon_feature_description *ofd; uint64_t platform_counter_freq; int rv; mips_postboot_fixup(); /* * Initialize boot parameters so that we can determine things like * which console we shoud use, etc. */ octeon_boot_params_init(a3); /* Initialize pcpu stuff */ mips_pcpu0_init(); mips_timer_early_init(cvmx_sysinfo_get()->cpu_clock_hz); /* Initialize console. */ cninit(); /* * Display information about the CPU. */ #if !defined(OCTEON_MODEL) printf("Using runtime CPU model checks.\n"); #else printf("Compiled for CPU model: " __XSTRING(OCTEON_MODEL) "\n"); #endif strcpy(cpu_model, octeon_model_get_string(cvmx_get_proc_id())); printf("CPU Model: %s\n", cpu_model); printf("CPU clock: %uMHz Core Mask: %#x\n", cvmx_sysinfo_get()->cpu_clock_hz / 1000000, cvmx_sysinfo_get()->core_mask); rv = octeon_model_version_check(cvmx_get_proc_id()); if (rv == -1) panic("%s: kernel not compatible with this processor.", __func__); /* * Display information about the board. */ #if defined(OCTEON_BOARD_CAPK_0100ND) strcpy(cpu_board, "CAPK-0100ND"); if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_CN3010_EVB_HS5) { panic("Compiled for %s, but board type is %s.", cpu_board, cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type)); } #else strcpy(cpu_board, cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type)); #endif printf("Board: %s\n", cpu_board); printf("Board Type: %u Revision: %u/%u\n", cvmx_sysinfo_get()->board_type, cvmx_sysinfo_get()->board_rev_major, cvmx_sysinfo_get()->board_rev_minor); printf("Serial number: %s\n", cvmx_sysinfo_get()->board_serial_number); /* * Additional on-chip hardware/settings. * * XXX Display PCI host/target? What else? */ printf("MAC address base: %6D (%u configured)\n", cvmx_sysinfo_get()->mac_addr_base, ":", cvmx_sysinfo_get()->mac_addr_count); octeon_ciu_reset(); /* * Convert U-Boot 'bootoctlinux' loader command line arguments into * boot flags and kernel environment variables. */ bootverbose = 1; octeon_init_kenv(a3); /* * For some reason on the cn38xx simulator ebase register is set to * 0x80001000 at bootup time. Move it back to the default, but * when we move to having support for multiple executives, we need * to rethink this. */ mips_wr_ebase(0x80000000); octeon_memory_init(); init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif cpu_clock = cvmx_sysinfo_get()->cpu_clock_hz; platform_counter_freq = cpu_clock; octeon_timecounter.tc_frequency = cpu_clock; platform_timecounter = &octeon_timecounter; mips_timer_init_params(platform_counter_freq, 0); set_cputicker(octeon_get_ticks, cpu_clock, 0); #ifdef SMP /* * Clear any pending IPIs. */ cvmx_write_csr(CVMX_CIU_MBOX_CLRX(0), 0xffffffff); #endif printf("Octeon SDK: %s\n", OCTEON_SDK_VERSION_STRING); printf("Available Octeon features:"); for (ofd = octeon_feature_descriptions; ofd->ofd_string != NULL; ofd++) if (octeon_has_feature(ofd->ofd_feature)) printf(" %s", ofd->ofd_string); printf("\n"); } static uint64_t octeon_get_ticks(void) { uint64_t cvmcount; CVMX_MF_CYCLE(cvmcount); return (cvmcount); } static unsigned octeon_get_timecount(struct timecounter *tc) { return ((unsigned)octeon_get_ticks()); } static int sysctl_machdep_led_display(SYSCTL_HANDLER_ARGS) { size_t buflen; char buf[9]; int error; if (req->newptr == NULL) return (EINVAL); if (cvmx_sysinfo_get()->led_display_base_addr == 0) return (ENODEV); /* * Revision 1.x of the EBT3000 only supports 4 characters, but * other devices support 8. */ if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBT3000 && cvmx_sysinfo_get()->board_rev_major == 1) buflen = 4; else buflen = 8; if (req->newlen > buflen) return (E2BIG); error = SYSCTL_IN(req, buf, req->newlen); if (error != 0) return (error); buf[req->newlen] = '\0'; ebt3000_str_write(buf); return (0); } SYSCTL_PROC(_machdep, OID_AUTO, led_display, CTLTYPE_STRING | CTLFLAG_WR, NULL, 0, sysctl_machdep_led_display, "A", "String to display on LED display"); void cvmx_dvprintf(const char *fmt, va_list ap) { if (!bootverbose) return; vprintf(fmt, ap); } void cvmx_dprintf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); cvmx_dvprintf(fmt, ap); va_end(ap); } /** * version of printf that works better in exception context. * * @param format * * XXX If this function weren't in cvmx-interrupt.c, we'd use the SDK version. */ void cvmx_safe_printf(const char *format, ...) { char buffer[256]; char *ptr = buffer; int count; va_list args; va_start(args, format); #ifndef __U_BOOT__ count = vsnprintf(buffer, sizeof(buffer), format, args); #else count = vsprintf(buffer, format, args); #endif va_end(args); while (count-- > 0) { cvmx_uart_lsr_t lsrval; /* Spin until there is room */ do { lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(0)); #if !defined(CONFIG_OCTEON_SIM_SPEED) if (lsrval.s.temt == 0) cvmx_wait(10000); /* Just to reduce the load on the system */ #endif } while (lsrval.s.temt == 0); if (*ptr == '\n') cvmx_write_csr(CVMX_MIO_UARTX_THR(0), '\r'); cvmx_write_csr(CVMX_MIO_UARTX_THR(0), *ptr++); } } /* impSTART: This stuff should move back into the Cavium SDK */ /* **************************************************************************************** * * APP/BOOT DESCRIPTOR STUFF * **************************************************************************************** */ /* Define the struct that is initialized by the bootloader used by the * startup code. * * Copyright (c) 2004, 2005, 2006 Cavium Networks. * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice is included verbatim in any distributions. No written agreement, * license, or royalty fee is required for any of the authorized uses. * Modifications to this software may be copyrighted by their authors * and need not follow the licensing terms described here, provided that * the new terms are clearly indicated on the first page of each file where * they apply. */ #define OCTEON_CURRENT_DESC_VERSION 6 #define OCTEON_ARGV_MAX_ARGS (64) #define OCTOEN_SERIAL_LEN 20 typedef struct { /* Start of block referenced by assembly code - do not change! */ uint32_t desc_version; uint32_t desc_size; uint64_t stack_top; uint64_t heap_base; uint64_t heap_end; uint64_t entry_point; /* Only used by bootloader */ uint64_t desc_vaddr; /* End of This block referenced by assembly code - do not change! */ uint32_t exception_base_addr; uint32_t stack_size; uint32_t heap_size; uint32_t argc; /* Argc count for application */ uint32_t argv[OCTEON_ARGV_MAX_ARGS]; uint32_t flags; uint32_t core_mask; uint32_t dram_size; /**< DRAM size in megabyes */ uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ uint32_t eclock_hz; /**< CPU clock speed, in hz */ uint32_t dclock_hz; /**< DRAM clock speed, in hz */ uint32_t spi_clock_hz; /**< SPI4 clock in hz */ uint16_t board_type; uint8_t board_rev_major; uint8_t board_rev_minor; uint16_t chip_type; uint8_t chip_rev_major; uint8_t chip_rev_minor; char board_serial_number[OCTOEN_SERIAL_LEN]; uint8_t mac_addr_base[6]; uint8_t mac_addr_count; uint64_t cvmx_desc_vaddr; } octeon_boot_descriptor_t; static cvmx_bootinfo_t * octeon_process_app_desc_ver_6(octeon_boot_descriptor_t *app_desc_ptr) { cvmx_bootinfo_t *octeon_bootinfo; /* XXX Why is 0x00000000ffffffffULL a bad value? */ if (app_desc_ptr->cvmx_desc_vaddr == 0 || app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) { cvmx_safe_printf("Bad octeon_bootinfo %#jx\n", (uintmax_t)app_desc_ptr->cvmx_desc_vaddr); return (NULL); } octeon_bootinfo = cvmx_phys_to_ptr(app_desc_ptr->cvmx_desc_vaddr); if (octeon_bootinfo->major_version != 1) { cvmx_safe_printf("Incompatible CVMX descriptor from bootloader: %d.%d %p\n", (int) octeon_bootinfo->major_version, (int) octeon_bootinfo->minor_version, octeon_bootinfo); return (NULL); } cvmx_sysinfo_minimal_initialize(octeon_bootinfo->phy_mem_desc_addr, octeon_bootinfo->board_type, octeon_bootinfo->board_rev_major, octeon_bootinfo->board_rev_minor, octeon_bootinfo->eclock_hz); memcpy(cvmx_sysinfo_get()->mac_addr_base, octeon_bootinfo->mac_addr_base, 6); cvmx_sysinfo_get()->mac_addr_count = octeon_bootinfo->mac_addr_count; cvmx_sysinfo_get()->compact_flash_common_base_addr = octeon_bootinfo->compact_flash_common_base_addr; cvmx_sysinfo_get()->compact_flash_attribute_base_addr = octeon_bootinfo->compact_flash_attribute_base_addr; cvmx_sysinfo_get()->core_mask = octeon_bootinfo->core_mask; cvmx_sysinfo_get()->led_display_base_addr = octeon_bootinfo->led_display_base_addr; memcpy(cvmx_sysinfo_get()->board_serial_number, octeon_bootinfo->board_serial_number, sizeof cvmx_sysinfo_get()->board_serial_number); return (octeon_bootinfo); } static void octeon_boot_params_init(register_t ptr) { octeon_boot_descriptor_t *app_desc_ptr; cvmx_bootinfo_t *octeon_bootinfo; if (ptr == 0 || ptr >= MAX_APP_DESC_ADDR) { cvmx_safe_printf("app descriptor passed at invalid address %#jx\n", (uintmax_t)ptr); platform_reset(); } app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr; if (app_desc_ptr->desc_version < 6) { cvmx_safe_printf("Your boot code is too old to be supported.\n"); platform_reset(); } octeon_bootinfo = octeon_process_app_desc_ver_6(app_desc_ptr); if (octeon_bootinfo == NULL) { cvmx_safe_printf("Could not parse boot descriptor.\n"); platform_reset(); } if (cvmx_sysinfo_get()->led_display_base_addr != 0) { /* * Revision 1.x of the EBT3000 only supports 4 characters, but * other devices support 8. */ if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBT3000 && cvmx_sysinfo_get()->board_rev_major == 1) ebt3000_str_write("FBSD"); else ebt3000_str_write("FreeBSD!"); } if (cvmx_sysinfo_get()->phy_mem_desc_addr == (uint64_t)0) { cvmx_safe_printf("Your boot loader did not supply a memory descriptor.\n"); platform_reset(); } cvmx_bootmem_init(cvmx_sysinfo_get()->phy_mem_desc_addr); octeon_feature_init(); __cvmx_helper_cfg_init(); } /* impEND: This stuff should move back into the Cavium SDK */ -static void -boothowto_parse(const char *v) -{ - if ((v == NULL) || (*v != '-')) - return; - - while (*v != '\0') { - v++; - switch (*v) { - case 'a': boothowto |= RB_ASKNAME; break; - case 'C': boothowto |= RB_CDROM; break; - case 'd': boothowto |= RB_KDB; break; - case 'D': boothowto |= RB_MULTIPLE; break; - case 'm': boothowto |= RB_MUTE; break; - case 'g': boothowto |= RB_GDB; break; - case 'h': boothowto |= RB_SERIAL; break; - case 'p': boothowto |= RB_PAUSE; break; - case 'r': boothowto |= RB_DFLTROOT; break; - case 's': boothowto |= RB_SINGLE; break; - case 'v': boothowto |= RB_VERBOSE; break; - } - } -} - /* * The boot loader command line may specify kernel environment variables or * applicable boot flags of boot(8). */ static void octeon_init_kenv(register_t ptr) { int i; char *n; char *v; octeon_boot_descriptor_t *app_desc_ptr; app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr; memset(octeon_kenv, 0, sizeof(octeon_kenv)); init_static_kenv(octeon_kenv, sizeof(octeon_kenv)); for (i = 0; i < app_desc_ptr->argc; i++) { v = cvmx_phys_to_ptr(app_desc_ptr->argv[i]); if (v == NULL) continue; if (*v == '-') { - boothowto_parse(v); + boothowto |= boot_parse_arg(v); continue; } n = strsep(&v, "="); if (v == NULL) kern_setenv(n, "1"); else kern_setenv(n, v); } } Index: head/sys/mips/ingenic/jz4780_machdep.c =================================================================== --- head/sys/mips/ingenic/jz4780_machdep.c (revision 336244) +++ head/sys/mips/ingenic/jz4780_machdep.c (revision 336245) @@ -1,296 +1,253 @@ /*- * Copyright (c) 2009 Oleksandr Tymoshenko * Copyright (c) 2015 Alexander Kabaev * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_platform.h" #include #include #include #include #include #include #include #include #ifdef FDT #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include uint32_t * const led = (uint32_t *)0xb0010548; extern char edata[], end[]; static char boot1_env[4096]; void platform_cpu_init(void) { uint32_t reg; /* * Do not expect mbox interrups while writing * mbox */ reg = mips_rd_xburst_reim(); reg &= ~JZ_REIM_MIRQ0M; mips_wr_xburst_reim(reg); /* Clean mailboxes */ mips_wr_xburst_mbox0(0); mips_wr_xburst_mbox1(0); mips_wr_xburst_core_sts(~JZ_CORESTS_MIRQ0P); /* Unmask mbox interrupts */ reg |= JZ_REIM_MIRQ0M; mips_wr_xburst_reim(reg); } void platform_reset(void) { /* * For now, provoke a watchdog reset in about a second, so UART buffers * have a fighting chance to flush before we pull the plug */ writereg(JZ_TCU_BASE + JZ_WDOG_TCER, 0); /* disable watchdog */ writereg(JZ_TCU_BASE + JZ_WDOG_TCNT, 0); /* reset counter */ writereg(JZ_TCU_BASE + JZ_WDOG_TDR, 128); /* wait for ~1s */ writereg(JZ_TCU_BASE + JZ_WDOG_TCSR, TCSR_RTC_EN | TCSR_DIV_256); writereg(JZ_TCU_BASE + JZ_WDOG_TCER, TCER_ENABLE); /* fire! */ /* Wait for reset */ while (1) ; } static void mips_init(void) { int i; #ifdef FDT struct mem_region mr[FDT_MEM_REGIONS]; uint64_t val; int mr_cnt; int j; #endif for (i = 0; i < 10; i++) { phys_avail[i] = 0; } /* The minimal amount of memory Ingenic SoC can have. */ dump_avail[0] = phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); physmem = realmem = btoc(32 * 1024 * 1024); /* * X1000 mips cpu special. * TODO: do anyone know what is this ? */ __asm( "li $2, 0xa9000000 \n\t" "mtc0 $2, $5, 4 \n\t" "nop \n\t" ::"r"(2)); #ifdef FDT if (fdt_get_mem_regions(mr, &mr_cnt, &val) == 0) { physmem = realmem = btoc(val); KASSERT((phys_avail[0] >= mr[0].mr_start) && \ (phys_avail[0] < (mr[0].mr_start + mr[0].mr_size)), ("First region is not within FDT memory range")); /* Limit size of the first region */ phys_avail[1] = (mr[0].mr_start + MIN(mr[0].mr_size, ctob(realmem))); dump_avail[1] = phys_avail[1]; /* Add the rest of regions */ for (i = 1, j = 2; i < mr_cnt; i++, j+=2) { phys_avail[j] = mr[i].mr_start; phys_avail[j+1] = (mr[i].mr_start + mr[i].mr_size); dump_avail[j] = phys_avail[j]; dump_avail[j+1] = phys_avail[j+1]; } } #endif init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); led[0] = 0x8000; #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } -static void -_parse_bootarg(char *v) -{ - char *n; - - if (*v == '-') { - while (*v != '\0') { - v++; - switch (*v) { - case 'a': boothowto |= RB_ASKNAME; break; - /* Someone should simulate that ;-) */ - case 'C': boothowto |= RB_CDROM; break; - case 'd': boothowto |= RB_KDB; break; - case 'D': boothowto |= RB_MULTIPLE; break; - case 'm': boothowto |= RB_MUTE; break; - case 'g': boothowto |= RB_GDB; break; - case 'h': boothowto |= RB_SERIAL; break; - case 'p': boothowto |= RB_PAUSE; break; - case 'r': boothowto |= RB_DFLTROOT; break; - case 's': boothowto |= RB_SINGLE; break; - case 'v': boothowto |= RB_VERBOSE; break; - } - } - } else { - n = strsep(&v, "="); - if (v == NULL) - kern_setenv(n, "1"); - else - kern_setenv(n, v); - } -} - -static void -_parse_cmdline(int argc, char *argv[]) -{ - int i; - - for (i = 1; i < argc; i++) - _parse_bootarg(argv[i]); -} - #ifdef FDT -/* Parse cmd line args as env - copied from xlp_machdep. */ -/* XXX-BZ this should really be centrally provided for all (boot) code. */ static void _parse_bootargs(char *cmdline) { char *v; while ((v = strsep(&cmdline, " \n")) != NULL) { if (*v == '\0') continue; - _parse_bootarg(v); + boothowto |= boot_parse_arg(v); } } #endif void platform_start(__register_t a0, __register_t a1, __register_t a2 __unused, __register_t a3 __unused) { char **argv; int argc; vm_offset_t kernend; #ifdef FDT vm_offset_t dtbp; phandle_t chosen; char buf[2048]; /* early stack supposedly big enough */ #endif /* * clear the BSS and SBSS segments, this should be first call in * the function */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); /* Initialize pcpu stuff */ mips_pcpu0_init(); /* Something to hold kernel env until kmem is available */ init_static_kenv(boot1_env, sizeof(boot1_env)); #ifdef FDT /* * Find the dtb passed in by the boot loader (currently fictional). */ dtbp = (vm_offset_t)NULL; #if defined(FDT_DTB_STATIC) /* * In case the device tree blob was not retrieved (from metadata) try * to use the statically embedded one. */ if (dtbp == (vm_offset_t)NULL) dtbp = (vm_offset_t)&fdt_static_dtb; #else #error "Non-static FDT not supported on JZ4780" #endif if (OF_install(OFW_FDT, 0) == FALSE) while (1); if (OF_init((void *)dtbp) != 0) while (1); #endif cninit(); #ifdef FDT /* * Get bootargs from FDT if specified. */ chosen = OF_finddevice("/chosen"); if (OF_getprop(chosen, "bootargs", buf, sizeof(buf)) != -1) - _parse_bootargs(buf); + boothowto |= boot_parse_cmdline(buf); #endif /* Parse cmdline from U-Boot */ argc = a0; argv = (char **)a1; - _parse_cmdline(argc, argv); + boothowto |= boot_parse_cmdline(argc, argv); mips_init(); } Index: head/sys/mips/mediatek/mtk_machdep.c =================================================================== --- head/sys/mips/mediatek/mtk_machdep.c (revision 336244) +++ head/sys/mips/mediatek/mtk_machdep.c (revision 336245) @@ -1,345 +1,300 @@ /*- * Copyright (C) 2015-2016 by Stanislav Galabov. All rights reserved. * Copyright (C) 2010-2011 by Aleksandr Rybalko. All rights reserved. * Copyright (C) 2007 by Oleksandr Tymoshenko. 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. * * 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 OR HIS RELATIVES 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 MIND, 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. * */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "opt_platform.h" #include "opt_rt305x.h" #include #include extern int *edata; extern int *end; static char boot1_env[0x1000]; void platform_cpu_init() { /* Nothing special */ } static void mips_init(void) { struct mem_region mr[FDT_MEM_REGIONS]; uint64_t val; int i, j, mr_cnt; char *memsize; printf("entry: mips_init()\n"); bootverbose = 1; for (i = 0; i < 10; i++) phys_avail[i] = 0; dump_avail[0] = phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); /* * The most low memory MT7621 can have. Currently MT7621 is the chip * that supports the most memory, so that seems reasonable. */ realmem = btoc(448 * 1024 * 1024); if (fdt_get_mem_regions(mr, &mr_cnt, &val) == 0) { physmem = btoc(val); printf("RAM size: %ldMB (from FDT)\n", ctob(physmem) / (1024 * 1024)); KASSERT((phys_avail[0] >= mr[0].mr_start) && \ (phys_avail[0] < (mr[0].mr_start + mr[0].mr_size)), ("First region is not within FDT memory range")); /* Limit size of the first region */ phys_avail[1] = (mr[0].mr_start + MIN(mr[0].mr_size, ctob(realmem))); dump_avail[1] = phys_avail[1]; /* Add the rest of the regions */ for (i = 1, j = 2; i < mr_cnt; i++, j+=2) { phys_avail[j] = mr[i].mr_start; phys_avail[j+1] = (mr[i].mr_start + mr[i].mr_size); dump_avail[j] = phys_avail[j]; dump_avail[j+1] = phys_avail[j+1]; } } else { if ((memsize = kern_getenv("memsize")) != NULL) { physmem = btoc(strtol(memsize, NULL, 0) << 20); printf("RAM size: %ldMB (from memsize)\n", ctob(physmem) / (1024 * 1024)); } else { /* All else failed, assume 32MB */ physmem = btoc(32 * 1024 * 1024); printf("RAM size: %ldMB (assumed)\n", ctob(physmem) / (1024 * 1024)); } if (mtk_soc_get_socid() == MTK_SOC_RT2880) { /* RT2880 memory start is 88000000 */ dump_avail[1] = phys_avail[1] = ctob(physmem) + 0x08000000; } else if (ctob(physmem) < (448 * 1024 * 1024)) { /* * Anything up to 448MB is assumed to be directly * mappable as low memory... */ dump_avail[1] = phys_avail[1] = ctob(physmem); } else if (mtk_soc_get_socid() == MTK_SOC_MT7621) { /* * On MT7621 the low memory is limited to 448MB, the * rest is high memory, mapped at 0x20000000 */ phys_avail[1] = 448 * 1024 * 1024; phys_avail[2] = 0x20000000; phys_avail[3] = phys_avail[2] + ctob(physmem) - phys_avail[1]; dump_avail[1] = phys_avail[1] - phys_avail[0]; dump_avail[2] = phys_avail[2]; dump_avail[3] = phys_avail[3] - phys_avail[2]; } else { /* * We have > 448MB RAM and we're not MT7621? Currently * there is no such chip, so we'll just limit the RAM to * 32MB and let the user know... */ printf("Unknown chip, assuming 32MB RAM\n"); physmem = btoc(32 * 1024 * 1024); dump_avail[1] = phys_avail[1] = ctob(physmem); } } if (physmem < realmem) realmem = physmem; init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } -static void -_parse_bootarg(char *v) -{ - char *n; - - if (*v == '-') { - while (*v != '\0') { - v++; - switch (*v) { - case 'a': boothowto |= RB_ASKNAME; break; - /* Someone should simulate that ;-) */ - case 'C': boothowto |= RB_CDROM; break; - case 'd': boothowto |= RB_KDB; break; - case 'D': boothowto |= RB_MULTIPLE; break; - case 'm': boothowto |= RB_MUTE; break; - case 'g': boothowto |= RB_GDB; break; - case 'h': boothowto |= RB_SERIAL; break; - case 'p': boothowto |= RB_PAUSE; break; - case 'r': boothowto |= RB_DFLTROOT; break; - case 's': boothowto |= RB_SINGLE; break; - case 'v': boothowto |= RB_VERBOSE; break; - } - } - } else { - n = strsep(&v, "="); - if (v == NULL) - kern_setenv(n, "1"); - else - kern_setenv(n, v); - } -} - -/* Parse cmd line args as env - copied from xlp_machdep. */ -/* XXX-BZ this should really be centrally provided for all (boot) code. */ -static void -_parse_bootargs(char *cmdline) -{ - char *v; - - while ((v = strsep(&cmdline, " \n")) != NULL) { - if (*v == '\0') - continue; - _parse_bootarg(v); - } -} - void platform_reset(void) { mtk_soc_reset(); } void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { vm_offset_t kernend; int argc = a0, i;//, res; uint32_t timer_clk; char **argv = (char **)MIPS_PHYS_TO_KSEG0(a1); char **envp = (char **)MIPS_PHYS_TO_KSEG0(a2); void *dtbp; phandle_t chosen; char buf[2048]; /* clear the BSS and SBSS segments */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); /* Initialize pcpu stuff */ mips_pcpu0_init(); dtbp = &fdt_static_dtb; if (OF_install(OFW_FDT, 0) == FALSE) while (1); if (OF_init((void *)dtbp) != 0) while (1); mtk_soc_try_early_detect(); if ((timer_clk = mtk_soc_get_timerclk()) == 0) timer_clk = 1000000000; /* no such speed yet */ mips_timer_early_init(timer_clk); /* initialize console so that we have printf */ boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */ boothowto |= (RB_VERBOSE); cninit(); init_static_kenv(boot1_env, sizeof(boot1_env)); /* * Get bsdbootargs from FDT if specified. */ chosen = OF_finddevice("/chosen"); if (OF_getprop(chosen, "bsdbootargs", buf, sizeof(buf)) != -1) - _parse_bootargs(buf); + boothowto |= boot_parse_cmdline(buf); printf("FDT DTB at: 0x%08x\n", (uint32_t)dtbp); printf("CPU clock: %4dMHz\n", mtk_soc_get_cpuclk()/(1000*1000)); printf("Timer clock: %4dMHz\n", timer_clk/(1000*1000)); printf("UART clock: %4dMHz\n\n", mtk_soc_get_uartclk()/(1000*1000)); printf("U-Boot args (from %d args):\n", argc - 1); if (argc == 1) printf("\tNone\n"); for (i = 1; i < argc; i++) { char *n = "argv ", *arg; if (i > 99) break; if (argv[i]) { arg = (char *)(intptr_t)MIPS_PHYS_TO_KSEG0(argv[i]); printf("\targv[%d] = %s\n", i, arg); sprintf(n, "argv%d", i); kern_setenv(n, arg); } } printf("Environment:\n"); for (i = 0; envp[i] && MIPS_IS_VALID_PTR(envp[i]); i++) { char *n, *arg; arg = (char *)(intptr_t)MIPS_PHYS_TO_KSEG0(envp[i]); if (! MIPS_IS_VALID_PTR(arg)) continue; printf("\t%s\n", arg); n = strsep(&arg, "="); if (arg == NULL) kern_setenv(n, "1"); else kern_setenv(n, arg); } mips_init(); mips_timer_init_params(timer_clk, 0); } Index: head/sys/mips/nlm/xlp_machdep.c =================================================================== --- head/sys/mips/nlm/xlp_machdep.c (revision 336244) +++ head/sys/mips/nlm/xlp_machdep.c (revision 336245) @@ -1,743 +1,714 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 2003-2011 Netlogic Microsystems (Netlogic). 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. * * THIS SOFTWARE IS PROVIDED BY Netlogic Microsystems ``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 NETLOGIC OR CONTRIBUTORS 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. * * NETLOGIC_BSD */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include /* cinit() */ #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #endif /* 4KB static data aread to keep a copy of the bootload env until the dynamic kenv is setup */ char boot1_env[4096]; uint64_t xlp_cpu_frequency; uint64_t xlp_io_base = MIPS_PHYS_TO_DIRECT_UNCACHED(XLP_DEFAULT_IO_BASE); int xlp_ncores; int xlp_threads_per_core; uint32_t xlp_hw_thread_mask; int xlp_cpuid_to_hwtid[MAXCPU]; int xlp_hwtid_to_cpuid[MAXCPU]; uint64_t xlp_pic_base; static int xlp_mmuval; extern uint32_t _end; extern char XLPResetEntry[], XLPResetEntryEnd[]; static void xlp_setup_core(void) { uint64_t reg; reg = nlm_mfcr(LSU_DEFEATURE); /* Enable Unaligned and L2HPE */ reg |= (1 << 30) | (1 << 23); /* * Experimental : Enable SUE * Speculative Unmap Enable. Enable speculative L2 cache request for * unmapped access. */ reg |= (1ull << 31); /* Clear S1RCM - A0 errata */ reg &= ~0xeull; nlm_mtcr(LSU_DEFEATURE, reg); reg = nlm_mfcr(SCHED_DEFEATURE); /* Experimental: Disable BRU accepting ALU ops - A0 errata */ reg |= (1 << 24); nlm_mtcr(SCHED_DEFEATURE, reg); } static void xlp_setup_mmu(void) { uint32_t pagegrain; if (nlm_threadid() == 0) { nlm_setup_extended_pagemask(0); nlm_large_variable_tlb_en(1); nlm_extended_tlb_en(1); nlm_mmu_setup(0, 0, 0); } /* Enable no-read, no-exec, large-physical-address */ pagegrain = mips_rd_pagegrain(); pagegrain |= (1U << 31) | /* RIE */ (1 << 30) | /* XIE */ (1 << 29); /* ELPA */ mips_wr_pagegrain(pagegrain); } static void xlp_enable_blocks(void) { uint64_t sysbase; int i; for (i = 0; i < XLP_MAX_NODES; i++) { if (!nlm_dev_exists(XLP_IO_SYS_OFFSET(i))) continue; sysbase = nlm_get_sys_regbase(i); nlm_sys_enable_block(sysbase, DFS_DEVICE_RSA); } } static void xlp_parse_mmu_options(void) { uint64_t sysbase; uint32_t cpu_map = xlp_hw_thread_mask; uint32_t core0_thr_mask, core_thr_mask, cpu_rst_mask; int i, j, k; #ifdef SMP if (cpu_map == 0) cpu_map = 0xffffffff; #else /* Uniprocessor! */ if (cpu_map == 0) cpu_map = 0x1; else if (cpu_map != 0x1) { printf("WARNING: Starting uniprocessor kernel on cpumask [0x%lx]!\n" "WARNING: Other CPUs will be unused.\n", (u_long)cpu_map); cpu_map = 0x1; } #endif xlp_ncores = 1; core0_thr_mask = cpu_map & 0xf; switch (core0_thr_mask) { case 1: xlp_threads_per_core = 1; xlp_mmuval = 0; break; case 3: xlp_threads_per_core = 2; xlp_mmuval = 2; break; case 0xf: xlp_threads_per_core = 4; xlp_mmuval = 3; break; default: goto unsupp; } /* Try to find the enabled cores from SYS block */ sysbase = nlm_get_sys_regbase(0); cpu_rst_mask = nlm_read_sys_reg(sysbase, SYS_CPU_RESET) & 0xff; /* XLP 416 does not report this correctly, fix */ if (nlm_processor_id() == CHIP_PROCESSOR_ID_XLP_416) cpu_rst_mask = 0xe; /* Take out cores which do not exist on chip */ for (i = 1; i < XLP_MAX_CORES; i++) { if ((cpu_rst_mask & (1 << i)) == 0) cpu_map &= ~(0xfu << (4 * i)); } /* Verify other cores' CPU masks */ for (i = 1; i < XLP_MAX_CORES; i++) { core_thr_mask = (cpu_map >> (4 * i)) & 0xf; if (core_thr_mask == 0) continue; if (core_thr_mask != core0_thr_mask) goto unsupp; xlp_ncores++; } xlp_hw_thread_mask = cpu_map; /* setup hardware processor id to cpu id mapping */ for (i = 0; i< MAXCPU; i++) xlp_cpuid_to_hwtid[i] = xlp_hwtid_to_cpuid[i] = -1; for (i = 0, k = 0; i < XLP_MAX_CORES; i++) { if (((cpu_map >> (i * 4)) & 0xf) == 0) continue; for (j = 0; j < xlp_threads_per_core; j++) { xlp_cpuid_to_hwtid[k] = i * 4 + j; xlp_hwtid_to_cpuid[i * 4 + j] = k; k++; } } return; unsupp: printf("ERROR : Unsupported CPU mask [use 1,2 or 4 threads per core].\n" "\tcore0 thread mask [%lx], boot cpu mask [%lx].\n", (u_long)core0_thr_mask, (u_long)cpu_map); panic("Invalid CPU mask - halting.\n"); return; } -/* Parse cmd line args as env - copied from ar71xx */ -static void -xlp_parse_bootargs(char *cmdline) -{ - char *n, *v; - - while ((v = strsep(&cmdline, " \n")) != NULL) { - if (*v == '\0') - continue; - if (*v == '-') { - while (*v != '\0') { - v++; - switch (*v) { - case 'a': boothowto |= RB_ASKNAME; break; - case 'd': boothowto |= RB_KDB; break; - case 'g': boothowto |= RB_GDB; break; - case 's': boothowto |= RB_SINGLE; break; - case 'v': boothowto |= RB_VERBOSE; break; - } - } - } else { - n = strsep(&v, "="); - if (v == NULL) - kern_setenv(n, "1"); - else - kern_setenv(n, v); - } - } -} - #ifdef FDT static void xlp_bootargs_init(__register_t arg) { char buf[2048]; /* early stack is big enough */ void *dtbp; phandle_t chosen; ihandle_t mask; dtbp = (void *)(intptr_t)arg; #if defined(FDT_DTB_STATIC) /* * In case the device tree blob was not passed as argument try * to use the statically embedded one. */ if (dtbp == NULL) dtbp = &fdt_static_dtb; #endif if (OF_install(OFW_FDT, 0) == FALSE) while (1); if (OF_init((void *)dtbp) != 0) while (1); OF_interpret("perform-fixup", 0); chosen = OF_finddevice("/chosen"); if (OF_getprop(chosen, "cpumask", &mask, sizeof(mask)) != -1) { xlp_hw_thread_mask = mask; } if (OF_getprop(chosen, "bootargs", buf, sizeof(buf)) != -1) - xlp_parse_bootargs(buf); + boothowto |= boot_parse_cmdline(buf); } #else /* * arg is a pointer to the environment block, the format of the block is * a=xyz\0b=pqr\0\0 */ static void xlp_bootargs_init(__register_t arg) { char buf[2048]; /* early stack is big enough */ char *p, *v, *n; uint32_t mask; /* * provide backward compat for passing cpu mask as arg */ if (arg & 1) { xlp_hw_thread_mask = arg; return; } p = (void *)(intptr_t)arg; while (*p != '\0') { strlcpy(buf, p, sizeof(buf)); v = buf; n = strsep(&v, "="); if (v == NULL) kern_setenv(n, "1"); else kern_setenv(n, v); p += strlen(p) + 1; } /* CPU mask can be passed thru env */ if (getenv_uint("cpumask", &mask) != 0) xlp_hw_thread_mask = mask; /* command line argument */ v = kern_getenv("bootargs"); if (v != NULL) { strlcpy(buf, v, sizeof(buf)); - xlp_parse_bootargs(buf); + boothowto |= boot_parse_cmdline(buf); freeenv(v); } } #endif static void mips_init(void) { init_param1(); init_param2(physmem); mips_cpu_init(); cpuinfo.cache_coherent_dma = TRUE; pmap_bootstrap(); mips_proc0_init(); mutex_init(); #ifdef DDB kdb_init(); if (boothowto & RB_KDB) { kdb_enter("Boot flags requested debugger", NULL); } #endif } unsigned int platform_get_timecount(struct timecounter *tc __unused) { uint64_t count = nlm_pic_read_timer(xlp_pic_base, PIC_CLOCK_TIMER); return (unsigned int)~count; } static void xlp_pic_init(void) { struct timecounter pic_timecounter = { platform_get_timecount, /* get_timecount */ 0, /* no poll_pps */ ~0U, /* counter_mask */ XLP_IO_CLK, /* frequency */ "XLRPIC", /* name */ 2000, /* quality (adjusted in code) */ }; int i; int maxirt; xlp_pic_base = nlm_get_pic_regbase(0); /* TOOD: Add other nodes */ maxirt = nlm_read_reg(nlm_get_pic_pcibase(nlm_nodeid()), XLP_PCI_DEVINFO_REG0); printf("Initializing PIC...@%jx %d IRTs\n", (uintmax_t)xlp_pic_base, maxirt); /* Bind all PIC irqs to cpu 0 */ for (i = 0; i < maxirt; i++) nlm_pic_write_irt(xlp_pic_base, i, 0, 0, 1, 0, 1, 0, 0x1); nlm_pic_set_timer(xlp_pic_base, PIC_CLOCK_TIMER, ~0ULL, 0, 0); platform_timecounter = &pic_timecounter; } #if defined(__mips_n32) || defined(__mips_n64) /* PHYSADDR_64_BIT */ #ifdef XLP_SIM #define XLP_MEM_LIM 0x200000000ULL #else #define XLP_MEM_LIM 0x10000000000ULL #endif #else #define XLP_MEM_LIM 0xfffff000UL #endif static vm_paddr_t xlp_mem_excl[] = { 0, 0, /* for kernel image region, see xlp_mem_init */ 0x0c000000, 0x14000000, /* uboot area, cms queue and other stuff */ 0x1fc00000, 0x1fd00000, /* reset vec */ 0x1e000000, 0x1e200000, /* poe buffers */ }; static int mem_exclude_add(vm_paddr_t *avail, vm_paddr_t mstart, vm_paddr_t mend) { int i, pos; pos = 0; for (i = 0; i < nitems(xlp_mem_excl); i += 2) { if (mstart > xlp_mem_excl[i + 1]) continue; if (mstart < xlp_mem_excl[i]) { avail[pos++] = mstart; if (mend < xlp_mem_excl[i]) avail[pos++] = mend; else avail[pos++] = xlp_mem_excl[i]; } mstart = xlp_mem_excl[i + 1]; if (mend <= mstart) break; } if (mstart < mend) { avail[pos++] = mstart; avail[pos++] = mend; } return (pos); } static void xlp_mem_init(void) { vm_paddr_t physsz, tmp; uint64_t bridgebase, base, lim, val; int i, j, k, n; /* update kernel image area in exclude regions */ tmp = (vm_paddr_t)MIPS_KSEG0_TO_PHYS(&_end); tmp = round_page(tmp) + 0x20000; /* round up */ xlp_mem_excl[1] = tmp; printf("Memory (from DRAM BARs):\n"); bridgebase = nlm_get_bridge_regbase(0); /* TODO: Add other nodes */ physsz = 0; for (i = 0, j = 0; i < 8; i++) { val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_BAR(i)); val = (val >> 12) & 0xfffff; base = val << 20; val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_LIMIT(i)); val = (val >> 12) & 0xfffff; if (val == 0) /* BAR not enabled */ continue; lim = (val + 1) << 20; printf(" BAR %d: %#jx - %#jx : ", i, (intmax_t)base, (intmax_t)lim); if (lim <= base) { printf("\tskipped - malformed %#jx -> %#jx\n", (intmax_t)base, (intmax_t)lim); continue; } else if (base >= XLP_MEM_LIM) { printf(" skipped - outside usable limit %#jx.\n", (intmax_t)XLP_MEM_LIM); continue; } else if (lim >= XLP_MEM_LIM) { lim = XLP_MEM_LIM; printf(" truncated to %#jx.\n", (intmax_t)XLP_MEM_LIM); } else printf(" usable\n"); /* exclude unusable regions from BAR and add rest */ n = mem_exclude_add(&phys_avail[j], base, lim); for (k = j; k < j + n; k += 2) { physsz += phys_avail[k + 1] - phys_avail[k]; printf("\tMem[%d]: %#jx - %#jx\n", k/2, (intmax_t)phys_avail[k], (intmax_t)phys_avail[k+1]); } j = k; } /* setup final entry with 0 */ phys_avail[j] = phys_avail[j + 1] = 0; /* copy phys_avail to dump_avail */ for (i = 0; i <= j + 1; i++) dump_avail[i] = phys_avail[i]; realmem = physmem = btoc(physsz); } void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { /* Initialize pcpu stuff */ mips_pcpu0_init(); /* initialize console so that we have printf */ boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */ init_static_kenv(boot1_env, sizeof(boot1_env)); xlp_bootargs_init(a0); /* clockrate used by delay, so initialize it here */ xlp_cpu_frequency = xlp_get_cpu_frequency(0, 0); cpu_clock = xlp_cpu_frequency / 1000000; mips_timer_early_init(xlp_cpu_frequency); /* Init console please */ cninit(); /* Early core init and fixes for errata */ xlp_setup_core(); xlp_parse_mmu_options(); xlp_mem_init(); bcopy(XLPResetEntry, (void *)MIPS_RESET_EXC_VEC, XLPResetEntryEnd - XLPResetEntry); #ifdef SMP /* * We will enable the other threads in core 0 here * so that the TLB and cache info is correct when * mips_init runs */ xlp_enable_threads(xlp_mmuval); #endif /* setup for the startup core */ xlp_setup_mmu(); xlp_enable_blocks(); /* Read/Guess/setup board information */ nlm_board_info_setup(); /* MIPS generic init */ mips_init(); /* * XLP specific post initialization * initialize other on chip stuff */ xlp_pic_init(); mips_timer_init_params(xlp_cpu_frequency, 0); } void platform_cpu_init() { } void platform_reset(void) { uint64_t sysbase = nlm_get_sys_regbase(0); nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1); for( ; ; ) __asm __volatile("wait"); } #ifdef SMP /* * XLP threads are started simultaneously when we enable threads, this will * ensure that the threads are blocked in platform_init_ap, until they are * ready to proceed to smp_init_secondary() */ static volatile int thr_unblock[4]; int platform_start_ap(int cpuid) { uint32_t coremask, val; uint64_t sysbase = nlm_get_sys_regbase(0); int hwtid = xlp_cpuid_to_hwtid[cpuid]; int core, thr; core = hwtid / 4; thr = hwtid % 4; if (thr == 0) { /* First thread in core, do core wake up */ coremask = 1u << core; /* Enable core clock */ val = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL); val &= ~coremask; nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, val); /* Remove CPU Reset */ val = nlm_read_sys_reg(sysbase, SYS_CPU_RESET); val &= ~coremask & 0xff; nlm_write_sys_reg(sysbase, SYS_CPU_RESET, val); if (bootverbose) printf("Waking up core %d ...", core); /* Poll for CPU to mark itself coherent */ do { val = nlm_read_sys_reg(sysbase, SYS_CPU_NONCOHERENT_MODE); } while ((val & coremask) != 0); if (bootverbose) printf("Done\n"); } else { /* otherwise release the threads stuck in platform_init_ap */ thr_unblock[thr] = 1; } return (0); } void platform_init_ap(int cpuid) { uint32_t stat; int thr; /* The first thread has to setup the MMU and enable other threads */ thr = nlm_threadid(); if (thr == 0) { xlp_setup_core(); xlp_enable_threads(xlp_mmuval); } else { /* * FIXME busy wait here eats too many cycles, especially * in the core 0 while bootup */ while (thr_unblock[thr] == 0) __asm__ __volatile__ ("nop;nop;nop;nop"); thr_unblock[thr] = 0; } xlp_setup_mmu(); stat = mips_rd_status(); KASSERT((stat & MIPS_SR_INT_IE) == 0, ("Interrupts enabled in %s!", __func__)); stat |= MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT; mips_wr_status(stat); nlm_write_c0_eimr(0ull); xlp_enable_irq(IRQ_IPI); xlp_enable_irq(IRQ_TIMER); xlp_enable_irq(IRQ_MSGRING); return; } int platform_ipi_hardintr_num(void) { return (IRQ_IPI); } int platform_ipi_softintr_num(void) { return (-1); } void platform_ipi_send(int cpuid) { nlm_pic_send_ipi(xlp_pic_base, xlp_cpuid_to_hwtid[cpuid], platform_ipi_hardintr_num(), 0); } void platform_ipi_clear(void) { } int platform_processor_id(void) { return (xlp_hwtid_to_cpuid[nlm_cpuid()]); } void platform_cpu_mask(cpuset_t *mask) { int i, s; CPU_ZERO(mask); s = xlp_ncores * xlp_threads_per_core; for (i = 0; i < s; i++) CPU_SET(i, mask); } struct cpu_group * platform_smp_topo() { return (smp_topo_2level(CG_SHARE_L2, xlp_ncores, CG_SHARE_L1, xlp_threads_per_core, CG_FLAG_THREAD)); } #endif