1/*	$NetBSD: arcbios.c,v 1.16 2005/12/24 23:23:59 perry 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/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: arcbios.c,v 1.16 2005/12/24 23:23:59 perry Exp $");
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/proc.h>
39#include <sys/kcore.h>
40#include <uvm/uvm_extern.h>
41#include <dev/cons.h>
42#include <machine/cpu.h>
43#include <arc/arc/arcbios.h>
44
45int Bios_Read(int, char *, int, int *);
46int Bios_Write(int, char *, int, int *);
47int Bios_Open(char *, int, u_int *);
48int Bios_Close(u_int);
49arc_mem_t *Bios_GetMemoryDescriptor(arc_mem_t *);
50arc_sid_t *Bios_GetSystemId(void);
51arc_config_t *Bios_GetChild(arc_config_t *);
52arc_config_t *Bios_GetPeer(arc_config_t *);
53arc_dsp_stat_t *Bios_GetDisplayStatus(int);
54
55static void bios_config_id_copy(arc_config_t *, char *, size_t);
56static void bios_config_component(arc_config_t *);
57static void bios_config_subtree(arc_config_t *);
58
59char arc_vendor_id[sizeof(((arc_sid_t *)0)->vendor) + 1];
60unsigned char arc_product_id[sizeof(((arc_sid_t *)0)->prodid)];
61
62char arc_id[64 + 1];
63
64char arc_displayc_id[64 + 1];		/* DisplayController id */
65arc_dsp_stat_t	arc_displayinfo;	/* Save area for display status info. */
66
67int arc_cpu_l2cache_size = 0;
68
69/*
70 *	ARC Bios trampoline code.
71 */
72#define ARC_Call(Name,Offset)	\
73__asm("\n"			\
74"	.text\n"		\
75"	.ent	" #Name "\n"	\
76"	.align	3\n"		\
77"	.set	noreorder\n"	\
78"	.globl	" #Name "\n" 	\
79#Name":\n"			\
80"	lw	$2, 0x80001020\n"\
81"	lw	$2," #Offset "($2)\n"\
82"	jr	$2\n"		\
83"	nop\n"			\
84"	.end	" #Name "\n"	);
85
86ARC_Call(Bios_Load,			0x00);
87ARC_Call(Bios_Invoke,			0x04);
88ARC_Call(Bios_Execute,			0x08);
89ARC_Call(Bios_Halt,			0x0c);
90ARC_Call(Bios_PowerDown,		0x10);
91ARC_Call(Bios_Restart,			0x14);
92ARC_Call(Bios_Reboot,			0x18);
93ARC_Call(Bios_EnterInteractiveMode,	0x1c);
94ARC_Call(Bios_Unused1,			0x20);	/* return_from_main? */
95ARC_Call(Bios_GetPeer,			0x24);
96ARC_Call(Bios_GetChild,			0x28);
97ARC_Call(Bios_GetParent,		0x2c);
98ARC_Call(Bios_GetConfigurationData,	0x30);
99ARC_Call(Bios_AddChild,			0x34);
100ARC_Call(Bios_DeleteComponent,		0x38);
101ARC_Call(Bios_GetComponent,		0x3c);
102ARC_Call(Bios_SaveConfiguration,	0x40);
103ARC_Call(Bios_GetSystemId,		0x44);
104ARC_Call(Bios_GetMemoryDescriptor,	0x48);
105ARC_Call(Bios_Unused2,			0x4c);	/* signal??? */
106ARC_Call(Bios_GetTime,			0x50);
107ARC_Call(Bios_GetRelativeTime,		0x54);
108ARC_Call(Bios_GetDirectoryEntry,	0x58);
109ARC_Call(Bios_Open,			0x5c);
110ARC_Call(Bios_Close,			0x60);
111ARC_Call(Bios_Read,			0x64);
112ARC_Call(Bios_GetReadStatus,		0x68);
113ARC_Call(Bios_Write,			0x6c);
114ARC_Call(Bios_Seek,			0x70);
115ARC_Call(Bios_Mount,			0x74);
116ARC_Call(Bios_GetEnvironmentVariable,	0x78);
117ARC_Call(Bios_SetEnvironmentVariable,	0x7c);
118ARC_Call(Bios_GetFileInformation,	0x80);
119ARC_Call(Bios_SetFileInformation,	0x84);
120ARC_Call(Bios_FlushAllCaches,		0x88);
121/* note: the followings don't exist on SGI */
122#ifdef arc
123ARC_Call(Bios_TestUnicodeCharacter,	0x8c);
124ARC_Call(Bios_GetDisplayStatus,		0x90);
125#endif
126
127/*
128 *	BIOS based console, for early stage.
129 */
130
131int  biosgetc(dev_t);
132void biosputc(dev_t, int);
133
134/* this is to fake out the console routines, while booting. */
135struct consdev bioscons = {
136	NULL, NULL, biosgetc, biosputc, nullcnpollc, NULL, NULL,
137	    NULL, NODEV, CN_DEAD
138};
139
140int
141biosgetc(dev_t dev)
142{
143	int cnt;
144	char buf;
145
146	if (Bios_Read(0, &buf, 1, &cnt) != arc_ESUCCESS)
147		return -1;
148	return buf & 255;
149}
150
151void
152biosputc(dev_t dev, int ch)
153{
154	int cnt;
155	char buf;
156
157	buf = ch;
158	Bios_Write(1, &buf, 1, &cnt);
159}
160
161void
162bios_init_console(void)
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 */
180int
181bios_configure_memory(int *mem_reserved, phys_ram_seg_t *mem_clusters,
182    int *mem_cluster_cnt_return)
183{
184	int bios_physmem = 0;		/* Total physical memory size */
185	int mem_cluster_cnt = 0;
186
187	arc_mem_t *descr = NULL;
188	paddr_t seg_start, seg_end;
189	int i, reserved;
190
191	while ((descr = Bios_GetMemoryDescriptor(descr)) != NULL) {
192		seg_start = descr->BasePage * 4096;
193		seg_end = seg_start + descr->PageCount * 4096;
194
195#ifdef BIOS_MEMORY_DEBUG
196		printf("memory type:%d, 0x%8lx..%8lx, size:%8ld bytes\n",
197		    descr->Type, (u_long)seg_start, (u_long)seg_end,
198		    (u_long)(seg_end - seg_start));
199#endif
200
201		switch (descr->Type) {
202		case BadMemory:		/* Have no use for these */
203			break;
204
205		case ExeceptionBlock:
206		case SystemParameterBlock:
207		case FirmwarePermanent:
208			reserved = 1;
209			goto account_it;
210
211		case FreeMemory:
212		case LoadedProgram:	/* This is the loaded kernel */
213		case FirmwareTemporary:
214		case FreeContigous:
215			reserved = 0;
216account_it:
217			bios_physmem += descr->PageCount * 4096;
218
219			for (i = 0; i < mem_cluster_cnt; ) {
220				if (mem_reserved[i] == reserved &&
221				    mem_clusters[i].start == seg_end)
222					seg_end += mem_clusters[i].size;
223				else if (mem_reserved[i] == reserved &&
224				    mem_clusters[i].start +
225				    mem_clusters[i].size == seg_start)
226					seg_start = mem_clusters[i].start;
227				else { /* do not merge the cluster */
228					i++;
229					continue;
230				}
231				--mem_cluster_cnt;
232				mem_reserved[i] = mem_reserved[mem_cluster_cnt];
233				mem_clusters[i] = mem_clusters[mem_cluster_cnt];
234			}
235			/* assert(i == mem_cluster_cnt); */
236			if (mem_cluster_cnt >= VM_PHYSSEG_MAX) {
237				printf("VM_PHYSSEG_MAX too small\n");
238				for (;;)
239					;
240			}
241			mem_reserved[i] = reserved;
242			mem_clusters[i].start =	seg_start;
243			mem_clusters[i].size = seg_end - seg_start;
244			mem_cluster_cnt++;
245			break;
246
247		default:		/* Unknown type, leave it alone... */
248			break;
249		}
250	}
251
252#ifdef BIOS_MEMORY_DEBUG
253	for (i = 0; i < mem_cluster_cnt; i++)
254		printf("mem_clusters[%d] = %d:{ 0x%8lx, 0x%8lx }\n", i,
255		    mem_reserved[i],
256		    (long)mem_clusters[i].start,
257		    (long)mem_clusters[i].size);
258	printf("physmem = %d\n", bios_physmem);
259#endif
260
261	*mem_cluster_cnt_return = mem_cluster_cnt;
262	return bios_physmem;
263}
264
265/*
266 * ARC Firmware present?
267 */
268int
269bios_ident(void)
270{
271
272	return (ArcBiosBase->magic == ARC_PARAM_BLK_MAGIC) ||
273	    (ArcBiosBase->magic == ARC_PARAM_BLK_MAGIC_BUG);
274}
275
276/*
277 * save various information of BIOS for future use.
278 */
279
280static void
281bios_config_id_copy(arc_config_t *cf, char *string, size_t size)
282{
283
284	size--;
285	if (size > cf->id_len)
286		size = cf->id_len;
287	memcpy(string, cf->id, size);
288	string[size] = '\0';
289}
290
291static void
292bios_config_component(arc_config_t *cf)
293{
294
295	switch (cf->class) {
296	case arc_SystemClass:
297		if (cf->type == arc_System)
298			bios_config_id_copy(cf, arc_id, sizeof(arc_id));
299		break;
300	case arc_CacheClass:
301		if (cf->type == arc_SecondaryDcache)
302			arc_cpu_l2cache_size = 4096 << (cf->key & 0xffff);
303		break;
304	case arc_ControllerClass:
305		if (cf->type == arc_DisplayController &&
306		    arc_displayc_id[0] == '\0' /* first found one. XXX */)
307			bios_config_id_copy(cf, arc_displayc_id,
308			    sizeof(arc_displayc_id));
309		break;
310	default:
311		break;
312	}
313}
314
315static
316void bios_config_subtree(arc_config_t *cf)
317{
318
319	for (cf = Bios_GetChild(cf); cf != NULL; cf = Bios_GetPeer(cf)) {
320		bios_config_component(cf);
321		bios_config_subtree(cf);
322	}
323}
324
325void
326bios_save_info(void)
327{
328	arc_sid_t *sid;
329
330	sid = Bios_GetSystemId();
331	if (sid) {
332		memcpy(arc_vendor_id, sid->vendor, sizeof(arc_vendor_id) - 1);
333		arc_vendor_id[sizeof(arc_vendor_id) - 1] = 0;
334		memcpy(arc_product_id, sid->prodid, sizeof(arc_product_id));
335	}
336
337	bios_config_subtree(NULL);
338
339#ifdef arc
340	arc_displayinfo = *Bios_GetDisplayStatus(1);
341#endif
342}
343
344#ifdef arc
345/*
346 * Return geometry of the display. Used by pccons.c to set up the
347 * display configuration.
348 */
349void
350bios_display_info(int *xpos, int *ypos, int *xsize, int *ysize)
351{
352
353	*xpos = arc_displayinfo.CursorXPosition;
354	*ypos = arc_displayinfo.CursorYPosition;
355	*xsize = arc_displayinfo.CursorMaxXPosition;
356	*ysize = arc_displayinfo.CursorMaxYPosition;
357}
358#endif
359