Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:09

0001 /*
0002  * Copyright (c) 2005 Martin Decky
0003  * All rights reserved.
0004  *
0005  * Redistribution and use in source and binary forms, with or without
0006  * modification, are permitted provided that the following conditions
0007  * are met:
0008  *
0009  * - Redistributions of source code must retain the above copyright
0010  *   notice, this list of conditions and the following disclaimer.
0011  * - Redistributions in binary form must reproduce the above copyright
0012  *   notice, this list of conditions and the following disclaimer in the
0013  *   documentation and/or other materials provided with the distribution.
0014  * - The name of the author may not be used to endorse or promote products
0015  *   derived from this software without specific prior written permission.
0016  *
0017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0027  */
0028 
0029 /*
0030  * Modifications are made to compile for RTEMS. Removes asm.h and printf.h.
0031  * Adds asm.h (rtems bsp). Adds ofw_read() and ofw_stdin variable. Uses 
0032  * printk instead of puts for error messages.
0033  *
0034  */
0035 
0036 #include <bsp.h>
0037 #include <rtems/bspIo.h>
0038 
0039 #include <boot/ofw.h>
0040 #include <boot/ofwarch.h>
0041 #if 0
0042 #include <boot/printf.h>
0043 #include <boot/asm.h>
0044 #endif
0045 #include <boot/types.h>
0046 #include <string.h>
0047 #include <asm.h>
0048 
0049 #define RED(i)    (((i) >> 5) & ((1 << 3) - 1))
0050 #define GREEN(i)  (((i) >> 3) & ((1 << 2) - 1))
0051 #define BLUE(i)   ((i) & ((1 << 3) - 1))
0052 #define CLIP(i)   ((i) <= 255 ? (i) : 255)
0053 
0054 uintptr_t ofw_cif;
0055 
0056 phandle ofw_chosen;
0057 ihandle ofw_stdout;
0058 ihandle ofw_stdin;
0059 
0060 phandle ofw_root;
0061 ihandle ofw_mmu;
0062 ihandle ofw_memory_prop;
0063 phandle ofw_memory;
0064 
0065 void ofw_init(void)
0066 {
0067     ofw_chosen = ofw_find_device("/chosen");
0068     if (ofw_chosen == -1)
0069         halt();
0070     
0071     if (ofw_get_property(ofw_chosen, "stdout", &ofw_stdout,
0072         sizeof(ofw_stdout)) <= 0)
0073         ofw_stdout = 0;
0074     
0075   if (ofw_get_property(ofw_chosen, "stdin", &ofw_stdin,
0076         sizeof(ofw_stdin)) <= 0)
0077         ofw_stdin = 0;
0078 
0079     ofw_root = ofw_find_device("/");
0080     if (ofw_root == -1) {
0081         printk("\r\nError: Unable to find / device, halted.\r\n");
0082         halt();
0083     }
0084     
0085     if (ofw_get_property(ofw_chosen, "mmu", &ofw_mmu,
0086         sizeof(ofw_mmu)) <= 0) {
0087         printk("\r\nError: Unable to get mmu property, halted.\r\n");
0088         halt();
0089     }
0090     if (ofw_get_property(ofw_chosen, "memory", &ofw_memory_prop,
0091         sizeof(ofw_memory_prop)) <= 0) {
0092         printk("\r\nError: Unable to get memory property, halted.\r\n");
0093         halt();
0094     }
0095     
0096     ofw_memory = ofw_find_device("/memory");
0097     if (ofw_memory == -1) {
0098         printk("\r\nError: Unable to find /memory device, halted.\r\n");
0099         halt();
0100     }
0101 }
0102 
0103 /** Perform a call to OpenFirmware client interface.
0104  *
0105  * @param service String identifying the service requested.
0106  * @param nargs   Number of input arguments.
0107  * @param nret    Number of output arguments. This includes the return
0108  *                value.
0109  * @param rets    Buffer for output arguments or NULL. The buffer must
0110  *                accommodate nret - 1 items.
0111  *
0112  * @return Return value returned by the client interface.
0113  *
0114  */
0115 unsigned long
0116 ofw_call(const char *service, const int nargs, const int nret, ofw_arg_t *rets,
0117     ...)
0118 {
0119     va_list list;
0120     ofw_args_t args;
0121     int i;
0122     
0123     args.service = (ofw_arg_t) service;
0124     args.nargs = nargs;
0125     args.nret = nret;
0126     
0127     va_start(list, rets);
0128     for (i = 0; i < nargs; i++)
0129         args.args[i] = va_arg(list, ofw_arg_t);
0130     va_end(list);
0131     
0132     for (i = 0; i < nret; i++)
0133         args.args[i + nargs] = 0;
0134     
0135     (void) ofw(&args);
0136 
0137     for (i = 1; i < nret; i++)
0138         rets[i - 1] = args.args[i + nargs];
0139 
0140     return args.args[nargs];
0141 }
0142 
0143 phandle ofw_find_device(const char *name)
0144 {
0145     return ofw_call("finddevice", 1, 1, NULL, name);
0146 }
0147 
0148 int ofw_get_property(const phandle device, const char *name, void *buf,
0149     const int buflen)
0150 {
0151     return ofw_call("getprop", 4, 1, NULL, device, name, buf, buflen);
0152 }
0153 
0154 int ofw_get_proplen(const phandle device, const char *name)
0155 {
0156     return ofw_call("getproplen", 2, 1, NULL, device, name);
0157 }
0158 
0159 int ofw_next_property(const phandle device, char *previous, char *buf)
0160 {
0161     return ofw_call("nextprop", 3, 1, NULL, device, previous, buf);
0162 }
0163 
0164 int ofw_package_to_path(const phandle device, char *buf, const int buflen)
0165 {
0166     return ofw_call("package-to-path", 3, 1, NULL, device, buf, buflen);
0167 }
0168 
0169 unsigned int ofw_get_address_cells(const phandle device)
0170 {
0171     unsigned int ret = 1;
0172     
0173     if (ofw_get_property(device, "#address-cells", &ret, sizeof(ret)) <= 0)
0174         if (ofw_get_property(ofw_root, "#address-cells", &ret,
0175             sizeof(ret)) <= 0)
0176             ret = OFW_ADDRESS_CELLS;
0177     
0178     return ret;
0179 }
0180 
0181 unsigned int ofw_get_size_cells(const phandle device)
0182 {
0183     unsigned int ret;
0184     
0185     if (ofw_get_property(device, "#size-cells", &ret, sizeof(ret)) <= 0)
0186         if (ofw_get_property(ofw_root, "#size-cells", &ret,
0187             sizeof(ret)) <= 0)
0188             ret = OFW_SIZE_CELLS;
0189     
0190     return ret;
0191 }
0192 
0193 phandle ofw_get_child_node(const phandle node)
0194 {
0195     return ofw_call("child", 1, 1, NULL, node);
0196 }
0197 
0198 phandle ofw_get_peer_node(const phandle node)
0199 {
0200     return ofw_call("peer", 1, 1, NULL, node);
0201 }
0202 
0203 static ihandle ofw_open(const char *name)
0204 {
0205     return ofw_call("open", 1, 1, NULL, name);
0206 }
0207 
0208 
0209 void ofw_write(const char *str, const int len)
0210 {
0211     if (ofw_stdout == 0)
0212         return;
0213     
0214     ofw_call("write", 3, 1, NULL, ofw_stdout, str, len);
0215 }
0216 
0217 void ofw_read(void *str, const int len)
0218 {
0219   if (ofw_stdin == 0)
0220     return;
0221 
0222   ofw_call("read", 3, 1, NULL, ofw_stdin, str, len);
0223 }
0224 
0225 void *ofw_translate(const void *virt)
0226 {
0227     ofw_arg_t result[4];
0228     int shift;
0229 
0230     if (ofw_call("call-method", 4, 5, result, "translate", ofw_mmu,
0231         virt, 0) != 0) {
0232         printk("Error: MMU method translate() failed, halting.\n");
0233         halt();
0234     }
0235 
0236     if (ofw_translate_failed(result[0]))
0237         return NULL;
0238 
0239     if (sizeof(unative_t) == 8)
0240         shift = 32;
0241     else
0242         shift = 0;
0243 
0244     return (void *) ((result[2] << shift) | result[3]);
0245 }
0246 
0247 void *ofw_claim_virt(const void *virt, const unsigned int len)
0248 {
0249     ofw_arg_t retaddr;
0250 
0251     if (ofw_call("call-method", 5, 2, &retaddr, "claim", ofw_mmu, 0, len,
0252         virt) != 0) {
0253         printk("Error: MMU method claim() failed, halting.\n");
0254         halt();
0255     }
0256 
0257     return (void *) retaddr;
0258 }
0259 
0260 static void *ofw_claim_phys_internal(const void *phys, const unsigned int len, const unsigned int alignment)
0261 {
0262     /*
0263      * Note that the return value check will help
0264      * us to discover conflicts between OpenFirmware
0265      * allocations and our use of physical memory.
0266      * It is better to detect collisions here
0267      * than to cope with weird errors later.
0268      *
0269      * So this is really not to make the loader
0270      * more generic; it is here for debugging
0271      * purposes.
0272      */
0273     
0274     if (sizeof(unative_t) == 8) {
0275         ofw_arg_t retaddr[2];
0276         int shift = 32;
0277         
0278         if (ofw_call("call-method", 6, 3, retaddr, "claim",
0279             ofw_memory_prop, alignment, len, ((uintptr_t) phys) >> shift,
0280             ((uintptr_t) phys) & ((uint32_t) -1)) != 0) {
0281             printk("Error: memory method claim() failed, halting.\n");
0282             halt();
0283         }
0284         
0285         return (void *) ((retaddr[0] << shift) | retaddr[1]);
0286     } else {
0287         ofw_arg_t retaddr[1];
0288         
0289         if (ofw_call("call-method", 5, 2, retaddr, "claim",
0290             ofw_memory_prop, alignment, len, (uintptr_t) phys) != 0) {
0291             printk("Error: memory method claim() failed, halting.\n");
0292             halt();
0293         }
0294         
0295         return (void *) retaddr[0];
0296     }
0297 }
0298 
0299 void *ofw_claim_phys(const void *phys, const unsigned int len)
0300 {
0301     return ofw_claim_phys_internal(phys, len, 0);
0302 }
0303 
0304 void *ofw_claim_phys_any(const unsigned int len, const unsigned int alignment)
0305 {
0306     return ofw_claim_phys_internal(NULL, len, alignment);
0307 }
0308 
0309 int ofw_map(const void *phys, const void *virt, const unsigned int size, const int mode)
0310 {
0311     uintptr_t phys_hi, phys_lo;
0312 
0313     if (sizeof(unative_t) == 8) {
0314         int shift = 32;
0315         phys_hi = (uintptr_t) phys >> shift;
0316         phys_lo = (uintptr_t) phys & 0xffffffff;
0317     } else {
0318         phys_hi = 0;
0319         phys_lo = (uintptr_t) phys;
0320     }
0321 
0322     return ofw_call("call-method", 7, 1, NULL, "map", ofw_mmu, mode, size,
0323         virt, phys_hi, phys_lo);
0324 }
0325 
0326 /** Save OpenFirmware physical memory map.
0327  *
0328  * @param map Memory map structure where the map will be saved.
0329  *
0330  * @return Zero on failure, non-zero on success.
0331  */
0332 int ofw_memmap(memmap_t *map)
0333 {
0334     unsigned int ac = ofw_get_address_cells(ofw_memory) /
0335         (sizeof(uintptr_t) / sizeof(uint32_t));
0336     unsigned int sc = ofw_get_size_cells(ofw_memory) /
0337         (sizeof(uintptr_t) / sizeof(uint32_t));
0338 
0339     uintptr_t buf[((ac + sc) * MEMMAP_MAX_RECORDS)];
0340     int ret = ofw_get_property(ofw_memory, "reg", buf, sizeof(buf));
0341     if (ret <= 0)       /* ret is the number of written bytes */
0342         return false;
0343 
0344     int pos;
0345     map->total = 0;
0346     map->count = 0;
0347     for (pos = 0; (pos < ret / sizeof(uintptr_t)) &&
0348         (map->count < MEMMAP_MAX_RECORDS); pos += ac + sc) {
0349         void *start = (void *) (buf[pos + ac - 1]);
0350         unsigned int size = buf[pos + ac + sc - 1];
0351 
0352         /*
0353          * This is a hot fix of the issue which occurs on machines
0354          * where there are holes in the physical memory (such as
0355          * SunBlade 1500). Should we detect a hole in the physical
0356          * memory, we will ignore any memory detected behind
0357          * the hole and pretend the hole does not exist.
0358          */
0359         if ((map->count > 0) && (map->zones[map->count - 1].start +
0360             map->zones[map->count - 1].size < start))
0361             break;
0362 
0363         if (size > 0) {
0364             map->zones[map->count].start = start;
0365             map->zones[map->count].size = size;
0366             map->count++;
0367             map->total += size;
0368         }
0369     }
0370     
0371     return true;
0372 }
0373 
0374 static void ofw_setup_screen(phandle handle)
0375 {
0376     /* Check for device type */
0377     char device_type[OFW_TREE_PROPERTY_MAX_VALUELEN];
0378     if (ofw_get_property(handle, "device_type", device_type, OFW_TREE_PROPERTY_MAX_VALUELEN) <= 0)
0379         return;
0380     
0381     device_type[OFW_TREE_PROPERTY_MAX_VALUELEN - 1] = '\0';
0382     if (strcmp(device_type, "display") != 0)
0383         return;
0384     
0385     /* Check for 8 bit depth */
0386     uint32_t depth;
0387     if (ofw_get_property(handle, "depth", &depth, sizeof(uint32_t)) <= 0)
0388         depth = 0;
0389     
0390     /* Get device path */
0391     static char path[OFW_TREE_PATH_MAX_LEN + 1];
0392     size_t len = ofw_package_to_path(handle, path, OFW_TREE_PATH_MAX_LEN);
0393     if (len == -1)
0394         return;
0395     
0396     path[len] = '\0';
0397     
0398     /* Open the display to initialize it */
0399     ihandle screen = ofw_open(path);
0400     if (screen == -1)
0401         return;
0402     
0403     if (depth == 8) {
0404         /* Setup the palette so that the (inverted) 3:2:3 scheme is usable */
0405         unsigned int i;
0406         for (i = 0; i < 256; i++) {
0407             ofw_call("call-method", 6, 1, NULL, "color!", screen,
0408                 255 - i, CLIP(BLUE(i) * 37), GREEN(i) * 85, CLIP(RED(i) * 37));
0409         }
0410     }
0411 }
0412 
0413 static void ofw_setup_screens_internal(phandle current)
0414 {
0415     while ((current != 0) && (current != -1)) {
0416         ofw_setup_screen(current);
0417         
0418         /*
0419          * Recursively process the potential child node.
0420          */
0421         phandle child = ofw_get_child_node(current);
0422         if ((child != 0) && (child != -1))
0423             ofw_setup_screens_internal(child);
0424         
0425         /*
0426          * Iteratively process the next peer node.
0427          * Note that recursion is a bad idea here.
0428          * Due to the topology of the OpenFirmware device tree,
0429          * the nesting of peer nodes could be to wide and the
0430          * risk of overflowing the stack is too real.
0431          */
0432         phandle peer = ofw_get_peer_node(current);
0433         if ((peer != 0) && (peer != -1)) {
0434             current = peer;
0435             /*
0436              * Process the peer in next iteration.
0437              */
0438             continue;
0439         }
0440         
0441         /*
0442          * No more peers on this level.
0443          */
0444         break;
0445     }
0446 }
0447 
0448 /** Setup all screens which can be detected.
0449  *
0450  * Open all screens which can be detected and set up the palette for the 8-bit
0451  * color depth configuration so that the 3:2:3 color scheme can be used.
0452  * Check that setting the palette makes sense (the color depth is not greater
0453  * than 8).
0454  *
0455  */
0456 void ofw_setup_screens(void)
0457 {
0458     ofw_setup_screens_internal(ofw_root);
0459 }
0460 
0461 void ofw_quiesce(void)
0462 {
0463     ofw_call("quiesce", 0, 0, NULL);
0464 }