linux/arch/sparc/kernel/prom_32.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Procedures for creating, accessing and interpreting the device tree.
   4 *
   5 * Paul Mackerras       August 1996.
   6 * Copyright (C) 1996-2005 Paul Mackerras.
   7 * 
   8 *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
   9 *    {engebret|bergner}@us.ibm.com 
  10 *
  11 *  Adapted for sparc32 by David S. Miller davem@davemloft.net
  12 */
  13
  14#include <linux/kernel.h>
  15#include <linux/types.h>
  16#include <linux/string.h>
  17#include <linux/mm.h>
  18#include <linux/memblock.h>
  19
  20#include <asm/prom.h>
  21#include <asm/oplib.h>
  22#include <asm/leon.h>
  23#include <asm/leon_amba.h>
  24
  25#include "prom.h"
  26
  27void * __init prom_early_alloc(unsigned long size)
  28{
  29        void *ret;
  30
  31        ret = memblock_alloc(size, SMP_CACHE_BYTES);
  32        if (!ret)
  33                panic("%s: Failed to allocate %lu bytes\n", __func__, size);
  34
  35        prom_early_allocated += size;
  36
  37        return ret;
  38}
  39
  40/* The following routines deal with the black magic of fully naming a
  41 * node.
  42 *
  43 * Certain well known named nodes are just the simple name string.
  44 *
  45 * Actual devices have an address specifier appended to the base name
  46 * string, like this "foo@addr".  The "addr" can be in any number of
  47 * formats, and the platform plus the type of the node determine the
  48 * format and how it is constructed.
  49 *
  50 * For children of the ROOT node, the naming convention is fixed and
  51 * determined by whether this is a sun4u or sun4v system.
  52 *
  53 * For children of other nodes, it is bus type specific.  So
  54 * we walk up the tree until we discover a "device_type" property
  55 * we recognize and we go from there.
  56 */
  57static void __init sparc32_path_component(struct device_node *dp, char *tmp_buf)
  58{
  59        const char *name = of_get_property(dp, "name", NULL);
  60        struct linux_prom_registers *regs;
  61        struct property *rprop;
  62
  63        rprop = of_find_property(dp, "reg", NULL);
  64        if (!rprop)
  65                return;
  66
  67        regs = rprop->value;
  68        sprintf(tmp_buf, "%s@%x,%x",
  69                name,
  70                regs->which_io, regs->phys_addr);
  71}
  72
  73/* "name@slot,offset"  */
  74static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
  75{
  76        const char *name = of_get_property(dp, "name", NULL);
  77        struct linux_prom_registers *regs;
  78        struct property *prop;
  79
  80        prop = of_find_property(dp, "reg", NULL);
  81        if (!prop)
  82                return;
  83
  84        regs = prop->value;
  85        sprintf(tmp_buf, "%s@%x,%x",
  86                name,
  87                regs->which_io,
  88                regs->phys_addr);
  89}
  90
  91/* "name@devnum[,func]" */
  92static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
  93{
  94        const char *name = of_get_property(dp, "name", NULL);
  95        struct linux_prom_pci_registers *regs;
  96        struct property *prop;
  97        unsigned int devfn;
  98
  99        prop = of_find_property(dp, "reg", NULL);
 100        if (!prop)
 101                return;
 102
 103        regs = prop->value;
 104        devfn = (regs->phys_hi >> 8) & 0xff;
 105        if (devfn & 0x07) {
 106                sprintf(tmp_buf, "%s@%x,%x",
 107                        name,
 108                        devfn >> 3,
 109                        devfn & 0x07);
 110        } else {
 111                sprintf(tmp_buf, "%s@%x",
 112                        name,
 113                        devfn >> 3);
 114        }
 115}
 116
 117/* "name@addrhi,addrlo" */
 118static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
 119{
 120        const char *name = of_get_property(dp, "name", NULL);
 121        struct linux_prom_registers *regs;
 122        struct property *prop;
 123
 124        prop = of_find_property(dp, "reg", NULL);
 125        if (!prop)
 126                return;
 127
 128        regs = prop->value;
 129
 130        sprintf(tmp_buf, "%s@%x,%x",
 131                name,
 132                regs->which_io, regs->phys_addr);
 133}
 134
 135/* "name@irq,addrlo" */
 136static void __init ambapp_path_component(struct device_node *dp, char *tmp_buf)
 137{
 138        const char *name = of_get_property(dp, "name", NULL);
 139        struct amba_prom_registers *regs;
 140        unsigned int *intr;
 141        unsigned int reg0;
 142        struct property *prop;
 143        int interrupt = 0;
 144
 145        /* In order to get a unique ID in the device tree (multiple AMBA devices
 146         * may have the same name) the node number is printed
 147         */
 148        prop = of_find_property(dp, "reg", NULL);
 149        if (!prop) {
 150                reg0 = (unsigned int)dp->phandle;
 151        } else {
 152                regs = prop->value;
 153                reg0 = regs->phys_addr;
 154        }
 155
 156        /* Not all cores have Interrupt */
 157        prop = of_find_property(dp, "interrupts", NULL);
 158        if (!prop)
 159                intr = &interrupt; /* IRQ0 does not exist */
 160        else
 161                intr = prop->value;
 162
 163        sprintf(tmp_buf, "%s@%x,%x", name, *intr, reg0);
 164}
 165
 166static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
 167{
 168        struct device_node *parent = dp->parent;
 169
 170        if (parent != NULL) {
 171                if (of_node_is_type(parent, "pci") ||
 172                    of_node_is_type(parent, "pciex"))
 173                        return pci_path_component(dp, tmp_buf);
 174                if (of_node_is_type(parent, "sbus"))
 175                        return sbus_path_component(dp, tmp_buf);
 176                if (of_node_is_type(parent, "ebus"))
 177                        return ebus_path_component(dp, tmp_buf);
 178                if (of_node_is_type(parent, "ambapp"))
 179                        return ambapp_path_component(dp, tmp_buf);
 180
 181                /* "isa" is handled with platform naming */
 182        }
 183
 184        /* Use platform naming convention.  */
 185        return sparc32_path_component(dp, tmp_buf);
 186}
 187
 188char * __init build_path_component(struct device_node *dp)
 189{
 190        const char *name = of_get_property(dp, "name", NULL);
 191        char tmp_buf[64], *n;
 192
 193        tmp_buf[0] = '\0';
 194        __build_path_component(dp, tmp_buf);
 195        if (tmp_buf[0] == '\0')
 196                strcpy(tmp_buf, name);
 197
 198        n = prom_early_alloc(strlen(tmp_buf) + 1);
 199        strcpy(n, tmp_buf);
 200
 201        return n;
 202}
 203
 204extern void restore_current(void);
 205
 206void __init of_console_init(void)
 207{
 208        char *msg = "OF stdout device is: %s\n";
 209        struct device_node *dp;
 210        unsigned long flags;
 211        const char *type;
 212        phandle node;
 213        int skip, tmp, fd;
 214
 215        of_console_path = prom_early_alloc(256);
 216
 217        switch (prom_vers) {
 218        case PROM_V0:
 219                skip = 0;
 220                switch (*romvec->pv_stdout) {
 221                case PROMDEV_SCREEN:
 222                        type = "display";
 223                        break;
 224
 225                case PROMDEV_TTYB:
 226                        skip = 1;
 227                        fallthrough;
 228
 229                case PROMDEV_TTYA:
 230                        type = "serial";
 231                        break;
 232
 233                default:
 234                        prom_printf("Invalid PROM_V0 stdout value %u\n",
 235                                    *romvec->pv_stdout);
 236                        prom_halt();
 237                }
 238
 239                tmp = skip;
 240                for_each_node_by_type(dp, type) {
 241                        if (!tmp--)
 242                                break;
 243                }
 244                if (!dp) {
 245                        prom_printf("Cannot find PROM_V0 console node.\n");
 246                        prom_halt();
 247                }
 248                of_console_device = dp;
 249
 250                sprintf(of_console_path, "%pOF", dp);
 251                if (!strcmp(type, "serial")) {
 252                        strcat(of_console_path,
 253                               (skip ? ":b" : ":a"));
 254                }
 255                break;
 256
 257        default:
 258        case PROM_V2:
 259        case PROM_V3:
 260                fd = *romvec->pv_v2bootargs.fd_stdout;
 261
 262                spin_lock_irqsave(&prom_lock, flags);
 263                node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
 264                restore_current();
 265                spin_unlock_irqrestore(&prom_lock, flags);
 266
 267                if (!node) {
 268                        prom_printf("Cannot resolve stdout node from "
 269                                    "instance %08x.\n", fd);
 270                        prom_halt();
 271                }
 272                dp = of_find_node_by_phandle(node);
 273
 274                if (!of_node_is_type(dp, "display") &&
 275                    !of_node_is_type(dp, "serial")) {
 276                        prom_printf("Console device_type is neither display "
 277                                    "nor serial.\n");
 278                        prom_halt();
 279                }
 280
 281                of_console_device = dp;
 282
 283                if (prom_vers == PROM_V2) {
 284                        sprintf(of_console_path, "%pOF", dp);
 285                        switch (*romvec->pv_stdout) {
 286                        case PROMDEV_TTYA:
 287                                strcat(of_console_path, ":a");
 288                                break;
 289                        case PROMDEV_TTYB:
 290                                strcat(of_console_path, ":b");
 291                                break;
 292                        }
 293                } else {
 294                        const char *path;
 295
 296                        dp = of_find_node_by_path("/");
 297                        path = of_get_property(dp, "stdout-path", NULL);
 298                        if (!path) {
 299                                prom_printf("No stdout-path in root node.\n");
 300                                prom_halt();
 301                        }
 302                        strcpy(of_console_path, path);
 303                }
 304                break;
 305        }
 306
 307        of_console_options = strrchr(of_console_path, ':');
 308        if (of_console_options) {
 309                of_console_options++;
 310                if (*of_console_options == '\0')
 311                        of_console_options = NULL;
 312        }
 313
 314        printk(msg, of_console_path);
 315}
 316
 317void __init of_fill_in_cpu_data(void)
 318{
 319}
 320
 321void __init irq_trans_init(struct device_node *dp)
 322{
 323}
 324