machdep.c revision 1.110
11.110Smatt/* $NetBSD: machdep.c,v 1.110 2010/02/25 23:33:45 matt Exp $ */ 21.96Sgarbled/*- 31.96Sgarbled * Copyright (c) 2007 The NetBSD Foundation, Inc. 41.1Sws * All rights reserved. 51.1Sws * 61.96Sgarbled * This code is derived from software contributed to The NetBSD Foundation 71.96Sgarbled * by Tim Rightnour 81.96Sgarbled * 91.1Sws * Redistribution and use in source and binary forms, with or without 101.1Sws * modification, are permitted provided that the following conditions 111.1Sws * are met: 121.1Sws * 1. Redistributions of source code must retain the above copyright 131.1Sws * notice, this list of conditions and the following disclaimer. 141.1Sws * 2. Redistributions in binary form must reproduce the above copyright 151.1Sws * notice, this list of conditions and the following disclaimer in the 161.1Sws * documentation and/or other materials provided with the distribution. 171.1Sws * 181.96Sgarbled * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 191.96Sgarbled * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 201.96Sgarbled * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 211.96Sgarbled * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 221.96Sgarbled * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 231.96Sgarbled * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 241.96Sgarbled * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 251.96Sgarbled * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 261.96Sgarbled * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 271.96Sgarbled * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 281.96Sgarbled * POSSIBILITY OF SUCH DAMAGE. 291.1Sws */ 301.86Slukem 311.86Slukem#include <sys/cdefs.h> 321.110Smatt__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.110 2010/02/25 23:33:45 matt Exp $"); 331.1Sws 341.1Sws#include <sys/param.h> 351.107Sdyoung#include <sys/systm.h> 361.1Sws#include <sys/buf.h> 371.93Sgarbled#include <sys/boot_flag.h> 381.1Sws#include <sys/mount.h> 391.43Sthorpej#include <sys/kernel.h> 401.107Sdyoung#include <sys/device.h> 411.1Sws 421.19Ssakamoto#include <uvm/uvm_extern.h> 431.19Ssakamoto 441.70Sthorpej#include <dev/ofw/openfirm.h> 451.93Sgarbled#include <dev/cons.h> 461.70Sthorpej 471.68Smatt#include <machine/autoconf.h> 481.1Sws#include <machine/pmap.h> 491.1Sws#include <machine/powerpc.h> 501.1Sws#include <machine/trap.h> 511.93Sgarbled#include <machine/bus.h> 521.93Sgarbled#include <machine/isa_machdep.h> 531.54Sthorpej 541.110Smatt#include <powerpc/spr.h> 551.110Smatt#include <powerpc/oea/spr.h> 561.87Smatt#include <powerpc/oea/bat.h> 571.93Sgarbled#include <powerpc/ofw_cons.h> 581.102Sgarbled#include <powerpc/rtas.h> 591.71Sthorpej 601.97Sgarbled#include "com.h" 611.97Sgarbled#if (NCOM > 0) 621.97Sgarbled#include <sys/termios.h> 631.97Sgarbled#include <dev/ic/comreg.h> 641.97Sgarbled#include <dev/ic/comvar.h> 651.97Sgarbled#endif 661.109Sphx#include "rtas.h" 671.97Sgarbled 681.93Sgarbledstruct pmap ofw_pmap; 691.78Schschar bootpath[256]; 701.1Sws 711.93Sgarbledvoid ofwppc_batinit(void); 721.104Sgarbledvoid ofppc_bootstrap_console(void); 731.77Smatt 741.99Sgarbledextern u_int l2cr_config; 751.108Sphx#if (NRTAS > 0) 761.103Sgarbledextern int machine_has_rtas; 771.108Sphx#endif 781.99Sgarbled 791.105Sgarbledstruct model_data modeldata; 801.105Sgarbled 811.1Swsvoid 821.93Sgarbledinitppc(u_int startkernel, u_int endkernel, char *args) 831.1Sws{ 841.93Sgarbled ofwoea_initppc(startkernel, endkernel, args); 851.1Sws} 861.1Sws 871.98Sgarbled/* perform model-specific actions at initppc() */ 881.98Sgarbledvoid 891.98Sgarbledmodel_init(void) 901.98Sgarbled{ 911.105Sgarbled int qhandle, phandle, j; 921.105Sgarbled 931.105Sgarbled memset(&modeldata, 0, sizeof(struct model_data)); 941.105Sgarbled /* provide sane defaults */ 951.105Sgarbled for (j=0; j < MAX_PCI_BUSSES; j++) { 961.105Sgarbled modeldata.pciiodata[j].start = 0x00008000; 971.105Sgarbled modeldata.pciiodata[j].limit = 0x0000ffff; 981.105Sgarbled } 991.105Sgarbled modeldata.ranges_offset = 1; 1001.105Sgarbled 1011.105Sgarbled if (strncmp(model_name, "FirePower,", 10) == 0) { 1021.105Sgarbled modeldata.ranges_offset = 0; 1031.105Sgarbled } 1041.105Sgarbled if (strcmp(model_name, "MOT,PowerStack_II_Pro4000") == 0) { 1051.105Sgarbled modeldata.ranges_offset = 0; 1061.105Sgarbled } 1071.105Sgarbled 1081.105Sgarbled /* 7044-270 and 7044-170 */ 1091.105Sgarbled if (strncmp(model_name, "IBM,7044", 8) == 0) { 1101.105Sgarbled for (j=0; j < MAX_PCI_BUSSES; j++) { 1111.105Sgarbled modeldata.pciiodata[j].start = 0x00fff000; 1121.105Sgarbled modeldata.pciiodata[j].limit = 0x00ffffff; 1131.105Sgarbled } 1141.105Sgarbled } 1151.98Sgarbled 1161.98Sgarbled /* Pegasos1, Pegasos2 */ 1171.98Sgarbled if (strncmp(model_name, "Pegasos", 7) == 0) { 1181.98Sgarbled static uint16_t modew[] = { 640, 800, 1024, 1280, 0 }; 1191.98Sgarbled static uint16_t modeh[] = { 480, 600, 768, 1024, 0 }; 1201.98Sgarbled uint32_t width, height, mode, fbaddr; 1211.98Sgarbled char buf[32]; 1221.98Sgarbled int i; 1231.98Sgarbled 1241.105Sgarbled modeldata.ranges_offset = 1; 1251.105Sgarbled modeldata.pciiodata[0].start = 0x00001400; 1261.105Sgarbled modeldata.pciiodata[0].limit = 0x0000ffff; 1271.105Sgarbled 1281.99Sgarbled /* the pegasos doesn't bother to set the L2 cache up*/ 1291.99Sgarbled l2cr_config = L2CR_L2PE; 1301.99Sgarbled 1311.98Sgarbled /* fix the device_type property of a graphics card */ 1321.98Sgarbled for (qhandle = OF_peer(0); qhandle; qhandle = phandle) { 1331.98Sgarbled if (OF_getprop(qhandle, "name", buf, sizeof buf) > 0 1341.98Sgarbled && strncmp(buf, "display", 7) == 0) { 1351.98Sgarbled OF_setprop(qhandle, "device_type", "display", 8); 1361.98Sgarbled break; 1371.98Sgarbled } 1381.98Sgarbled if ((phandle = OF_child(qhandle))) 1391.98Sgarbled continue; 1401.98Sgarbled while (qhandle) { 1411.98Sgarbled if ((phandle = OF_peer(qhandle))) 1421.98Sgarbled break; 1431.98Sgarbled qhandle = OF_parent(qhandle); 1441.98Sgarbled } 1451.98Sgarbled } 1461.98Sgarbled 1471.98Sgarbled /* 1481.98Sgarbled * Get screen width/height and switch to framebuffer mode. 1491.98Sgarbled * The default dimensions are: 800 x 600 1501.98Sgarbled */ 1511.98Sgarbled OF_interpret("screen-width", 0, 1, &width); 1521.98Sgarbled if (width == 0) 1531.98Sgarbled width = 800; 1541.98Sgarbled 1551.98Sgarbled OF_interpret("screen-height", 0, 1, &height); 1561.98Sgarbled if (height == 0) 1571.98Sgarbled height = 600; 1581.98Sgarbled 1591.98Sgarbled /* find VESA mode */ 1601.98Sgarbled for (i = 0, mode = 0; modew[i] != 0; i++) { 1611.98Sgarbled if (modew[i] == width && modeh[i] == height) { 1621.98Sgarbled mode = 0x101 + 2 * i; 1631.98Sgarbled break; 1641.98Sgarbled } 1651.98Sgarbled } 1661.98Sgarbled if (!mode) { 1671.98Sgarbled mode = 0x102; 1681.98Sgarbled width = 800; 1691.98Sgarbled height = 600; 1701.98Sgarbled } 1711.98Sgarbled 1721.98Sgarbled /* init frame buffer mode */ 1731.98Sgarbled sprintf(buf, "%x vesa-set-mode", mode); 1741.98Sgarbled OF_interpret(buf, 0, 0); 1751.98Sgarbled 1761.98Sgarbled /* set dimensions and frame buffer address in OFW */ 1771.98Sgarbled sprintf(buf, "%x to screen-width", width); 1781.98Sgarbled OF_interpret(buf, 0, 0); 1791.98Sgarbled sprintf(buf, "%x to screen-height", height); 1801.98Sgarbled OF_interpret(buf, 0, 0); 1811.98Sgarbled OF_interpret("vesa-frame-buffer-adr", 0, 1, &fbaddr); 1821.98Sgarbled if (fbaddr != 0) { 1831.98Sgarbled sprintf(buf, "%x to frame-buffer-adr", fbaddr); 1841.98Sgarbled OF_interpret(buf, 0, 0); 1851.98Sgarbled } 1861.98Sgarbled } 1871.98Sgarbled} 1881.98Sgarbled 1891.1Swsvoid 1901.93Sgarbledcpu_startup(void) 1911.1Sws{ 1921.98Sgarbled oea_startup(model_name[0] ? model_name : NULL); 1931.104Sgarbled bus_space_mallocok(); 1941.1Sws} 1951.1Sws 1961.96Sgarbled 1971.1Swsvoid 1981.93Sgarbledconsinit(void) 1991.1Sws{ 2001.93Sgarbled ofwoea_consinit(); 2011.71Sthorpej} 2021.96Sgarbled 2031.71Sthorpej 2041.71Sthorpejvoid 2051.93Sgarbleddumpsys(void) 2061.71Sthorpej{ 2071.101Sgarbled aprint_normal("dumpsys: TBD\n"); 2081.1Sws} 2091.1Sws 2101.1Sws/* 2111.93Sgarbled * Halt or reboot the machine after syncing/dumping according to howto. 2121.1Sws */ 2131.1Sws 2141.1Swsvoid 2151.93Sgarbledcpu_reboot(int howto, char *what) 2161.1Sws{ 2171.1Sws static int syncing; 2181.1Sws static char str[256]; 2191.108Sphx char *ap = str, *ap1 = ap; 2201.108Sphx#if (NRTAS > 0) 2211.102Sgarbled int junk; 2221.108Sphx#endif 2231.1Sws 2241.1Sws boothowto = howto; 2251.1Sws if (!cold && !(howto & RB_NOSYNC) && !syncing) { 2261.1Sws syncing = 1; 2271.93Sgarbled vfs_shutdown(); /* sync */ 2281.93Sgarbled resettodr(); /* set wall clock */ 2291.1Sws } 2301.1Sws splhigh(); 2311.1Sws if (howto & RB_HALT) { 2321.1Sws doshutdownhooks(); 2331.107Sdyoung pmf_system_shutdown(boothowto); 2341.101Sgarbled aprint_normal("halted\n\n"); 2351.108Sphx#if (NRTAS > 0) 2361.103Sgarbled if ((howto & 0x800) && machine_has_rtas && 2371.103Sgarbled rtas_has_func(RTAS_FUNC_POWER_OFF)) 2381.103Sgarbled rtas_call(RTAS_FUNC_POWER_OFF, 2, 1, 0, 0, &junk); 2391.108Sphx#endif 2401.1Sws ppc_exit(); 2411.1Sws } 2421.1Sws if (!cold && (howto & RB_DUMP)) 2431.82Smatt oea_dumpsys(); 2441.1Sws doshutdownhooks(); 2451.107Sdyoung 2461.107Sdyoung pmf_system_shutdown(boothowto); 2471.101Sgarbled aprint_normal("rebooting\n\n"); 2481.95Sgarbled 2491.108Sphx#if (NRTAS > 0) 2501.103Sgarbled if (machine_has_rtas && rtas_has_func(RTAS_FUNC_SYSTEM_REBOOT)) { 2511.103Sgarbled rtas_call(RTAS_FUNC_SYSTEM_REBOOT, 0, 1, &junk); 2521.103Sgarbled for(;;); 2531.103Sgarbled } 2541.108Sphx#endif 2551.1Sws if (what && *what) { 2561.1Sws if (strlen(what) > sizeof str - 5) 2571.101Sgarbled aprint_normal("boot string too large, ignored\n"); 2581.1Sws else { 2591.1Sws strcpy(str, what); 2601.1Sws ap1 = ap = str + strlen(str); 2611.1Sws *ap++ = ' '; 2621.1Sws } 2631.1Sws } 2641.1Sws *ap++ = '-'; 2651.1Sws if (howto & RB_SINGLE) 2661.1Sws *ap++ = 's'; 2671.1Sws if (howto & RB_KDB) 2681.1Sws *ap++ = 'd'; 2691.1Sws *ap++ = 0; 2701.1Sws if (ap[-2] == '-') 2711.1Sws *ap1 = 0; 2721.1Sws ppc_boot(str); 2731.1Sws} 2741.97Sgarbled 2751.97Sgarbled/* 2761.97Sgarbled */ 2771.97Sgarbled 2781.97Sgarbled#define divrnd(n, q) (((n)*2/(q)+1)/2) 2791.97Sgarbled 2801.97Sgarbledvoid 2811.98Sgarbledofppc_init_comcons(int isa_node) 2821.97Sgarbled{ 2831.97Sgarbled#if (NCOM > 0) 2841.97Sgarbled char name[64]; 2851.97Sgarbled uint32_t reg[2], comfreq; 2861.97Sgarbled uint8_t dll, dlm; 2871.98Sgarbled int speed, rate, err, com_node, child; 2881.104Sgarbled bus_space_handle_t comh; 2891.97Sgarbled 2901.97Sgarbled /* if we have a serial cons, we have work to do */ 2911.97Sgarbled memset(name, 0, sizeof(name)); 2921.97Sgarbled OF_getprop(console_node, "device_type", name, sizeof(name)); 2931.97Sgarbled if (strcmp(name, "serial") != 0) 2941.97Sgarbled return; 2951.97Sgarbled 2961.98Sgarbled /* scan ISA children for serial devices to match our console */ 2971.98Sgarbled com_node = -1; 2981.98Sgarbled for (child = OF_child(isa_node); child; child = OF_peer(child)) { 2991.98Sgarbled memset(name, 0, sizeof(name)); 3001.98Sgarbled OF_getprop(child, "device_type", name, sizeof(name)); 3011.98Sgarbled if (strcmp(name, "serial") == 0) { 3021.98Sgarbled /* 3031.98Sgarbled * Serial device even matches our console_node? 3041.98Sgarbled * Then we're done! 3051.98Sgarbled */ 3061.98Sgarbled if (child == console_node) { 3071.98Sgarbled com_node = child; 3081.98Sgarbled break; 3091.98Sgarbled } 3101.98Sgarbled /* remember first serial device found */ 3111.98Sgarbled if (com_node == -1) 3121.98Sgarbled com_node = child; 3131.98Sgarbled } 3141.98Sgarbled } 3151.98Sgarbled 3161.98Sgarbled if (com_node == -1) 3171.98Sgarbled return; 3181.98Sgarbled 3191.98Sgarbled if (OF_getprop(com_node, "reg", reg, sizeof(reg)) == -1) 3201.97Sgarbled return; 3211.97Sgarbled 3221.98Sgarbled if (OF_getprop(com_node, "clock-frequency", &comfreq, 4) == -1) 3231.97Sgarbled comfreq = 0; 3241.97Sgarbled 3251.97Sgarbled if (comfreq == 0) 3261.97Sgarbled comfreq = COM_FREQ; 3271.97Sgarbled 3281.104Sgarbled /* we need to BSM this, and then undo that before calling 3291.104Sgarbled * comcnattach. 3301.104Sgarbled */ 3311.104Sgarbled 3321.104Sgarbled if (bus_space_map(&genppc_isa_io_space_tag, reg[1], 8, 0, &comh) != 0) 3331.104Sgarbled panic("Can't map isa serial\n"); 3341.104Sgarbled 3351.104Sgarbled bus_space_write_1(&genppc_isa_io_space_tag, comh, com_cfcr, LCR_DLAB); 3361.104Sgarbled dll = bus_space_read_1(&genppc_isa_io_space_tag, comh, com_dlbl); 3371.104Sgarbled dlm = bus_space_read_1(&genppc_isa_io_space_tag, comh, com_dlbh); 3381.97Sgarbled rate = dll | (dlm << 8); 3391.104Sgarbled bus_space_write_1(&genppc_isa_io_space_tag, comh, com_cfcr, LCR_8BITS); 3401.97Sgarbled speed = divrnd((comfreq / 16), rate); 3411.97Sgarbled err = speed - (speed + 150)/300 * 300; 3421.97Sgarbled speed -= err; 3431.97Sgarbled if (err < 0) 3441.97Sgarbled err = -err; 3451.97Sgarbled if (err > 50) 3461.97Sgarbled speed = 9600; 3471.97Sgarbled 3481.104Sgarbled bus_space_unmap(&genppc_isa_io_space_tag, comh, 8); 3491.104Sgarbled 3501.97Sgarbled /* Now we can attach the comcons */ 3511.97Sgarbled aprint_verbose("Switching to COM console at speed %d", speed); 3521.98Sgarbled if (comcnattach(&genppc_isa_io_space_tag, reg[1], 3531.98Sgarbled speed, comfreq, COM_TYPE_NORMAL, 3541.97Sgarbled ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8))) 3551.97Sgarbled panic("Can't init serial console"); 3561.97Sgarbled aprint_verbose("\n"); 3571.97Sgarbled#endif /*NCOM*/ 3581.97Sgarbled} 3591.98Sgarbled 3601.98Sgarbledvoid 3611.98Sgarbledcopy_disp_props(struct device *dev, int node, prop_dictionary_t dict) 3621.98Sgarbled{ 3631.98Sgarbled uint32_t temp; 3641.98Sgarbled char typestr[32]; 3651.98Sgarbled 3661.98Sgarbled memset(typestr, 0, sizeof(typestr)); 3671.98Sgarbled OF_getprop(console_node, "device_type", typestr, sizeof(typestr)); 3681.98Sgarbled if (strcmp(typestr, "serial") != 0) { 3691.98Sgarbled /* this is our console, when we don't have a serial console */ 3701.98Sgarbled prop_dictionary_set_bool(dict, "is_console", 1); 3711.98Sgarbled } 3721.98Sgarbled 3731.98Sgarbled if (!of_to_uint32_prop(dict, node, "width", "width")) { 3741.98Sgarbled 3751.98Sgarbled OF_interpret("screen-width", 0, 1, &temp); 3761.98Sgarbled prop_dictionary_set_uint32(dict, "width", temp); 3771.98Sgarbled } 3781.98Sgarbled if (!of_to_uint32_prop(dict, node, "height", "height")) { 3791.98Sgarbled 3801.98Sgarbled OF_interpret("screen-height", 0, 1, &temp); 3811.98Sgarbled prop_dictionary_set_uint32(dict, "height", temp); 3821.98Sgarbled } 3831.98Sgarbled of_to_uint32_prop(dict, node, "linebytes", "linebytes"); 3841.98Sgarbled if (!of_to_uint32_prop(dict, node, "depth", "depth")) { 3851.98Sgarbled /* 3861.98Sgarbled * XXX we should check linebytes vs. width but those 3871.98Sgarbled * FBs that don't have a depth property ( /chaos/control... ) 3881.98Sgarbled * won't have linebytes either 3891.98Sgarbled */ 3901.98Sgarbled prop_dictionary_set_uint32(dict, "depth", 8); 3911.98Sgarbled } 3921.98Sgarbled if (!of_to_uint32_prop(dict, node, "address", "address")) { 3931.98Sgarbled uint32_t fbaddr = 0; 3941.98Sgarbled OF_interpret("frame-buffer-adr", 0, 1, &fbaddr); 3951.98Sgarbled if (fbaddr != 0) 3961.98Sgarbled prop_dictionary_set_uint32(dict, "address", fbaddr); 3971.98Sgarbled } 3981.98Sgarbled} 399