xref: /netbsd/sys/arch/powerpc/powerpc/ofw_machdep.c (revision 6550d01e)
1 /*	$NetBSD: ofw_machdep.c,v 1.18 2008/03/27 18:01:08 phx Exp $	*/
2 
3 /*
4  * Copyright (C) 1996 Wolfgang Solfrank.
5  * Copyright (C) 1996 TooLs GmbH.
6  * 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. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: ofw_machdep.c,v 1.18 2008/03/27 18:01:08 phx Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/buf.h>
39 #include <sys/conf.h>
40 #include <sys/device.h>
41 #include <sys/disk.h>
42 #include <sys/disklabel.h>
43 #include <sys/fcntl.h>
44 #include <sys/ioctl.h>
45 #include <sys/malloc.h>
46 #include <sys/stat.h>
47 #include <sys/systm.h>
48 
49 #include <dev/ofw/openfirm.h>
50 
51 #include <machine/powerpc.h>
52 #include <machine/autoconf.h>
53 
54 #define	OFMEM_REGIONS	32
55 static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
56 
57 /*
58  * This is called during initppc, before the system is really initialized.
59  * It shall provide the total and the available regions of RAM.
60  * Both lists must have a zero-size entry as terminator.
61  * The available regions need not take the kernel into account, but needs
62  * to provide space for two additional entry beyond the terminating one.
63  */
64 void
65 mem_regions(struct mem_region **memp, struct mem_region **availp)
66 {
67 	int phandle, i, cnt, regcnt;
68 	struct mem_region_avail {
69 		paddr_t start;
70 		paddr_t size;
71 	} OFavail_G5[OFMEM_REGIONS + 3] __attribute((unused));
72 
73 	/*
74 	 * Get memory.
75 	 */
76 	if ((phandle = OF_finddevice("/memory")) == -1)
77 		goto error;
78 
79 	memset(OFmem, 0, sizeof OFmem);
80 	regcnt = OF_getprop(phandle, "reg",
81 		OFmem, sizeof OFmem[0] * OFMEM_REGIONS);
82 	if (regcnt <= 0)
83 		goto error;
84 
85 	/* Remove zero sized entry in the returned data. */
86 	regcnt /= sizeof OFmem[0];
87 	for (i = 0; i < regcnt; )
88 		if (OFmem[i].size == 0) {
89 			memmove(&OFmem[i], &OFmem[i + 1],
90 				(regcnt - i) * sizeof OFmem[0]);
91 			regcnt--;
92 		} else
93 			i++;
94 
95 #if defined (PMAC_G5)
96 	/* XXXSL: the G5 implementation of OFW is defines the /memory reg/available
97 	 * properties differently. Try to fix it up here with minimal damage to the
98 	 * rest of the code
99  	 */
100 	{
101 		int count;
102 		memset(OFavail_G5, 0, sizeof OFavail_G5);
103 		count = OF_getprop(phandle, "available",
104 			OFavail_G5, sizeof OFavail_G5[0] * OFMEM_REGIONS);
105 
106 		if (count <= 0)
107 			goto error;
108 
109 		count /= sizeof OFavail_G5[0];
110 		cnt = count * sizeof(OFavail[0]);
111 
112 		for (i = 0; i < count; i++ )
113 		{
114 			OFavail[i].start_hi = 0;
115 			OFavail[i].start = OFavail_G5[i].start;
116 			OFavail[i].size = OFavail_G5[i].size;
117 		}
118 	}
119 #else
120 	memset(OFavail, 0, sizeof OFavail);
121 	cnt = OF_getprop(phandle, "available",
122 		OFavail, sizeof OFavail[0] * OFMEM_REGIONS);
123 #endif
124 	if (cnt <= 0)
125 		goto error;
126 
127 	cnt /= sizeof OFavail[0];
128 	for (i = 0; i < cnt; ) {
129 		if (OFavail[i].size == 0) {
130 			memmove(&OFavail[i], &OFavail[i + 1],
131 				(cnt - i) * sizeof OFavail[0]);
132 			cnt--;
133 		} else
134 			i++;
135 	}
136 
137 	if (strncmp(model_name, "Pegasos", 7) == 0) {
138 		/*
139 		 * Some versions of SmartFirmware, only recognize the first
140 		 * 256MB segment as available. Work around it and add an
141 		 * extra entry to OFavail[] to account for this.
142 		 */
143 #define AVAIL_THRESH (0x10000000-1)
144 		if (((OFavail[cnt-1].start + OFavail[cnt-1].size +
145 		    AVAIL_THRESH) & ~AVAIL_THRESH) <
146 		    (OFmem[regcnt-1].start + OFmem[regcnt-1].size)) {
147 
148 			OFavail[cnt].start =
149 			    (OFavail[cnt-1].start + OFavail[cnt-1].size +
150 			    AVAIL_THRESH) & ~AVAIL_THRESH;
151 			OFavail[cnt].size =
152 			    OFmem[regcnt-1].size - OFavail[cnt].start;
153 			aprint_normal("WARNING: add memory segment %lx - %lx,"
154 			    "\nWARNING: which was not recognized by "
155 			    "the Firmware.\n",
156 			    (unsigned long)OFavail[cnt].start,
157 			    (unsigned long)OFavail[cnt].start +
158 			    OFavail[cnt].size);
159 			cnt++;
160 		}
161 	}
162 
163 	*memp = OFmem;
164 	*availp = OFavail;
165 	return;
166 
167 error:
168 #if defined (MAMBO)
169 	printf("no memory, assuming 512MB\n");
170 
171 	OFmem[0].start = 0x0;
172 	OFmem[0].size = 0x20000000;
173 
174 	OFavail[0].start = 0x3000;
175 	OFavail[0].size = 0x20000000 - 0x3000;
176 
177 	*memp = OFmem;
178 	*availp = OFavail;
179 #else
180 	panic("no memory?");
181 #endif
182 	return;
183 }
184 
185 void
186 ppc_exit(void)
187 {
188 	OF_exit();
189 }
190 
191 void
192 ppc_boot(char *str)
193 {
194 	OF_boot(str);
195 }
196