/* $NetBSD: ofw_machdep.c,v 1.25 2014/02/28 05:44:39 matt Exp $ */ /* * Copyright (C) 1996 Wolfgang Solfrank. * Copyright (C) 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. */ #include __KERNEL_RCSID(0, "$NetBSD: ofw_machdep.c,v 1.25 2014/02/28 05:44:39 matt Exp $"); #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG #define DPRINTF aprint_error #else #define DPRINTF while(0) printf #endif #define OFMEM_REGIONS 32 static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3]; /* * This is called during initppc, before the system is really initialized. * It shall provide the total and the available regions of RAM. * Both lists must have a zero-size entry as terminator. * The available regions need not take the kernel into account, but needs * to provide space for two additional entry beyond the terminating one. */ void mem_regions(struct mem_region **memp, struct mem_region **availp) { const char *macrisc[] = {"MacRISC", "MacRISC2", "MacRISC4", NULL}; int hroot, hmem, i, cnt, memcnt, regcnt, acells, scells; int numregs; uint32_t regs[OFMEM_REGIONS * 4]; /* 2 values + 2 for 64bit */ DPRINTF("calling mem_regions\n"); /* determine acell size */ if ((hroot = OF_finddevice("/")) == -1) goto error; cnt = OF_getprop(hroot, "#address-cells", &acells, sizeof(int)); if (cnt <= 0) acells = 1; /* determine scell size */ cnt = OF_getprop(hroot, "#size-cells", &scells, sizeof(int)); if (cnt <= 0) scells = 1; /* Get memory */ memset(regs, 0, sizeof(regs)); if ((hmem = OF_finddevice("/memory")) == -1) goto error; regcnt = OF_getprop(hmem, "reg", regs, sizeof(regs[0]) * OFMEM_REGIONS * 4); if (regcnt <= 0) goto error; /* how many mem regions did we get? */ numregs = regcnt / (sizeof(uint32_t) * (acells + scells)); DPRINTF("regcnt=%d num=%d acell=%d scell=%d\n", regcnt, numregs, acells, scells); /* move the data into OFmem */ memset(OFmem, 0, sizeof(OFmem)); for (i = 0, memcnt = 0; i < numregs; i++) { uint64_t addr, size; if (acells > 1) memcpy(&addr, ®s[i * (acells + scells)], sizeof(int32_t) * acells); else addr = regs[i * (acells + scells)]; if (scells > 1) memcpy(&size, ®s[i * (acells + scells) + acells], sizeof(int32_t) * scells); else size = regs[i * (acells + scells) + acells]; /* skip entry of 0 size */ if (size == 0) continue; #ifndef _LP64 if (addr > 0xFFFFFFFF || size > 0xFFFFFFFF || (addr + size) > 0xFFFFFFFF) { aprint_error("Base addr of %llx or size of %llx too" " large for 32 bit OS. Skipping.", addr, size); continue; } #endif OFmem[memcnt].start = addr; OFmem[memcnt].size = size; aprint_normal("mem region %d start=%"PRIx64" size=%"PRIx64"\n", memcnt, addr, size); memcnt++; } DPRINTF("available\n"); /* now do the same thing again, for the available counts */ memset(regs, 0, sizeof(regs)); regcnt = OF_getprop(hmem, "available", regs, sizeof(regs[0]) * OFMEM_REGIONS * 4); if (regcnt <= 0) goto error; DPRINTF("%08x %08x %08x %08x\n", regs[0], regs[1], regs[2], regs[3]); /* * according to comments in FreeBSD all Apple OF has 32bit values in * "available", no matter what the cell sizes are */ if (of_compatible(hroot, macrisc) != -1) { DPRINTF("this appears to be a mac...\n"); acells = 1; scells = 1; } /* how many mem regions did we get? */ numregs = regcnt / (sizeof(uint32_t) * (acells + scells)); DPRINTF("regcnt=%d num=%d acell=%d scell=%d\n", regcnt, numregs, acells, scells); DPRINTF("to OF_avail\n"); /* move the data into OFavail */ memset(OFavail, 0, sizeof(OFavail)); for (i = 0, cnt = 0; i < numregs; i++) { uint64_t addr, size; DPRINTF("%d\n", i); if (acells > 1) memcpy(&addr, ®s[i * (acells + scells)], sizeof(int32_t) * acells); else addr = regs[i * (acells + scells)]; if (scells > 1) memcpy(&size, ®s[i * (acells + scells) + acells], sizeof(int32_t) * scells); else size = regs[i * (acells + scells) + acells]; /* skip entry of 0 size */ if (size == 0) continue; #ifndef _LP64 if (addr > 0xFFFFFFFF || size > 0xFFFFFFFF || (addr + size) > 0xFFFFFFFF) { aprint_verbose("Base addr of %llx or size of %llx too" " large for 32 bit OS. Skipping.", addr, size); continue; } #endif OFavail[cnt].start = addr; OFavail[cnt].size = size; aprint_normal("avail region %d start=%#"PRIx64" size=%#"PRIx64"\n", cnt, addr, size); cnt++; } if (strncmp(model_name, "Pegasos", 7) == 0) { /* * Some versions of SmartFirmware, only recognize the first * 256MB segment as available. Work around it and add an * extra entry to OFavail[] to account for this. */ #define AVAIL_THRESH (0x10000000-1) if (((OFavail[cnt-1].start + OFavail[cnt-1].size + AVAIL_THRESH) & ~AVAIL_THRESH) < (OFmem[memcnt-1].start + OFmem[memcnt-1].size)) { OFavail[cnt].start = (OFavail[cnt-1].start + OFavail[cnt-1].size + AVAIL_THRESH) & ~AVAIL_THRESH; OFavail[cnt].size = OFmem[memcnt-1].size - OFavail[cnt].start; aprint_normal("WARNING: add memory segment %lx - %lx," "\nWARNING: which was not recognized by " "the Firmware.\n", (unsigned long)OFavail[cnt].start, (unsigned long)OFavail[cnt].start + OFavail[cnt].size); cnt++; } } *memp = OFmem; *availp = OFavail; return; error: #if defined (MAMBO) printf("no memory, assuming 512MB\n"); OFmem[0].start = 0x0; OFmem[0].size = 0x20000000; OFavail[0].start = 0x3000; OFavail[0].size = 0x20000000 - 0x3000; *memp = OFmem; *availp = OFavail; #else panic("no memory?"); #endif return; } void ppc_exit(void) { OF_exit(); } void ppc_boot(char *str) { OF_boot(str); }