sh: Populate initial secondary CPU info from boot_cpu_data.
[safe/jmp/linux-2.6] / arch / powerpc / kernel / legacy_serial.c
index 83023bb..9ddfaef 100644 (file)
@@ -1,10 +1,10 @@
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_core.h>
 #include <linux/console.h>
 #include <linux/pci.h>
+#include <linux/of_device.h>
 #include <asm/io.h>
 #include <asm/mmu.h>
 #include <asm/prom.h>
@@ -29,25 +29,39 @@ static struct legacy_serial_info {
        struct device_node              *np;
        unsigned int                    speed;
        unsigned int                    clock;
+       int                             irq_check_parent;
        phys_addr_t                     taddr;
 } legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS];
+
+static struct __initdata of_device_id legacy_serial_parents[] = {
+       {.type = "soc",},
+       {.type = "tsi-bridge",},
+       {.type = "opb", },
+       {.compatible = "ibm,opb",},
+       {.compatible = "simple-bus",},
+       {.compatible = "wrs,epld-localbus",},
+       {},
+};
+
 static unsigned int legacy_serial_count;
 static int legacy_serial_console = -1;
 
 static int __init add_legacy_port(struct device_node *np, int want_index,
                                  int iotype, phys_addr_t base,
-                                 phys_addr_t taddr, unsigned long irq)
+                                 phys_addr_t taddr, unsigned long irq,
+                                 upf_t flags, int irq_check_parent)
 {
-       u32 *clk, *spd, clock = BASE_BAUD * 16;
+       const u32 *clk, *spd;
+       u32 clock = BASE_BAUD * 16;
        int index;
 
        /* get clock freq. if present */
-       clk = (u32 *)get_property(np, "clock-frequency", NULL);
+       clk = of_get_property(np, "clock-frequency", NULL);
        if (clk && *clk)
                clock = *clk;
 
        /* get default speed if present */
-       spd = (u32 *)get_property(np, "current-speed", NULL);
+       spd = of_get_property(np, "current-speed", NULL);
 
        /* If we have a location index, then try to use it */
        if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS)
@@ -68,7 +82,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
        if (legacy_serial_infos[index].np != 0) {
                /* if we still have some room, move it, else override */
                if (legacy_serial_count < MAX_LEGACY_SERIAL_PORTS) {
-                       printk(KERN_INFO "Moved legacy port %d -> %d\n",
+                       printk(KERN_DEBUG "Moved legacy port %d -> %d\n",
                               index, legacy_serial_count);
                        legacy_serial_ports[legacy_serial_count] =
                                legacy_serial_ports[index];
@@ -76,7 +90,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
                                legacy_serial_infos[index];
                        legacy_serial_count++;
                } else {
-                       printk(KERN_INFO "Replacing legacy port %d\n", index);
+                       printk(KERN_DEBUG "Replacing legacy port %d\n", index);
                }
        }
 
@@ -90,15 +104,16 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
        legacy_serial_ports[index].iotype = iotype;
        legacy_serial_ports[index].uartclk = clock;
        legacy_serial_ports[index].irq = irq;
-       legacy_serial_ports[index].flags = ASYNC_BOOT_AUTOCONF;
+       legacy_serial_ports[index].flags = flags;
        legacy_serial_infos[index].taddr = taddr;
        legacy_serial_infos[index].np = of_node_get(np);
        legacy_serial_infos[index].clock = clock;
        legacy_serial_infos[index].speed = spd ? *spd : 0;
+       legacy_serial_infos[index].irq_check_parent = irq_check_parent;
 
-       printk(KERN_INFO "Found legacy serial port %d for %s\n",
+       printk(KERN_DEBUG "Found legacy serial port %d for %s\n",
               index, np->full_name);
-       printk(KERN_INFO "  %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n",
+       printk(KERN_DEBUG "  %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n",
               (iotype == UPIO_PORT) ? "port" : "mem",
               (unsigned long long)base, (unsigned long long)taddr, irq,
               legacy_serial_ports[index].uartclk,
@@ -107,16 +122,60 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
        return index;
 }
 
+static int __init add_legacy_soc_port(struct device_node *np,
+                                     struct device_node *soc_dev)
+{
+       u64 addr;
+       const u32 *addrp;
+       upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ
+               | UPF_FIXED_PORT;
+       struct device_node *tsi = of_get_parent(np);
+
+       /* We only support ports that have a clock frequency properly
+        * encoded in the device-tree.
+        */
+       if (of_get_property(np, "clock-frequency", NULL) == NULL)
+               return -1;
+
+       /* if reg-shift or offset, don't try to use it */
+       if ((of_get_property(np, "reg-shift", NULL) != NULL) ||
+               (of_get_property(np, "reg-offset", NULL) != NULL))
+               return -1;
+
+       /* if rtas uses this device, don't try to use it as well */
+       if (of_get_property(np, "used-by-rtas", NULL) != NULL)
+               return -1;
+
+       /* Get the address */
+       addrp = of_get_address(soc_dev, 0, NULL, NULL);
+       if (addrp == NULL)
+               return -1;
+
+       addr = of_translate_address(soc_dev, addrp);
+       if (addr == OF_BAD_ADDR)
+               return -1;
+
+       /* Add port, irq will be dealt with later. We passed a translated
+        * IO port value. It will be fixed up later along with the irq
+        */
+       if (tsi && !strcmp(tsi->type, "tsi-bridge"))
+               return add_legacy_port(np, -1, UPIO_TSI, addr, addr, NO_IRQ, flags, 0);
+       else
+               return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags, 0);
+}
+
 static int __init add_legacy_isa_port(struct device_node *np,
-                                     struct device_node *isa_bridge)
+                                     struct device_node *isa_brg)
 {
-       u32 *reg;
-       char *typep;
+       const u32 *reg;
+       const char *typep;
        int index = -1;
-       phys_addr_t taddr;
+       u64 taddr;
+
+       DBG(" -> add_legacy_isa_port(%s)\n", np->full_name);
 
        /* Get the ISA port number */
-       reg = (u32 *)get_property(np, "reg", NULL);
+       reg = of_get_property(np, "reg", NULL);
        if (reg == NULL)
                return -1;
 
@@ -127,27 +186,37 @@ static int __init add_legacy_isa_port(struct device_node *np,
        /* Now look for an "ibm,aix-loc" property that gives us ordering
         * if any...
         */
-       typep = (char *)get_property(np, "ibm,aix-loc", NULL);
+       typep = of_get_property(np, "ibm,aix-loc", NULL);
 
        /* If we have a location index, then use it */
        if (typep && *typep == 'S')
                index = simple_strtol(typep+1, NULL, 0) - 1;
 
-       /* Translate ISA address */
+       /* Translate ISA address. If it fails, we still register the port
+        * with no translated address so that it can be picked up as an IO
+        * port later by the serial driver
+        */
        taddr = of_translate_address(np, reg);
+       if (taddr == OF_BAD_ADDR)
+               taddr = 0;
 
        /* Add port, irq will be dealt with later */
-       return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, NO_IRQ);
+       return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr,
+                              NO_IRQ, UPF_BOOT_AUTOCONF, 0);
 
 }
 
+#ifdef CONFIG_PCI
 static int __init add_legacy_pci_port(struct device_node *np,
                                      struct device_node *pci_dev)
 {
-       phys_addr_t addr, base;
-       u32 *addrp;
+       u64 addr, base;
+       const u32 *addrp;
+       unsigned int flags;
        int iotype, index = -1, lindex = 0;
 
+       DBG(" -> add_legacy_pci_port(%s)\n", np->full_name);
+
        /* We only support ports that have a clock frequency properly
         * encoded in the device-tree (that is have an fcode). Anything
         * else can't be used that early and will be normally probed by
@@ -155,17 +224,19 @@ static int __init add_legacy_pci_port(struct device_node *np,
         * compatible UARTs on PCI need all sort of quirks (port offsets
         * etc...) that this code doesn't know about
         */
-       if (get_property(np, "clock-frequency", NULL) == NULL)
+       if (of_get_property(np, "clock-frequency", NULL) == NULL)
                return -1;
 
        /* Get the PCI address. Assume BAR 0 */
-       addrp = of_get_pci_address(pci_dev, 0, NULL);
+       addrp = of_get_pci_address(pci_dev, 0, NULL, &flags);
        if (addrp == NULL)
                return -1;
 
        /* We only support BAR 0 for now */
-       iotype = (addrp[0] & 0x02000000) ? UPIO_MEM : UPIO_PORT;
+       iotype = (flags & IORESOURCE_MEM) ? UPIO_MEM : UPIO_PORT;
        addr = of_translate_address(pci_dev, addrp);
+       if (addr == OF_BAD_ADDR)
+               return -1;
 
        /* Set the IO base to the same as the translated address for MMIO,
         * or to the domain local IO base for PIO (it will be fixed up later)
@@ -179,7 +250,7 @@ static int __init add_legacy_pci_port(struct device_node *np,
         * we get to their "reg" property
         */
        if (np != pci_dev) {
-               u32 *reg = (u32 *)get_property(np, "reg", NULL);
+               const u32 *reg = of_get_property(np, "reg", NULL);
                if (reg && (*reg < 4))
                        index = lindex = *reg;
        }
@@ -190,9 +261,9 @@ static int __init add_legacy_pci_port(struct device_node *np,
         * doesn't work for these settings, you'll have to add your own special
         * cases here
         */
-       if (device_is_compatible(pci_dev, "pci13a8,152") ||
-           device_is_compatible(pci_dev, "pci13a8,154") ||
-           device_is_compatible(pci_dev, "pci13a8,158")) {
+       if (of_device_is_compatible(pci_dev, "pci13a8,152") ||
+           of_device_is_compatible(pci_dev, "pci13a8,154") ||
+           of_device_is_compatible(pci_dev, "pci13a8,158")) {
                addr += 0x200 * lindex;
                base += 0x200 * lindex;
        } else {
@@ -203,7 +274,26 @@ static int __init add_legacy_pci_port(struct device_node *np,
        /* Add port, irq will be dealt with later. We passed a translated
         * IO port value. It will be fixed up later along with the irq
         */
-       return add_legacy_port(np, index, iotype, base, addr, NO_IRQ);
+       return add_legacy_port(np, index, iotype, base, addr, NO_IRQ,
+                              UPF_BOOT_AUTOCONF, np != pci_dev);
+}
+#endif
+
+static void __init setup_legacy_serial_console(int console)
+{
+       struct legacy_serial_info *info =
+               &legacy_serial_infos[console];
+       void __iomem *addr;
+
+       if (info->taddr == 0)
+               return;
+       addr = ioremap(info->taddr, 0x1000);
+       if (addr == NULL)
+               return;
+       if (info->speed == 0)
+               info->speed = udbg_probe_uart_speed(addr, info->clock);
+       DBG("default console speed = %d\n", info->speed);
+       udbg_init_uart(addr, info->speed, info->clock);
 }
 
 /*
@@ -217,25 +307,37 @@ static int __init add_legacy_pci_port(struct device_node *np,
  */
 void __init find_legacy_serial_ports(void)
 {
-       struct device_node *np, *stdout;
-       char *path;
+       struct device_node *np, *stdout = NULL;
+       const char *path;
        int index;
 
        DBG(" -> find_legacy_serial_port()\n");
 
        /* Now find out if one of these is out firmware console */
-       path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
-       if (path == NULL) {
+       path = of_get_property(of_chosen, "linux,stdout-path", NULL);
+       if (path != NULL) {
+               stdout = of_find_node_by_path(path);
+               if (stdout)
+                       DBG("stdout is %s\n", stdout->full_name);
+       } else {
                DBG(" no linux,stdout-path !\n");
-               return;
        }
-       stdout = of_find_node_by_path(path);
-       if (stdout) {
-               DBG("stdout is %s\n", stdout->full_name);
+
+       /* Iterate over all the 16550 ports, looking for known parents */
+       for_each_compatible_node(np, "serial", "ns16550") {
+               struct device_node *parent = of_get_parent(np);
+               if (!parent)
+                       continue;
+               if (of_match_node(legacy_serial_parents, parent) != NULL) {
+                       index = add_legacy_soc_port(np, np);
+                       if (index >= 0 && np == stdout)
+                               legacy_serial_console = index;
+               }
+               of_node_put(parent);
        }
 
-       /* First fill our array with ISA ports */
-       for (np = NULL; (np = of_find_node_by_type(np, "serial"));) {
+       /* Next, fill our array with ISA ports */
+       for_each_node_by_type(np, "serial") {
                struct device_node *isa = of_get_parent(np);
                if (isa && !strcmp(isa->name, "isa")) {
                        index = add_legacy_isa_port(np, isa);
@@ -245,6 +347,7 @@ void __init find_legacy_serial_ports(void)
                of_node_put(isa);
        }
 
+#ifdef CONFIG_PCI
        /* Next, try to locate PCI ports */
        for (np = NULL; (np = of_find_all_nodes(np));) {
                struct device_node *pci, *parent = of_get_parent(np);
@@ -259,11 +362,11 @@ void __init find_legacy_serial_ports(void)
                /* Check for known pciclass, and also check wether we have
                 * a device with child nodes for ports or not
                 */
-               if (device_is_compatible(np, "pciclass,0700") ||
-                   device_is_compatible(np, "pciclass,070002"))
+               if (of_device_is_compatible(np, "pciclass,0700") ||
+                   of_device_is_compatible(np, "pciclass,070002"))
                        pci = np;
-               else if (device_is_compatible(parent, "pciclass,0700") ||
-                        device_is_compatible(parent, "pciclass,070002"))
+               else if (of_device_is_compatible(parent, "pciclass,0700") ||
+                        of_device_is_compatible(parent, "pciclass,070002"))
                        pci = parent;
                else {
                        of_node_put(parent);
@@ -274,27 +377,11 @@ void __init find_legacy_serial_ports(void)
                        legacy_serial_console = index;
                of_node_put(parent);
        }
+#endif
 
        DBG("legacy_serial_console = %d\n", legacy_serial_console);
-
-       /* udbg is 64 bits only for now, that will change soon though ... */
-       while (legacy_serial_console >= 0) {
-               struct legacy_serial_info *info =
-                       &legacy_serial_infos[legacy_serial_console];
-               void __iomem *addr;
-
-               if (info->taddr == 0)
-                       break;
-               addr = ioremap(info->taddr, 0x1000);
-               if (addr == NULL)
-                       break;
-               if (info->speed == 0)
-                       info->speed = udbg_probe_uart_speed(addr, info->clock);
-               DBG("default console speed = %d\n", info->speed);
-               udbg_init_uart(addr, info->speed, info->clock);
-               break;
-       }
-
+       if (legacy_serial_console >= 0)
+               setup_legacy_serial_console(legacy_serial_console);
        DBG(" <- find_legacy_serial_port()\n");
 }
 
@@ -310,33 +397,29 @@ static void __init fixup_port_irq(int index,
                                  struct device_node *np,
                                  struct plat_serial8250_port *port)
 {
+       unsigned int virq;
+
        DBG("fixup_port_irq(%d)\n", index);
 
-       /* Check for interrupts in that node */
-       if (np->n_intrs > 0) {
-               port->irq = np->intrs[0].line;
-               DBG(" port %d (%s), irq=%d\n",
-                   index, np->full_name, port->irq);
-               return;
+       virq = irq_of_parse_and_map(np, 0);
+       if (virq == NO_IRQ && legacy_serial_infos[index].irq_check_parent) {
+               np = of_get_parent(np);
+               if (np == NULL)
+                       return;
+               virq = irq_of_parse_and_map(np, 0);
+               of_node_put(np);
        }
-
-       /* Check for interrupts in the parent */
-       np = of_get_parent(np);
-       if (np == NULL)
+       if (virq == NO_IRQ)
                return;
 
-       if (np->n_intrs > 0) {
-               port->irq = np->intrs[0].line;
-               DBG(" port %d (%s), irq=%d\n",
-                   index, np->full_name, port->irq);
-       }
-       of_node_put(np);
+       port->irq = virq;
 }
 
 static void __init fixup_port_pio(int index,
                                  struct device_node *np,
                                  struct plat_serial8250_port *port)
 {
+#ifdef CONFIG_PCI
        struct pci_controller *hose;
 
        DBG("fixup_port_pio(%d)\n", index);
@@ -353,6 +436,7 @@ static void __init fixup_port_pio(int index,
                    index, port->iobase, port->iobase + offset);
                port->iobase += offset;
        }
+#endif
 }
 
 static void __init fixup_port_mmio(int index,
@@ -386,7 +470,7 @@ static int __init serial_dev_init(void)
 
        /*
         * Before we register the platfrom serial devices, we need
-        * to fixup their interrutps and their IO ports.
+        * to fixup their interrupts and their IO ports.
         */
        DBG("Fixing serial ports interrupts and IO ports ...\n");
 
@@ -398,7 +482,7 @@ static int __init serial_dev_init(void)
                        fixup_port_irq(i, np, port);
                if (port->iotype == UPIO_PORT)
                        fixup_port_pio(i, np, port);
-               if (port->iotype == UPIO_MEM)
+               if ((port->iotype == UPIO_MEM) || (port->iotype == UPIO_TSI))
                        fixup_port_mmio(i, np, port);
        }
 
@@ -406,28 +490,28 @@ static int __init serial_dev_init(void)
 
        return platform_device_register(&serial_device);
 }
-arch_initcall(serial_dev_init);
+device_initcall(serial_dev_init);
 
 
+#ifdef CONFIG_SERIAL_8250_CONSOLE
 /*
  * This is called very early, as part of console_init() (typically just after
  * time_init()). This function is respondible for trying to find a good
  * default console on serial ports. It tries to match the open firmware
- * default output with one of the available serial console drivers, either
- * one of the platform serial ports that have been probed earlier by
- * find_legacy_serial_ports() or some more platform specific ones.
+ * default output with one of the available serial console drivers that have
+ * been probed earlier by find_legacy_serial_ports()
  */
 static int __init check_legacy_serial_console(void)
 {
        struct device_node *prom_stdout = NULL;
-       int speed = 0, offset = 0;
-       char *name;
-       u32 *spd;
+       int i, speed = 0, offset = 0;
+       const char *name;
+       const u32 *spd;
 
        DBG(" -> check_legacy_serial_console()\n");
 
        /* The user has requested a console so this is already set up. */
-       if (strstr(saved_command_line, "console=")) {
+       if (strstr(boot_command_line, "console=")) {
                DBG(" console was specified !\n");
                return -EBUSY;
        }
@@ -436,9 +520,14 @@ static int __init check_legacy_serial_console(void)
                DBG(" of_chosen is NULL !\n");
                return -ENODEV;
        }
+
+       if (legacy_serial_console < 0) {
+               DBG(" legacy_serial_console not found !\n");
+               return -ENODEV;
+       }
        /* We are getting a weird phandle from OF ... */
        /* ... So use the full path instead */
-       name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+       name = of_get_property(of_chosen, "linux,stdout-path", NULL);
        if (name == NULL) {
                DBG(" no linux,stdout-path !\n");
                return -ENODEV;
@@ -450,40 +539,29 @@ static int __init check_legacy_serial_console(void)
        }
        DBG("stdout is %s\n", prom_stdout->full_name);
 
-       name = (char *)get_property(prom_stdout, "name", NULL);
+       name = of_get_property(prom_stdout, "name", NULL);
        if (!name) {
                DBG(" stdout package has no name !\n");
                goto not_found;
        }
-       spd = (u32 *)get_property(prom_stdout, "current-speed", NULL);
+       spd = of_get_property(prom_stdout, "current-speed", NULL);
        if (spd)
                speed = *spd;
 
-       if (0)
-               ;
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-       else if (strcmp(name, "serial") == 0) {
-               int i;
-               /* Look for it in probed array */
-               for (i = 0; i < legacy_serial_count; i++) {
-                       if (prom_stdout != legacy_serial_infos[i].np)
-                               continue;
-                       offset = i;
-                       speed = legacy_serial_infos[i].speed;
-                       break;
-               }
-               if (i >= legacy_serial_count)
-                       goto not_found;
+       if (strcmp(name, "serial") != 0)
+               goto not_found;
+
+       /* Look for it in probed array */
+       for (i = 0; i < legacy_serial_count; i++) {
+               if (prom_stdout != legacy_serial_infos[i].np)
+                       continue;
+               offset = i;
+               speed = legacy_serial_infos[i].speed;
+               break;
        }
-#endif /* CONFIG_SERIAL_8250_CONSOLE */
-#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
-       else if (strcmp(name, "ch-a") == 0)
-               offset = 0;
-       else if (strcmp(name, "ch-b") == 0)
-               offset = 1;
-#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
-       else
+       if (i >= legacy_serial_count)
                goto not_found;
+
        of_node_put(prom_stdout);
 
        DBG("Found serial console at ttyS%d\n", offset);
@@ -502,3 +580,4 @@ static int __init check_legacy_serial_console(void)
 }
 console_initcall(check_legacy_serial_console);
 
+#endif /* CONFIG_SERIAL_8250_CONSOLE */