xref: /netbsd/sys/arch/ofppc/ofppc/machdep.c (revision 6550d01e)
1 /*	$NetBSD: machdep.c,v 1.113 2010/11/02 19:19:22 phx Exp $	*/
2 /*-
3  * Copyright (c) 2007 The NetBSD Foundation, Inc.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to The NetBSD Foundation
7  * by Tim Rightnour
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.113 2010/11/02 19:19:22 phx Exp $");
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/buf.h>
37 #include <sys/boot_flag.h>
38 #include <sys/mount.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 
42 #include <uvm/uvm_extern.h>
43 
44 #include <dev/ofw/openfirm.h>
45 #include <dev/cons.h>
46 
47 #include <machine/autoconf.h>
48 #include <machine/pmap.h>
49 #include <machine/powerpc.h>
50 #include <machine/trap.h>
51 #include <machine/bus.h>
52 #include <machine/isa_machdep.h>
53 
54 #include <powerpc/spr.h>
55 #include <powerpc/oea/spr.h>
56 #include <powerpc/oea/bat.h>
57 #include <powerpc/ofw_cons.h>
58 #include <powerpc/rtas.h>
59 
60 #include "com.h"
61 #if (NCOM > 0)
62 #include <sys/termios.h>
63 #include <dev/ic/comreg.h>
64 #include <dev/ic/comvar.h>
65 #endif
66 #include "rtas.h"
67 
68 struct pmap ofw_pmap;
69 char bootpath[256];
70 
71 extern u_int l2cr_config;
72 #if (NRTAS > 0)
73 extern int machine_has_rtas;
74 #endif
75 
76 struct model_data modeldata;
77 
78 void
79 initppc(u_int startkernel, u_int endkernel, char *args)
80 {
81 	ofwoea_initppc(startkernel, endkernel, args);
82 }
83 
84 /* perform model-specific actions at initppc() */
85 void
86 model_init(void)
87 {
88 	int qhandle, phandle, j;
89 
90 	memset(&modeldata, 0, sizeof(struct model_data));
91 	/* provide sane defaults */
92 	for (j=0; j < MAX_PCI_BUSSES; j++) {
93 		modeldata.pciiodata[j].start = 0x00008000;
94 		modeldata.pciiodata[j].limit = 0x0000ffff;
95 	}
96 	modeldata.ranges_offset = 1;
97 
98 	if (strncmp(model_name, "FirePower,", 10) == 0) {
99 		modeldata.ranges_offset = 0;
100 	}
101 	if (strcmp(model_name, "MOT,PowerStack_II_Pro4000") == 0) {
102 		modeldata.ranges_offset = 0;
103 	}
104 
105 	/* 7044-270 and 7044-170 */
106 	if (strncmp(model_name, "IBM,7044", 8) == 0) {
107 		for (j=0; j < MAX_PCI_BUSSES; j++) {
108 			modeldata.pciiodata[j].start = 0x00fff000;
109 			modeldata.pciiodata[j].limit = 0x00ffffff;
110 		}
111 	}
112 
113 	/* Pegasos1, Pegasos2 */
114 	if (strncmp(model_name, "Pegasos", 7) == 0) {
115 		static uint16_t modew[] = { 640, 800, 1024, 1280, 0 };
116 		static uint16_t modeh[] = { 480, 600, 768, 1024, 0 };
117 		uint32_t width, height, mode, fbaddr;
118 		char buf[32];
119 		int i;
120 
121 		modeldata.pciiodata[0].start = 0x00001400;
122 		modeldata.pciiodata[0].limit = 0x0000ffff;
123 
124 		/* the pegasos doesn't bother to set the L2 cache up */
125 		l2cr_config = L2CR_L2PE;
126 
127 		/* fix the device_type property of a graphics card */
128 		for (qhandle = OF_peer(0); qhandle; qhandle = phandle) {
129 			if (OF_getprop(qhandle, "name", buf, sizeof buf) > 0
130 			    && strncmp(buf, "display", 7) == 0) {
131 				OF_setprop(qhandle, "device_type", "display", 8);
132 				break;
133 			}
134 			if ((phandle = OF_child(qhandle)))
135 				continue;
136 			while (qhandle) {
137 				if ((phandle = OF_peer(qhandle)))
138 					break;
139 				qhandle = OF_parent(qhandle);
140 			}
141 		}
142 
143 		/*
144 		 * Get screen width/height and switch to framebuffer mode.
145 		 * The default dimensions are: 800 x 600
146 		 */
147 		OF_interpret("screen-width", 0, 1, &width);
148 		if (width == 0)
149 			width = 800;
150 
151 		OF_interpret("screen-height", 0, 1, &height);
152 		if (height == 0)
153 			height = 600;
154 
155 		/* find VESA mode */
156 		for (i = 0, mode = 0; modew[i] != 0; i++) {
157 			if (modew[i] == width && modeh[i] == height) {
158 				mode = 0x101 + 2 * i;
159 				break;
160 			}
161 		}
162 		if (!mode) {
163 			mode = 0x103;
164 			width = 800;
165 			height = 600;
166 		}
167 
168 		/* init frame buffer mode */
169 		sprintf(buf, "%x vesa-set-mode", mode);
170 		OF_interpret(buf, 0, 0);
171 
172 		/* set dimensions and frame buffer address in OFW */
173 		sprintf(buf, "%x to screen-width", width);
174 		OF_interpret(buf, 0, 0);
175 		sprintf(buf, "%x to screen-height", height);
176 		OF_interpret(buf, 0, 0);
177 		OF_interpret("vesa-frame-buffer-adr", 0, 1, &fbaddr);
178 		if (fbaddr != 0) {
179 			sprintf(buf, "%x to frame-buffer-adr", fbaddr);
180 			OF_interpret(buf, 0, 0);
181 		}
182 	}
183 }
184 
185 void
186 cpu_startup(void)
187 {
188 	oea_startup(model_name[0] ? model_name : NULL);
189 	bus_space_mallocok();
190 }
191 
192 
193 void
194 consinit(void)
195 {
196 	ofwoea_consinit();
197 }
198 
199 
200 void
201 dumpsys(void)
202 {
203 	aprint_normal("dumpsys: TBD\n");
204 }
205 
206 /*
207  * Halt or reboot the machine after syncing/dumping according to howto.
208  */
209 
210 void
211 cpu_reboot(int howto, char *what)
212 {
213 	static int syncing;
214 	static char str[256];
215 	char *ap = str, *ap1 = ap;
216 #if (NRTAS > 0)
217 	int junk;
218 #endif
219 
220 	boothowto = howto;
221 	if (!cold && !(howto & RB_NOSYNC) && !syncing) {
222 		syncing = 1;
223 		vfs_shutdown();         /* sync */
224 		resettodr();            /* set wall clock */
225 	}
226 	splhigh();
227 	if (howto & RB_HALT) {
228 		doshutdownhooks();
229 		pmf_system_shutdown(boothowto);
230 		aprint_normal("halted\n\n");
231 #if (NRTAS > 0)
232 		if ((howto & 0x800) && machine_has_rtas &&
233 		    rtas_has_func(RTAS_FUNC_POWER_OFF))
234 			rtas_call(RTAS_FUNC_POWER_OFF, 2, 1, 0, 0, &junk);
235 #endif
236 		ppc_exit();
237 	}
238 	if (!cold && (howto & RB_DUMP))
239 		oea_dumpsys();
240 	doshutdownhooks();
241 
242 	pmf_system_shutdown(boothowto);
243 	aprint_normal("rebooting\n\n");
244 
245 #if (NRTAS > 0)
246 	if (machine_has_rtas && rtas_has_func(RTAS_FUNC_SYSTEM_REBOOT)) {
247 		rtas_call(RTAS_FUNC_SYSTEM_REBOOT, 0, 1, &junk);
248 		for(;;);
249 	}
250 #endif
251 	if (what && *what) {
252 		if (strlen(what) > sizeof str - 5)
253 			aprint_normal("boot string too large, ignored\n");
254 		else {
255 			strcpy(str, what);
256 			ap1 = ap = str + strlen(str);
257 			*ap++ = ' ';
258 		}
259 	}
260 	*ap++ = '-';
261 	if (howto & RB_SINGLE)
262 		*ap++ = 's';
263 	if (howto & RB_KDB)
264 		*ap++ = 'd';
265 	*ap++ = 0;
266 	if (ap[-2] == '-')
267 		*ap1 = 0;
268 	ppc_boot(str);
269 }
270 
271 /*
272  */
273 
274 #define divrnd(n, q)	(((n)*2/(q)+1)/2)
275 
276 void
277 ofppc_init_comcons(int isa_node)
278 {
279 #if (NCOM > 0)
280 	char name[64];
281 	uint32_t reg[2], comfreq;
282 	uint8_t dll, dlm;
283 	int speed, rate, err, com_node, child;
284 	bus_space_handle_t comh;
285 
286 	/* if we have a serial cons, we have work to do */
287 	memset(name, 0, sizeof(name));
288 	OF_getprop(console_node, "device_type", name, sizeof(name));
289 	if (strcmp(name, "serial") != 0)
290 		return;
291 
292 	/* scan ISA children for serial devices to match our console */
293 	com_node = -1;
294 	for (child = OF_child(isa_node); child; child = OF_peer(child)) {
295 		memset(name, 0, sizeof(name));
296 		OF_getprop(child, "device_type", name, sizeof(name));
297 		if (strcmp(name, "serial") == 0) {
298 			/*
299 			 * Serial device even matches our console_node?
300 			 * Then we're done!
301 			 */
302 			if (child == console_node) {
303 				com_node = child;
304 				break;
305 			}
306 			/* remember first serial device found */
307 			if (com_node == -1)
308 				com_node = child;
309 		}
310 	}
311 
312 	if (com_node == -1)
313 		return;
314 
315 	if (OF_getprop(com_node, "reg", reg, sizeof(reg)) == -1)
316 		return;
317 
318 	if (OF_getprop(com_node, "clock-frequency", &comfreq, 4) == -1)
319 		comfreq = 0;
320 
321 	if (comfreq == 0)
322 		comfreq = COM_FREQ;
323 
324 	/* we need to BSM this, and then undo that before calling
325 	 * comcnattach.
326 	 */
327 
328 	if (bus_space_map(&genppc_isa_io_space_tag, reg[1], 8, 0, &comh) != 0)
329 		panic("Can't map isa serial\n");
330 
331 	bus_space_write_1(&genppc_isa_io_space_tag, comh, com_cfcr, LCR_DLAB);
332 	dll = bus_space_read_1(&genppc_isa_io_space_tag, comh, com_dlbl);
333 	dlm = bus_space_read_1(&genppc_isa_io_space_tag, comh, com_dlbh);
334 	rate = dll | (dlm << 8);
335 	bus_space_write_1(&genppc_isa_io_space_tag, comh, com_cfcr, LCR_8BITS);
336 	speed = divrnd((comfreq / 16), rate);
337 	err = speed - (speed + 150)/300 * 300;
338 	speed -= err;
339 	if (err < 0)
340 		err = -err;
341 	if (err > 50)
342 		speed = 9600;
343 
344 	bus_space_unmap(&genppc_isa_io_space_tag, comh, 8);
345 
346 	/* Now we can attach the comcons */
347 	aprint_verbose("Switching to COM console at speed %d", speed);
348 	if (comcnattach(&genppc_isa_io_space_tag, reg[1],
349 	    speed, comfreq, COM_TYPE_NORMAL,
350 	    ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8)))
351 		panic("Can't init serial console");
352 	aprint_verbose("\n");
353 #endif /*NCOM*/
354 }
355 
356 void
357 copy_disp_props(struct device *dev, int node, prop_dictionary_t dict)
358 {
359 	uint32_t temp;
360 	char typestr[32];
361 
362 	memset(typestr, 0, sizeof(typestr));
363 	OF_getprop(console_node, "device_type", typestr, sizeof(typestr));
364 	if (strcmp(typestr, "serial") != 0) {
365 		/* this is our console, when we don't have a serial console */
366 		prop_dictionary_set_bool(dict, "is_console", 1);
367 	}
368 
369 	if (!of_to_uint32_prop(dict, node, "width", "width")) {
370 
371 		OF_interpret("screen-width", 0, 1, &temp);
372 		prop_dictionary_set_uint32(dict, "width", temp);
373 	}
374 	if (!of_to_uint32_prop(dict, node, "height", "height")) {
375 
376 		OF_interpret("screen-height", 0, 1, &temp);
377 		prop_dictionary_set_uint32(dict, "height", temp);
378 	}
379 	of_to_uint32_prop(dict, node, "linebytes", "linebytes");
380 	if (!of_to_uint32_prop(dict, node, "depth", "depth")) {
381 		/*
382 		 * XXX we should check linebytes vs. width but those
383 		 * FBs that don't have a depth property ( /chaos/control... )
384 		 * won't have linebytes either
385 		 */
386 		prop_dictionary_set_uint32(dict, "depth", 8);
387 	}
388 	if (!of_to_uint32_prop(dict, node, "address", "address")) {
389 		uint32_t fbaddr = 0;
390 
391 		OF_interpret("frame-buffer-adr", 0, 1, &fbaddr);
392 		if (fbaddr != 0)
393 			prop_dictionary_set_uint32(dict, "address", fbaddr);
394 	}
395 }
396