-#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>
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,
- unsigned int flags)
+ 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)
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];
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);
}
}
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,
static int __init add_legacy_soc_port(struct device_node *np,
struct device_node *soc_dev)
{
- phys_addr_t addr;
- u32 *addrp;
- unsigned int flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+ 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 (get_property(np, "clock-frequency", NULL) == NULL)
+ 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 */
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
*/
- return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags);
+ 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);
}
-#ifdef CONFIG_ISA
static int __init add_legacy_isa_port(struct device_node *np,
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;
/* 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, UPF_BOOT_AUTOCONF);
+ return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr,
+ NO_IRQ, UPF_BOOT_AUTOCONF, 0);
}
-#endif
#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
* 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 */
/* We only support BAR 0 for now */
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)
* 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;
}
* 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 {
/* 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, UPF_BOOT_AUTOCONF);
+ 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);
+}
+
/*
* This is called very early, as part of setup_system() or eventually
* setup_arch(), basically before anything else in this file. This function
void __init find_legacy_serial_ports(void)
{
struct device_node *np, *stdout = NULL;
- char *path;
+ 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);
+ path = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (path != NULL) {
stdout = of_find_node_by_path(path);
if (stdout)
DBG(" no linux,stdout-path !\n");
}
- /* 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")) {
+ /* 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(soc);
+ of_node_put(parent);
}
-#ifdef CONFIG_ISA
- /* 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);
}
of_node_put(isa);
}
-#endif
#ifdef CONFIG_PCI
/* Next, try to locate PCI ports */
/* 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);
#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");
}
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,
/*
* 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");
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);
}
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;
}
}
/* 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;
}
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);
}
console_initcall(check_legacy_serial_console);
+#endif /* CONFIG_SERIAL_8250_CONSOLE */