source: mainline/boot/genarch/ofw.c@ a1d89ad

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a1d89ad was fd375a8d, checked in by Martin Decky <martin@…>, 17 years ago

more exact RGB323 palette calculation
set the RGB323 palette on ppc32

  • Property mode set to 100644
File size: 10.8 KB
RevLine 
[ce8725be]1/*
[df4ed85]2 * Copyright (c) 2005 Martin Decky
[ce8725be]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
[fd375a8d]28
[63cda71]29#include <ofw.h>
30#include <ofwarch.h>
[ce8725be]31#include <printf.h>
32#include <asm.h>
[822b64e]33#include <types.h>
[ce8725be]34
[2e672fd]35uintptr_t ofw_cif;
[ce8725be]36
37phandle ofw_chosen;
38ihandle ofw_stdout;
39phandle ofw_root;
40ihandle ofw_mmu;
[95b47c82]41ihandle ofw_memory_prop;
[ce8725be]42phandle ofw_memory;
43phandle ofw_aliases;
44
[63cda71]45void ofw_init(void)
46{
47 ofw_chosen = ofw_find_device("/chosen");
48 if (ofw_chosen == -1)
49 halt();
50
[965dc18]51 if (ofw_get_property(ofw_chosen, "stdout", &ofw_stdout,
52 sizeof(ofw_stdout)) <= 0)
[63cda71]53 ofw_stdout = 0;
54
55 ofw_root = ofw_find_device("/");
56 if (ofw_root == -1) {
57 puts("\r\nError: Unable to find / device, halted.\r\n");
58 halt();
59 }
60
[965dc18]61 if (ofw_get_property(ofw_chosen, "mmu", &ofw_mmu,
62 sizeof(ofw_mmu)) <= 0) {
[63cda71]63 puts("\r\nError: Unable to get mmu property, halted.\r\n");
64 halt();
65 }
[965dc18]66 if (ofw_get_property(ofw_chosen, "memory", &ofw_memory_prop,
67 sizeof(ofw_memory_prop)) <= 0) {
[95b47c82]68 puts("\r\nError: Unable to get memory property, halted.\r\n");
69 halt();
70 }
[63cda71]71
72 ofw_memory = ofw_find_device("/memory");
73 if (ofw_memory == -1) {
74 puts("\r\nError: Unable to find /memory device, halted.\r\n");
75 halt();
76 }
77
78 ofw_aliases = ofw_find_device("/aliases");
79 if (ofw_aliases == -1) {
80 puts("\r\nError: Unable to find /aliases device, halted.\r\n");
81 halt();
82 }
83}
84
[94d614e]85/** Perform a call to OpenFirmware client interface.
86 *
[965dc18]87 * @param service String identifying the service requested.
88 * @param nargs Number of input arguments.
89 * @param nret Number of output arguments. This includes the return
90 * value.
91 * @param rets Buffer for output arguments or NULL. The buffer must
92 * accommodate nret - 1 items.
[94d614e]93 *
[965dc18]94 * @return Return value returned by the client interface.
[94d614e]95 */
[965dc18]96unsigned long
97ofw_call(const char *service, const int nargs, const int nret, ofw_arg_t *rets,
98 ...)
[ce8725be]99{
100 va_list list;
101 ofw_args_t args;
102 int i;
103
[94d614e]104 args.service = (ofw_arg_t) service;
[ce8725be]105 args.nargs = nargs;
106 args.nret = nret;
107
108 va_start(list, rets);
109 for (i = 0; i < nargs; i++)
110 args.args[i] = va_arg(list, ofw_arg_t);
111 va_end(list);
112
113 for (i = 0; i < nret; i++)
114 args.args[i + nargs] = 0;
115
[2e672fd]116 (void) ofw(&args);
117
[ce8725be]118 for (i = 1; i < nret; i++)
119 rets[i - 1] = args.args[i + nargs];
[2e672fd]120
[ce8725be]121 return args.args[nargs];
122}
123
[b7b5f83]124phandle ofw_find_device(const char *name)
[ce8725be]125{
126 return ofw_call("finddevice", 1, 1, NULL, name);
127}
128
[965dc18]129int
130ofw_get_property(const phandle device, const char *name, void *buf,
131 const int buflen)
[ce8725be]132{
133 return ofw_call("getprop", 4, 1, NULL, device, name, buf, buflen);
134}
135
[3abe07f5]136int ofw_get_proplen(const phandle device, const char *name)
137{
138 return ofw_call("getproplen", 2, 1, NULL, device, name);
139}
140
141int ofw_next_property(const phandle device, char *previous, char *buf)
142{
143 return ofw_call("nextprop", 3, 1, NULL, device, previous, buf);
144}
[ce8725be]145
[16529d5]146int ofw_package_to_path(const phandle device, char *buf, const int buflen)
147{
148 return ofw_call("package-to-path", 3, 1, NULL, device, buf, buflen);
149}
150
[63cda71]151unsigned int ofw_get_address_cells(const phandle device)
[ce8725be]152{
[63cda71]153 unsigned int ret = 1;
[ce8725be]154
155 if (ofw_get_property(device, "#address-cells", &ret, sizeof(ret)) <= 0)
[965dc18]156 if (ofw_get_property(ofw_root, "#address-cells", &ret,
157 sizeof(ret)) <= 0)
[63cda71]158 ret = OFW_ADDRESS_CELLS;
[ce8725be]159
160 return ret;
161}
162
163
[63cda71]164unsigned int ofw_get_size_cells(const phandle device)
[ce8725be]165{
166 unsigned int ret;
167
168 if (ofw_get_property(device, "#size-cells", &ret, sizeof(ret)) <= 0)
[965dc18]169 if (ofw_get_property(ofw_root, "#size-cells", &ret,
170 sizeof(ret)) <= 0)
[63cda71]171 ret = OFW_SIZE_CELLS;
[ce8725be]172
173 return ret;
174}
175
[9a5b556]176phandle ofw_get_child_node(const phandle node)
177{
178 return ofw_call("child", 1, 1, NULL, node);
179}
180
181phandle ofw_get_peer_node(const phandle node)
182{
183 return ofw_call("peer", 1, 1, NULL, node);
184}
[ce8725be]185
186static ihandle ofw_open(const char *name)
187{
188 return ofw_call("open", 1, 1, NULL, name);
189}
190
191
192void ofw_write(const char *str, const int len)
193{
194 if (ofw_stdout == 0)
195 return;
196
197 ofw_call("write", 3, 1, NULL, ofw_stdout, str, len);
198}
199
200
201void *ofw_translate(const void *virt)
202{
[822b64e]203 ofw_arg_t result[4];
204 int shift;
205
[4bc73fa]206 if (ofw_call("call-method", 4, 5, result, "translate", ofw_mmu,
207 virt, 0) != 0) {
[ce8725be]208 puts("Error: MMU method translate() failed, halting.\n");
209 halt();
210 }
[822b64e]211
[2e672fd]212 if (ofw_translate_failed(result[0]))
213 return NULL;
214
[822b64e]215 if (sizeof(unative_t) == 8)
216 shift = 32;
217 else
218 shift = 0;
[63cda71]219
[95b47c82]220 return (void *) ((result[2] << shift) | result[3]);
[ce8725be]221}
222
[95b47c82]223void *ofw_claim_virt(const void *virt, const int len)
[2e672fd]224{
225 ofw_arg_t retaddr;
226
[965dc18]227 if (ofw_call("call-method", 5, 2, &retaddr, "claim", ofw_mmu, 0, len,
228 virt) != 0) {
[2e672fd]229 puts("Error: MMU method claim() failed, halting.\n");
230 halt();
231 }
232
233 return (void *) retaddr;
234}
[ce8725be]235
[95b47c82]236void *ofw_claim_phys(const void *phys, const int len)
237{
238 ofw_arg_t retaddr[2];
239 int shift;
240
241 if (sizeof(unative_t) == 8) {
242 shift = 32;
243 if (ofw_call("call-method", 6, 3, retaddr, "claim",
244 ofw_memory_prop, 0, len, ((uintptr_t) phys) >> shift,
245 ((uintptr_t) phys) & ((uint32_t) -1)) != 0) {
246 /*
247 * Note that this will help us to discover
248 * conflicts between OpenFirmware allocations
249 * and our use of physical memory.
250 * It is better to detect collisions here
251 * than to cope with weird errors later.
252 *
253 * So this is really not to make the loader
254 * more generic; it is here for debugging
255 * purposes.
256 */
257 puts("Error: memory method claim() failed, halting.\n");
258 halt();
259 }
260 } else {
261 shift = 0;
262 /*
263 * FIXME: the number of arguments is probably different...
264 */
265 puts("Error: 32-bit ofw_claim_phys not implemented.\n");
266 halt();
267 }
268
269 return (void *) ((retaddr[0] << shift) | retaddr[1]);
270}
271
[ce8725be]272int ofw_map(const void *phys, const void *virt, const int size, const int mode)
273{
[822b64e]274 uintptr_t phys_hi, phys_lo;
275
276 if (sizeof(unative_t) == 8) {
277 int shift = 32;
278 phys_hi = (uintptr_t) phys >> shift;
279 phys_lo = (uintptr_t) phys & 0xffffffff;
280 } else {
281 phys_hi = 0;
282 phys_lo = (uintptr_t) phys;
283 }
284
[965dc18]285 return ofw_call("call-method", 7, 1, NULL, "map", ofw_mmu, mode, size,
286 virt, phys_hi, phys_lo);
[ce8725be]287}
288
[771cd22]289/** Save OpenFirmware physical memory map.
290 *
291 * @param map Memory map structure where the map will be saved.
292 *
293 * @return Zero on failure, non-zero on success.
294 */
[ce8725be]295int ofw_memmap(memmap_t *map)
296{
[965dc18]297 unsigned int ac = ofw_get_address_cells(ofw_memory) /
298 (sizeof(uintptr_t) / sizeof(uint32_t));
299 unsigned int sc = ofw_get_size_cells(ofw_memory) /
300 (sizeof(uintptr_t) / sizeof(uint32_t));
[63cda71]301
[965dc18]302 uintptr_t buf[((ac + sc) * MEMMAP_MAX_RECORDS)];
[63cda71]303 int ret = ofw_get_property(ofw_memory, "reg", buf, sizeof(buf));
304 if (ret <= 0) /* ret is the number of written bytes */
305 return false;
306
[ce8725be]307 int pos;
308 map->total = 0;
309 map->count = 0;
[965dc18]310 for (pos = 0; (pos < ret / sizeof(uintptr_t)) &&
[95b47c82]311 (map->count < MEMMAP_MAX_RECORDS); pos += ac + sc) {
[965dc18]312 void *start = (void *) (buf[pos + ac - 1]);
[ce8725be]313 unsigned int size = buf[pos + ac + sc - 1];
[965dc18]314
315 /*
316 * This is a hot fix of the issue which occurs on machines
317 * where there are holes in the physical memory (such as
318 * SunBlade 1500). Should we detect a hole in the physical
319 * memory, we will ignore any memory detected behind
320 * the hole and pretend the hole does not exist.
321 */
322 if ((map->count > 0) && (map->zones[map->count - 1].start +
323 map->zones[map->count - 1].size < start))
324 break;
325
[ce8725be]326 if (size > 0) {
327 map->zones[map->count].start = start;
328 map->zones[map->count].size = size;
329 map->count++;
330 map->total += size;
331 }
332 }
[63cda71]333
334 return true;
[ce8725be]335}
336
337int ofw_screen(screen_t *screen)
338{
339 char device_name[BUF_SIZE];
[63cda71]340 uint32_t virtaddr;
[ce8725be]341
[965dc18]342 if (ofw_get_property(ofw_aliases, "screen", device_name,
343 sizeof(device_name)) <= 0)
[ce8725be]344 return false;
345
346 phandle device = ofw_find_device(device_name);
347 if (device == -1)
348 return false;
349
[965dc18]350 if (ofw_get_property(device, "address", &virtaddr,
351 sizeof(virtaddr)) <= 0)
[ce8725be]352 return false;
[63cda71]353
354 screen->addr = (void *) ((uintptr_t) virtaddr);
355
[965dc18]356 if (ofw_get_property(device, "width", &screen->width,
357 sizeof(screen->width)) <= 0)
[ce8725be]358 return false;
359
[965dc18]360 if (ofw_get_property(device, "height", &screen->height,
361 sizeof(screen->height)) <= 0)
[ce8725be]362 return false;
363
[965dc18]364 if (ofw_get_property(device, "depth", &screen->bpp,
365 sizeof(screen->bpp)) <= 0)
[ce8725be]366 return false;
367
[965dc18]368 if (ofw_get_property(device, "linebytes", &screen->scanline,
369 sizeof(screen->scanline)) <= 0)
[ce8725be]370 return false;
371
372 return true;
373}
[deb14fb]374
[fd375a8d]375#define RED(i) (((i) >> 5) & ((1 << 3) - 1))
376#define GREEN(i) (((i) >> 3) & ((1 << 2) - 1))
377#define BLUE(i) ((i) & ((1 << 3) - 1))
378#define CLIP(i) ((i) <= 255 ? (i) : 255)
379
380
[2b1f860]381/**
382 * Sets up the palette for the 8-bit color depth configuration so that the
383 * 3:2:3 color scheme can be used. Checks that setting the palette makes sense
384 * (appropriate nodes exist in the OBP tree and the color depth is not greater
[fd375a8d]385 * than 8).
386 *
387 * @return true if the palette has been set, false otherwise
[2b1f860]388 *
389 */
[fd375a8d]390int ofw_setup_palette(void)
[2b1f860]391{
392 char device_name[BUF_SIZE];
393
394 /* resolve alias */
395 if (ofw_get_property(ofw_aliases, "screen", device_name,
[fd375a8d]396 sizeof(device_name)) <= 0)
[2b1f860]397 return false;
[fd375a8d]398
[2b1f860]399 /* for depth greater than 8 it makes no sense to set up the palette */
400 uint32_t depth;
401 phandle device = ofw_find_device(device_name);
402 if (device == -1)
403 return false;
404 if (ofw_get_property(device, "depth", &depth, sizeof(uint32_t)) <= 0)
405 return false;
406 if (depth != 8)
407 return false;
408
409 /* required in order to be able to make a method call */
410 ihandle screen = ofw_open(device_name);
411 if (screen == -1)
412 return false;
[fd375a8d]413
[925fdd7]414 /* setup the palette so that the (inverted) 3:2:3 scheme is usable */
[2b1f860]415 unsigned int i;
416 for (i = 0; i < 256; i++)
[fd375a8d]417 ofw_call("call-method", 6, 1, NULL, "color!", screen,
418 255 - i, CLIP(BLUE(i) * 37), GREEN(i) * 85, CLIP(RED(i) * 37));
[2b1f860]419 return true;
420}
[deb14fb]421
422void ofw_quiesce(void)
423{
[282f2c9c]424 ofw_call("quiesce", 0, 0, NULL);
[deb14fb]425}
Note: See TracBrowser for help on using the repository browser.