1/* 2 * Copyright (C) 1996 The Australian National University. 3 * Copyright (C) 1996 Fujitsu Laboratories Limited 4 * Copyright (C) 1997 Michael A. Griffith (grif@acm.org) 5 * Copyright (C) 1997 Sun Weenie (ko@ko.reno.nv.us) 6 * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 7 * 8 * This software may be distributed under the terms of the Gnu 9 * Public License version 2 or later 10 * 11 * fake a really simple Sun prom for the SUN4 12 */ 13 14#include <linux/kernel.h> 15#include <linux/string.h> 16#include <asm/oplib.h> 17#include <asm/idprom.h> 18#include <asm/machines.h> 19#include <asm/sun4prom.h> 20#include <asm/asi.h> 21#include <asm/contregs.h> 22#include <linux/init.h> 23 24static struct linux_romvec sun4romvec; 25static struct idprom sun4_idprom; 26 27struct property { 28 char *name; 29 char *value; 30 int length; 31}; 32 33struct node { 34 int level; 35 struct property *properties; 36}; 37 38struct property null_properties = { NULL, NULL, -1 }; 39 40struct property root_properties[] = { 41 {"device_type", "cpu", 4}, 42 {"idprom", (char *)&sun4_idprom, sizeof(struct idprom)}, 43 {NULL, NULL, -1} 44}; 45 46struct node nodes[] = { 47 { 0, &null_properties }, 48 { 0, root_properties }, 49 { -1,&null_properties } 50}; 51 52 53static int no_nextnode(int node) 54{ 55 if (nodes[node].level == nodes[node+1].level) 56 return node+1; 57 return -1; 58} 59 60static int no_child(int node) 61{ 62 if (nodes[node].level == nodes[node+1].level-1) 63 return node+1; 64 return -1; 65} 66 67static struct property *find_property(int node,char *name) 68{ 69 struct property *prop = &nodes[node].properties[0]; 70 while (prop && prop->name) { 71 if (strcmp(prop->name,name) == 0) return prop; 72 prop++; 73 } 74 return NULL; 75} 76 77static int no_proplen(int node,char *name) 78{ 79 struct property *prop = find_property(node,name); 80 if (prop) return prop->length; 81 return -1; 82} 83 84static int no_getprop(int node,char *name,char *value) 85{ 86 struct property *prop = find_property(node,name); 87 if (prop) { 88 memcpy(value,prop->value,prop->length); 89 return 1; 90 } 91 return -1; 92} 93 94static int no_setprop(int node,char *name,char *value,int len) 95{ 96 return -1; 97} 98 99static char *no_nextprop(int node,char *name) 100{ 101 struct property *prop = find_property(node,name); 102 if (prop) return prop[1].name; 103 return NULL; 104} 105 106static struct linux_nodeops sun4_nodeops = { 107 no_nextnode, 108 no_child, 109 no_proplen, 110 no_getprop, 111 no_setprop, 112 no_nextprop 113}; 114 115static int synch_hook; 116 117struct linux_romvec * __init sun4_prom_init(void) 118{ 119 int i; 120 unsigned char x; 121 char *p; 122 123 p = (char *)&sun4_idprom; 124 for (i = 0; i < sizeof(sun4_idprom); i++) { 125 __asm__ __volatile__ ("lduba [%1] %2, %0" : "=r" (x) : 126 "r" (AC_IDPROM + i), "i" (ASI_CONTROL)); 127 *p++ = x; 128 } 129 130 memset(&sun4romvec,0,sizeof(sun4romvec)); 131 132 sun4_romvec = (linux_sun4_romvec *) SUN4_PROM_VECTOR; 133 134 sun4romvec.pv_romvers = 40; 135 sun4romvec.pv_nodeops = &sun4_nodeops; 136 sun4romvec.pv_reboot = sun4_romvec->reboot; 137 sun4romvec.pv_abort = sun4_romvec->abortentry; 138 sun4romvec.pv_halt = sun4_romvec->exittomon; 139 sun4romvec.pv_synchook = (void (**)(void))&synch_hook; 140 sun4romvec.pv_setctxt = sun4_romvec->setcxsegmap; 141 sun4romvec.pv_v0bootargs = sun4_romvec->bootParam; 142 sun4romvec.pv_nbgetchar = sun4_romvec->mayget; 143 sun4romvec.pv_nbputchar = sun4_romvec->mayput; 144 sun4romvec.pv_stdin = sun4_romvec->insource; 145 sun4romvec.pv_stdout = sun4_romvec->outsink; 146 147 /* 148 * We turn on the LEDs to let folks without monitors or 149 * terminals know we booted. Nothing too fancy now. They 150 * are all on, except for LED 5, which blinks. When we 151 * have more time, we can teach the penguin to say "By your 152 * command" or "Activating turbo boost, Michael". :-) 153 */ 154 sun4_romvec->setLEDs(NULL); 155 156 printk("PROMLIB: Old Sun4 boot PROM monitor %s, romvec version %d\n", 157 sun4_romvec->monid, 158 sun4_romvec->romvecversion); 159 160 return &sun4romvec; 161} 162