xref: /netbsd/sys/arch/arc/arc/arcbios.c (revision bf9ec67e)
1 /*	$NetBSD: arcbios.c,v 1.10 2001/11/22 12:17:00 tsutsui Exp $	*/
2 /*	$OpenBSD: arcbios.c,v 1.3 1998/06/06 06:33:33 mickey Exp $	*/
3 
4 /*-
5  * Copyright (c) 1996 M. Warner Losh.  All rights reserved.
6  * Copyright (c) 1996, 1997, 1998 Per Fogelstrom.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/proc.h>
36 #include <sys/user.h>
37 #include <sys/kcore.h>
38 #include <uvm/uvm_extern.h>
39 #include <dev/cons.h>
40 #include <machine/cpu.h>
41 #include <arc/arc/arcbios.h>
42 
43 int Bios_Read __P((int, char *, int, int *));
44 int Bios_Write __P((int, char *, int, int *));
45 int Bios_Open __P((char *, int, u_int *));
46 int Bios_Close __P((u_int));
47 arc_mem_t *Bios_GetMemoryDescriptor __P((arc_mem_t *));
48 arc_sid_t *Bios_GetSystemId __P((void));
49 arc_config_t *Bios_GetChild __P((arc_config_t *));
50 arc_config_t *Bios_GetPeer __P((arc_config_t *));
51 arc_dsp_stat_t *Bios_GetDisplayStatus __P((int));
52 
53 static void bios_config_id_copy __P((arc_config_t *, char *, size_t));
54 static void bios_config_component __P((arc_config_t *));
55 static void bios_config_subtree __P((arc_config_t *));
56 
57 char arc_vendor_id[sizeof(((arc_sid_t *)0)->vendor) + 1];
58 unsigned char arc_product_id[sizeof(((arc_sid_t *)0)->prodid)];
59 
60 char arc_id[64 + 1];
61 
62 char arc_displayc_id[64 + 1];		/* DisplayController id */
63 arc_dsp_stat_t	arc_displayinfo;	/* Save area for display status info. */
64 
65 int arc_cpu_l2cache_size = 0;
66 
67 /*
68  *	ARC Bios trampoline code.
69  */
70 #define ARC_Call(Name,Offset)	\
71 __asm__("\n"			\
72 "	.text\n"		\
73 "	.ent	" #Name "\n"	\
74 "	.align	3\n"		\
75 "	.set	noreorder\n"	\
76 "	.globl	" #Name "\n" 	\
77 #Name":\n"			\
78 "	lw	$2, 0x80001020\n"\
79 "	lw	$2," #Offset "($2)\n"\
80 "	jr	$2\n"		\
81 "	nop\n"			\
82 "	.end	" #Name "\n"	);
83 
84 ARC_Call(Bios_Load,			0x00);
85 ARC_Call(Bios_Invoke,			0x04);
86 ARC_Call(Bios_Execute,			0x08);
87 ARC_Call(Bios_Halt,			0x0c);
88 ARC_Call(Bios_PowerDown,		0x10);
89 ARC_Call(Bios_Restart,			0x14);
90 ARC_Call(Bios_Reboot,			0x18);
91 ARC_Call(Bios_EnterInteractiveMode,	0x1c);
92 ARC_Call(Bios_Unused1,			0x20);	/* return_from_main? */
93 ARC_Call(Bios_GetPeer,			0x24);
94 ARC_Call(Bios_GetChild,			0x28);
95 ARC_Call(Bios_GetParent,		0x2c);
96 ARC_Call(Bios_GetConfigurationData,	0x30);
97 ARC_Call(Bios_AddChild,			0x34);
98 ARC_Call(Bios_DeleteComponent,		0x38);
99 ARC_Call(Bios_GetComponent,		0x3c);
100 ARC_Call(Bios_SaveConfiguration,	0x40);
101 ARC_Call(Bios_GetSystemId,		0x44);
102 ARC_Call(Bios_GetMemoryDescriptor,	0x48);
103 ARC_Call(Bios_Unused2,			0x4c);	/* signal??? */
104 ARC_Call(Bios_GetTime,			0x50);
105 ARC_Call(Bios_GetRelativeTime,		0x54);
106 ARC_Call(Bios_GetDirectoryEntry,	0x58);
107 ARC_Call(Bios_Open,			0x5c);
108 ARC_Call(Bios_Close,			0x60);
109 ARC_Call(Bios_Read,			0x64);
110 ARC_Call(Bios_GetReadStatus,		0x68);
111 ARC_Call(Bios_Write,			0x6c);
112 ARC_Call(Bios_Seek,			0x70);
113 ARC_Call(Bios_Mount,			0x74);
114 ARC_Call(Bios_GetEnvironmentVariable,	0x78);
115 ARC_Call(Bios_SetEnvironmentVariable,	0x7c);
116 ARC_Call(Bios_GetFileInformation,	0x80);
117 ARC_Call(Bios_SetFileInformation,	0x84);
118 ARC_Call(Bios_FlushAllCaches,		0x88);
119 /* note: the followings don't exist on SGI */
120 #ifdef arc
121 ARC_Call(Bios_TestUnicodeCharacter,	0x8c);
122 ARC_Call(Bios_GetDisplayStatus,		0x90);
123 #endif
124 
125 /*
126  *	BIOS based console, for early stage.
127  */
128 
129 int  biosgetc __P((dev_t));
130 void biosputc __P((dev_t, int));
131 
132 /* this is to fake out the console routines, while booting. */
133 struct consdev bioscons = {
134 	NULL, NULL, biosgetc, biosputc, nullcnpollc, NULL, NODEV, CN_DEAD
135 };
136 
137 int
138 biosgetc(dev)
139 	dev_t dev;
140 {
141 	int cnt;
142 	char buf;
143 
144 	if (Bios_Read(0, &buf, 1, &cnt) != arc_ESUCCESS)
145 		return (-1);
146 	return (buf & 255);
147 }
148 
149 void
150 biosputc(dev, ch)
151 	dev_t dev;
152 	int ch;
153 {
154 	int cnt;
155 	char buf;
156 
157 	buf = ch;
158 	Bios_Write(1, &buf, 1, &cnt);
159 }
160 
161 void
162 bios_init_console()
163 {
164 	static int initialized = 0;
165 
166 	if (!initialized) {
167 		initialized = 1;
168 		/* fake out the console routines, for now */
169 		cn_tab = &bioscons;
170 	}
171 }
172 
173 /*
174  * Get memory descriptor for the memory configuration and
175  * create a layout database used by pmap init to set up
176  * the memory system.
177  *
178  * Concatenate obvious adjecent segments.
179  */
180 int
181 bios_configure_memory(mem_reserved, mem_clusters, mem_cluster_cnt_return)
182 	int *mem_reserved;
183 	phys_ram_seg_t *mem_clusters;
184 	int *mem_cluster_cnt_return;
185 {
186 	int physmem = 0;		/* Total physical memory size */
187 	int mem_cluster_cnt = 0;
188 
189 	arc_mem_t *descr = NULL;
190 	paddr_t seg_start, seg_end;
191 	int i, reserved;
192 
193 	while ((descr = Bios_GetMemoryDescriptor(descr)) != NULL) {
194 		seg_start = descr->BasePage * 4096;
195 		seg_end = seg_start + descr->PageCount * 4096;
196 
197 #ifdef BIOS_MEMORY_DEBUG
198 		printf("memory type:%d, 0x%8lx..%8lx, size:%8ld bytes\n",
199 		    descr->Type, (u_long)seg_start, (u_long)seg_end,
200 		    (u_long)(seg_end - seg_start));
201 #endif
202 
203 		switch (descr->Type) {
204 		case BadMemory:		/* Have no use for these */
205 			break;
206 
207 		case ExeceptionBlock:
208 		case SystemParameterBlock:
209 		case FirmwarePermanent:
210 			reserved = 1;
211 			goto account_it;
212 
213 		case FreeMemory:
214 		case LoadedProgram:	/* This is the loaded kernel */
215 		case FirmwareTemporary:
216 		case FreeContigous:
217 			reserved = 0;
218 account_it:
219 			physmem += descr->PageCount * 4096;
220 
221 			for (i = 0; i < mem_cluster_cnt; ) {
222 				if (mem_reserved[i] == reserved &&
223 				    mem_clusters[i].start == seg_end)
224 					seg_end += mem_clusters[i].size;
225 				else if (mem_reserved[i] == reserved &&
226 				    mem_clusters[i].start +
227 				    mem_clusters[i].size == seg_start)
228 					seg_start = mem_clusters[i].start;
229 				else { /* do not merge the cluster */
230 					i++;
231 					continue;
232 				}
233 				--mem_cluster_cnt;
234 				mem_reserved[i] = mem_reserved[mem_cluster_cnt];
235 				mem_clusters[i] = mem_clusters[mem_cluster_cnt];
236 			}
237 			/* assert(i == mem_cluster_cnt); */
238 			if (mem_cluster_cnt >= VM_PHYSSEG_MAX) {
239 				printf("VM_PHYSSEG_MAX too small\n");
240 				for (;;)
241 					;
242 			}
243 			mem_reserved[i] = reserved;
244 			mem_clusters[i].start =	seg_start;
245 			mem_clusters[i].size = seg_end - seg_start;
246 			mem_cluster_cnt++;
247 			break;
248 
249 		default:		/* Unknown type, leave it alone... */
250 			break;
251 		}
252 	}
253 
254 #ifdef BIOS_MEMORY_DEBUG
255 	for (i = 0; i < mem_cluster_cnt; i++)
256 		printf("mem_clusters[%d] = %d:{ 0x%8lx, 0x%8lx }\n", i,
257 		    mem_reserved[i],
258 		    (long)mem_clusters[i].start,
259 		    (long)mem_clusters[i].size);
260 	printf("physmem = %d\n", physmem);
261 #endif
262 
263 	*mem_cluster_cnt_return = mem_cluster_cnt;
264 	return (physmem);
265 }
266 
267 /*
268  * ARC Firmware present?
269  */
270 int
271 bios_ident()
272 {
273 	return (
274 	    (ArcBiosBase->magic == ARC_PARAM_BLK_MAGIC) ||
275 	    (ArcBiosBase->magic == ARC_PARAM_BLK_MAGIC_BUG));
276 }
277 
278 /*
279  * save various information of BIOS for future use.
280  */
281 
282 static void
283 bios_config_id_copy(cf, string, size)
284 	arc_config_t *cf;
285 	char *string;
286 	size_t size;
287 {
288 	size--;
289 	if (size > cf->id_len)
290 		size = cf->id_len;
291 	memcpy(string, cf->id, size);
292 	string[size] = '\0';
293 }
294 
295 static void
296 bios_config_component(cf)
297 	arc_config_t *cf;
298 {
299 	switch (cf->class) {
300 	case arc_SystemClass:
301 		if (cf->type == arc_System)
302 			bios_config_id_copy(cf, arc_id, sizeof(arc_id));
303 		break;
304 	case arc_CacheClass:
305 		if (cf->type == arc_SecondaryDcache)
306 			arc_cpu_l2cache_size = 4096 << (cf->key & 0xffff);
307 		break;
308 	case arc_ControllerClass:
309 		if (cf->type == arc_DisplayController &&
310 		    arc_displayc_id[0] == '\0' /* first found one. XXX */)
311 			bios_config_id_copy(cf, arc_displayc_id,
312 			    sizeof(arc_displayc_id));
313 		break;
314 	default:
315 		break;
316 	}
317 }
318 
319 static
320 void bios_config_subtree(cf)
321 	arc_config_t *cf;
322 {
323 	for (cf = Bios_GetChild(cf); cf != NULL; cf = Bios_GetPeer(cf)) {
324 		bios_config_component(cf);
325 		bios_config_subtree(cf);
326 	}
327 }
328 
329 void
330 bios_save_info()
331 {
332 	arc_sid_t *sid;
333 
334 	sid = Bios_GetSystemId();
335 	if (sid) {
336 		memcpy(arc_vendor_id, sid->vendor, sizeof(arc_vendor_id) - 1);
337 		arc_vendor_id[sizeof(arc_vendor_id) - 1] = 0;
338 		memcpy(arc_product_id, sid->prodid, sizeof(arc_product_id));
339 	}
340 
341 	bios_config_subtree(NULL);
342 
343 #ifdef arc
344 	arc_displayinfo = *Bios_GetDisplayStatus(1);
345 #endif
346 }
347 
348 #ifdef arc
349 /*
350  * Return geometry of the display. Used by pccons.c to set up the
351  * display configuration.
352  */
353 void
354 bios_display_info(xpos, ypos, xsize, ysize)
355 	int *xpos;
356 	int *ypos;
357 	int *xsize;
358 	int *ysize;
359 {
360 	*xpos = arc_displayinfo.CursorXPosition;
361 	*ypos = arc_displayinfo.CursorYPosition;
362 	*xsize = arc_displayinfo.CursorMaxXPosition;
363 	*ysize = arc_displayinfo.CursorMaxYPosition;
364 }
365 #endif
366