ofw_machdep.c revision 160714
11590Srgrimes/*- 21590Srgrimes * Copyright (C) 1996 Wolfgang Solfrank. 31590Srgrimes * Copyright (C) 1996 TooLs GmbH. 41590Srgrimes * All rights reserved. 51590Srgrimes * 61590Srgrimes * Redistribution and use in source and binary forms, with or without 71590Srgrimes * modification, are permitted provided that the following conditions 81590Srgrimes * are met: 91590Srgrimes * 1. Redistributions of source code must retain the above copyright 101590Srgrimes * notice, this list of conditions and the following disclaimer. 111590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer in the 131590Srgrimes * documentation and/or other materials provided with the distribution. 141590Srgrimes * 3. All advertising materials mentioning features or use of this software 151590Srgrimes * must display the following acknowledgement: 161590Srgrimes * This product includes software developed by TooLs GmbH. 171590Srgrimes * 4. The name of TooLs GmbH may not be used to endorse or promote products 181590Srgrimes * derived from this software without specific prior written permission. 191590Srgrimes * 201590Srgrimes * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 211590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 221590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 231590Srgrimes * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 241590Srgrimes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 251590Srgrimes * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 261590Srgrimes * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 271590Srgrimes * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 281590Srgrimes * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 291590Srgrimes * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 301590Srgrimes * 311590Srgrimes * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#include <sys/cdefs.h> 3541568Sarchie__FBSDID("$FreeBSD: head/sys/powerpc/aim/ofw_machdep.c 160714 2006-07-26 17:12:54Z marcel $"); 361590Srgrimes 371590Srgrimes#include <sys/param.h> 3887241Smarkm#include <sys/bus.h> 391590Srgrimes#include <sys/systm.h> 4087628Sdwmalone#include <sys/conf.h> 411590Srgrimes#include <sys/disk.h> 4287628Sdwmalone#include <sys/fcntl.h> 4387241Smarkm#include <sys/malloc.h> 4487628Sdwmalone#include <sys/stat.h> 451590Srgrimes 4687628Sdwmalone#include <net/ethernet.h> 4787628Sdwmalone 4887628Sdwmalone#include <dev/ofw/openfirm.h> 491590Srgrimes 501590Srgrimes#include <vm/vm.h> 511590Srgrimes#include <vm/vm_param.h> 521590Srgrimes#include <vm/vm_page.h> 531590Srgrimes 541590Srgrimes#include <machine/bus.h> 551590Srgrimes#include <machine/md_var.h> 561590Srgrimes#include <machine/powerpc.h> 571590Srgrimes#include <machine/ofw_machdep.h> 581590Srgrimes#include <powerpc/ofw/ofw_pci.h> 591590Srgrimes 601590Srgrimes#define OFMEM_REGIONS 32 6163157Sbrianstatic struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3]; 621590Srgrimesstatic struct mem_region OFfree[OFMEM_REGIONS + 3]; 631590Srgrimes 641590Srgrimesextern register_t ofmsr[5]; 651590Srgrimesextern struct pcpu __pcpu[MAXCPU]; 661590Srgrimesextern struct pmap ofw_pmap; 671590Srgrimesstatic int (*ofwcall)(void *); 681590Srgrimes 691590Srgrimes/* 701590Srgrimes * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 711590Srgrimes */ 721590Srgrimesregister_t ofw_sprg0_save; 7386099Sdwmalone 741590Srgrimesstatic __inline void 7563157Sbrianofw_sprg_prepare(void) 761590Srgrimes{ 771590Srgrimes /* 781590Srgrimes * Assume that interrupt are disabled at this point, or 791590Srgrimes * SPRG1-3 could be trashed 801590Srgrimes */ 811590Srgrimes __asm __volatile("mfsprg0 %0\n\t" 8263157Sbrian "mtsprg0 %1\n\t" 831590Srgrimes "mtsprg1 %2\n\t" 8460583Sphk "mtsprg2 %3\n\t" 8560583Sphk "mtsprg3 %4\n\t" 8660583Sphk : "=&r"(ofw_sprg0_save) 8760583Sphk : "r"(ofmsr[1]), 8863157Sbrian "r"(ofmsr[2]), 8963157Sbrian "r"(ofmsr[3]), 9063157Sbrian "r"(ofmsr[4])); 911590Srgrimes} 921590Srgrimes 931590Srgrimesstatic __inline void 941590Srgrimesofw_sprg_restore(void) 951590Srgrimes{ 961590Srgrimes /* 971590Srgrimes * Note that SPRG1-3 contents are irrelevant. They are scratch 981590Srgrimes * registers used in the early portion of trap handling when 991590Srgrimes * interrupts are disabled. 1001590Srgrimes * 1011590Srgrimes * PCPU data cannot be used until this routine is called ! 1021590Srgrimes */ 10363157Sbrian __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 1041590Srgrimes} 1051590Srgrimes 1061590Srgrimes/* 1071590Srgrimes * Memory region utilities: determine if two regions overlap, 1081590Srgrimes * and merge two overlapping regions into one 1091590Srgrimes */ 1101590Srgrimesstatic int 1111590Srgrimesmemr_overlap(struct mem_region *r1, struct mem_region *r2) 1121590Srgrimes{ 1131590Srgrimes if ((r1->mr_start + r1->mr_size) < r2->mr_start || 1141590Srgrimes (r2->mr_start + r2->mr_size) < r1->mr_start) 1152149Sjkh return (FALSE); 1162149Sjkh 1172149Sjkh return (TRUE); 1182149Sjkh} 1192149Sjkh 1202149Sjkhstatic void 1211590Srgrimesmemr_merge(struct mem_region *from, struct mem_region *to) 1221590Srgrimes{ 1231590Srgrimes int end; 1241590Srgrimes end = imax(to->mr_start + to->mr_size, from->mr_start + from->mr_size); 1251590Srgrimes to->mr_start = imin(from->mr_start, to->mr_start); 1261590Srgrimes to->mr_size = end - to->mr_start; 1271590Srgrimes} 1281590Srgrimes 1292149Sjkh/* 1302149Sjkh * This is called during powerpc_init, before the system is really initialized. 1312149Sjkh * It shall provide the total and the available regions of RAM. 1322149Sjkh * Both lists must have a zero-size entry as terminator. 1332149Sjkh * The available regions need not take the kernel into account, but needs 1342149Sjkh * to provide space for two additional entry beyond the terminating one. 1351590Srgrimes */ 13628421Sjlemonvoid 13728421Sjlemonmem_regions(struct mem_region **memp, int *memsz, 1381590Srgrimes struct mem_region **availp, int *availsz) 1391590Srgrimes{ 1402149Sjkh int phandle; 1412149Sjkh int asz, msz, fsz; 1422149Sjkh int i, j; 1432149Sjkh int still_merging; 1442149Sjkh 1452149Sjkh /* 1461590Srgrimes * Get memory. 1471590Srgrimes */ 1481590Srgrimes if ((phandle = OF_finddevice("/memory")) == -1 1492149Sjkh || (msz = OF_getprop(phandle, "reg", 1502149Sjkh OFmem, sizeof OFmem[0] * OFMEM_REGIONS)) 1512149Sjkh <= 0 1522149Sjkh || (asz = OF_getprop(phandle, "available", 1532149Sjkh OFavail, sizeof OFavail[0] * OFMEM_REGIONS)) 1542149Sjkh <= 0) 1551590Srgrimes panic("no memory?"); 1561590Srgrimes *memp = OFmem; 1571590Srgrimes *memsz = msz / sizeof(struct mem_region); 1581590Srgrimes 1591590Srgrimes /* 1601590Srgrimes * OFavail may have overlapping regions - collapse these 1611590Srgrimes * and copy out remaining regions to OFfree 16263843Ssheldonh */ 16363157Sbrian asz /= sizeof(struct mem_region); 16463157Sbrian do { 16563157Sbrian still_merging = FALSE; 16663157Sbrian for (i = 0; i < asz; i++) { 16763157Sbrian if (OFavail[i].mr_size == 0) 16863157Sbrian continue; 1691590Srgrimes for (j = i+1; j < asz; j++) { 1701590Srgrimes if (OFavail[j].mr_size == 0) 17163843Ssheldonh continue; 1721590Srgrimes if (memr_overlap(&OFavail[j], &OFavail[i])) { 1731590Srgrimes memr_merge(&OFavail[j], &OFavail[i]); 1741590Srgrimes /* mark inactive */ 1751590Srgrimes OFavail[j].mr_size = 0; 1761590Srgrimes still_merging = TRUE; 1771590Srgrimes } 1781590Srgrimes } 1791590Srgrimes } 18063157Sbrian } while (still_merging == TRUE); 1811590Srgrimes 1821590Srgrimes /* evict inactive ranges */ 183 for (i = 0, fsz = 0; i < asz; i++) { 184 if (OFavail[i].mr_size != 0) { 185 OFfree[fsz] = OFavail[i]; 186 fsz++; 187 } 188 } 189 190 *availp = OFfree; 191 *availsz = fsz; 192} 193 194void 195set_openfirm_callback(int (*openfirm)(void *)) 196{ 197 198 ofwcall = openfirm; 199} 200 201int 202openfirmware(void *args) 203{ 204 long oldmsr; 205 int result; 206 u_int srsave[16]; 207 u_int i; 208 209 __asm __volatile( "\t" 210 "sync\n\t" 211 "mfmsr %0\n\t" 212 "mtmsr %1\n\t" 213 "isync\n" 214 : "=r" (oldmsr) 215 : "r" (ofmsr[0]) 216 ); 217 218 ofw_sprg_prepare(); 219 220 if (pmap_bootstrapped) { 221 /* 222 * Swap the kernel's address space with Open Firmware's 223 */ 224 for (i = 0; i < 16; i++) { 225 srsave[i] = mfsrin(i << ADDR_SR_SHFT); 226 mtsrin(i << ADDR_SR_SHFT, ofw_pmap.pm_sr[i]); 227 } 228 229 /* 230 * Clear battable[] translations 231 */ 232 __asm __volatile("mtdbatu 2, %0\n" 233 "mtdbatu 3, %0" : : "r" (0)); 234 isync(); 235 } 236 237 result = ofwcall(args); 238 239 if (pmap_bootstrapped) { 240 /* 241 * Restore the kernel's addr space. The isync() doesn;t 242 * work outside the loop unless mtsrin() is open-coded 243 * in an asm statement :( 244 */ 245 for (i = 0; i < 16; i++) { 246 mtsrin(i << ADDR_SR_SHFT, srsave[i]); 247 isync(); 248 } 249 } 250 251 ofw_sprg_restore(); 252 253 __asm( "\t" 254 "mtmsr %0\n\t" 255 "isync\n" 256 : : "r" (oldmsr) 257 ); 258 259 return (result); 260} 261 262void 263OF_halt() 264{ 265 int retval; /* dummy, this may not be needed */ 266 267 OF_interpret("shut-down", 1, &retval); 268 for (;;); /* just in case */ 269} 270 271void 272OF_reboot() 273{ 274 int retval; /* dummy, this may not be needed */ 275 276 OF_interpret("reset-all", 1, &retval); 277 for (;;); /* just in case */ 278} 279 280void 281OF_getetheraddr(device_t dev, u_char *addr) 282{ 283 phandle_t node; 284 285 node = ofw_pci_find_node(dev); 286 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 287} 288 289/* 290 * Return the physical address and the bus space to use for a node 291 * referenced by its package handle and the index of the register bank 292 * to decode. Intended to be used by console drivers in early boot only. 293 * Works by mapping the address of the node's bank given in the address 294 * space of its parent upward in the device tree at each bridge along the 295 * path. 296 */ 297int 298OF_decode_addr(phandle_t node, int bank, bus_space_tag_t *tag, 299 bus_space_handle_t *handle) 300{ 301 302 return (ENXIO); 303} 304 305int 306mem_valid(vm_offset_t addr, int len) 307{ 308 int i; 309 310 for (i = 0; i < OFMEM_REGIONS; i++) 311 if ((addr >= OFmem[i].mr_start) 312 && (addr + len < OFmem[i].mr_start + OFmem[i].mr_size)) 313 return (0); 314 315 return (EFAULT); 316} 317