]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/powerpc/kernel/legacy_serial.c
Pull trivial2 into release branch
[linux-2.6-omap-h63xx.git] / arch / powerpc / kernel / legacy_serial.c
index 28ad50e424a9e07311b3cf79f125b2ba1a4720fd..6e67b5b49ba1aedaa44a818835e396a0701a1185 100644 (file)
@@ -36,14 +36,16 @@ 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)
 {
-       u32 *clk, *spd, clock;
+       u32 *clk, *spd, clock = BASE_BAUD * 16;
        int index;
 
        /* get clock freq. if present */
        clk = (u32 *)get_property(np, "clock-frequency", NULL);
-       clock = clk ? *clk : BASE_BAUD * 16;
+       if (clk && *clk)
+               clock = *clk;
 
        /* get default speed if present */
        spd = (u32 *)get_property(np, "current-speed", NULL);
@@ -85,11 +87,11 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
        if (iotype == UPIO_PORT)
                legacy_serial_ports[index].iobase = base;
        else
-               legacy_serial_ports[index].membase = (void __iomem *)base;
+               legacy_serial_ports[index].mapbase = base;
        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;
@@ -106,8 +108,34 @@ 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)
+{
+       phys_addr_t addr;
+       u32 *addrp;
+       upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+
+       /* We only support ports that have a clock frequency properly
+        * encoded in the device-tree.
+        */
+       if (get_property(np, "clock-frequency", 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);
+
+       /* 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, -1, UPIO_MEM, addr, addr, NO_IRQ, flags);
+}
+
 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;
@@ -136,34 +164,36 @@ static int __init add_legacy_isa_port(struct device_node *np,
        taddr = of_translate_address(np, reg);
 
        /* 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);
 
 }
 
+#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;
-       int iotype, index = -1;
+       unsigned int flags;
+       int iotype, index = -1, lindex = 0;
 
-#if 0
        /* 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
-        * the generic 8250_pci driver later on.
+        * the generic 8250_pci driver later on. The reason is that 8250
+        * 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)
                return -1;
-#endif
 
        /* 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);
 
        /* Set the IO base to the same as the translated address for MMIO,
@@ -180,13 +210,47 @@ static int __init add_legacy_pci_port(struct device_node *np,
        if (np != pci_dev) {
                u32 *reg = (u32 *)get_property(np, "reg", NULL);
                if (reg && (*reg < 4))
-                       index = legacy_serial_count + *reg;
+                       index = lindex = *reg;
+       }
+
+       /* Local index means it's the Nth port in the PCI chip. Unfortunately
+        * the offset to add here is device specific. We know about those
+        * EXAR ports and we default to the most common case. If your UART
+        * 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")) {
+               addr += 0x200 * lindex;
+               base += 0x200 * lindex;
+       } else {
+               addr += 8 * lindex;
+               base += 8 * lindex;
        }
 
        /* 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);
+}
+#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);
 }
 
 /*
@@ -200,7 +264,7 @@ static int __init add_legacy_pci_port(struct device_node *np,
  */
 void __init find_legacy_serial_ports(void)
 {
-       struct device_node *np, *stdout;
+       struct device_node *np, *stdout = NULL;
        char *path;
        int index;
 
@@ -208,13 +272,23 @@ void __init find_legacy_serial_ports(void)
 
        /* Now find out if one of these is out firmware console */
        path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
-       if (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);
+
+       /* First fill our array with SOC ports */
+       for (np = NULL; (np = of_find_compatible_node(np, "serial", "ns16550")) != NULL;) {
+               struct device_node *soc = of_get_parent(np);
+               if (soc && !strcmp(soc->type, "soc")) {
+                       index = add_legacy_soc_port(np, np);
+                       if (index >= 0 && np == stdout)
+                               legacy_serial_console = index;
+               }
+               of_node_put(soc);
        }
 
        /* First fill our array with ISA ports */
@@ -228,6 +302,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);
@@ -257,29 +332,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 ... */
-#ifdef CONFIG_PPC64
-       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;
-       }
-#endif /* CONFIG_PPC64 */
-
+       if (legacy_serial_console >= 0)
+               setup_legacy_serial_console(legacy_serial_console);
        DBG(" <- find_legacy_serial_port()\n");
 }
 
@@ -322,6 +379,7 @@ 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);
@@ -338,6 +396,16 @@ 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,
+                                  struct device_node *np,
+                                  struct plat_serial8250_port *port)
+{
+       DBG("fixup_port_mmio(%d)\n", index);
+
+       port->membase = ioremap(port->mapbase, 0x100);
 }
 
 /*
@@ -374,6 +442,8 @@ 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)
+                       fixup_port_mmio(i, np, port);
        }
 
        DBG("Registering platform serial ports\n");
@@ -410,6 +480,11 @@ 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);