diff --git a/[refs] b/[refs] index c1d1a3d096c4..9a96cf2f4f1a 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 6002e45045a190a112bc3bc2134d0ff4fac7ced7 +refs/heads/master: da298d3a4f01dbc10c54da75d6b5717a99fb9cbc diff --git a/trunk/arch/sparc/kernel/ioport.c b/trunk/arch/sparc/kernel/ioport.c index 8654b446ac9e..79d177149fdb 100644 --- a/trunk/arch/sparc/kernel/ioport.c +++ b/trunk/arch/sparc/kernel/ioport.c @@ -26,7 +26,6 @@ */ #include -#include #include #include #include @@ -41,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -145,21 +143,6 @@ void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset, phyres->start + offset, size, name); } -void __iomem *of_ioremap(struct resource *res, unsigned long offset, - unsigned long size, char *name) -{ - return _sparc_alloc_io(res->flags & 0xF, - res->start + offset, - size, name); -} -EXPORT_SYMBOL(of_ioremap); - -void of_iounmap(void __iomem *base, unsigned long size) -{ - iounmap(base); -} -EXPORT_SYMBOL(of_iounmap); - /* */ void sbus_iounmap(volatile void __iomem *addr, unsigned long size) diff --git a/trunk/arch/sparc/kernel/of_device.c b/trunk/arch/sparc/kernel/of_device.c index bc956c530376..80a809478781 100644 --- a/trunk/arch/sparc/kernel/of_device.c +++ b/trunk/arch/sparc/kernel/of_device.c @@ -129,26 +129,6 @@ static int of_device_resume(struct device * dev) return error; } -static int node_match(struct device *dev, void *data) -{ - struct of_device *op = to_of_device(dev); - struct device_node *dp = data; - - return (op->node == dp); -} - -struct of_device *of_find_device_by_node(struct device_node *dp) -{ - struct device *dev = bus_find_device(&of_bus_type, NULL, - dp, node_match); - - if (dev) - return to_of_device(dev); - - return NULL; -} -EXPORT_SYMBOL(of_find_device_by_node); - #ifdef CONFIG_PCI struct bus_type ebus_bus_type = { .name = "ebus", @@ -173,459 +153,10 @@ struct bus_type sbus_bus_type = { EXPORT_SYMBOL(sbus_bus_type); #endif -struct bus_type of_bus_type = { - .name = "of", - .match = of_platform_bus_match, - .probe = of_device_probe, - .remove = of_device_remove, - .suspend = of_device_suspend, - .resume = of_device_resume, -}; -EXPORT_SYMBOL(of_bus_type); - -static inline u64 of_read_addr(u32 *cell, int size) -{ - u64 r = 0; - while (size--) - r = (r << 32) | *(cell++); - return r; -} - -static void __init get_cells(struct device_node *dp, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = of_n_addr_cells(dp); - if (sizec) - *sizec = of_n_size_cells(dp); -} - -/* Max address size we deal with */ -#define OF_MAX_ADDR_CELLS 4 - -struct of_bus { - const char *name; - const char *addr_prop_name; - int (*match)(struct device_node *parent); - void (*count_cells)(struct device_node *child, - int *addrc, int *sizec); - u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); - int (*translate)(u32 *addr, u64 offset, int na); - unsigned int (*get_flags)(u32 *addr); -}; - -/* - * Default translator (generic bus) - */ - -static void of_bus_default_count_cells(struct device_node *dev, - int *addrc, int *sizec) -{ - get_cells(dev, addrc, sizec); -} - -static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) -{ - u64 cp, s, da; - - cp = of_read_addr(range, na); - s = of_read_addr(range + na + pna, ns); - da = of_read_addr(addr, na); - - if (da < cp || da >= (cp + s)) - return OF_BAD_ADDR; - return da - cp; -} - -static int of_bus_default_translate(u32 *addr, u64 offset, int na) -{ - u64 a = of_read_addr(addr, na); - memset(addr, 0, na * 4); - a += offset; - if (na > 1) - addr[na - 2] = a >> 32; - addr[na - 1] = a & 0xffffffffu; - - return 0; -} - -static unsigned int of_bus_default_get_flags(u32 *addr) -{ - return IORESOURCE_MEM; -} - - -/* - * PCI bus specific translator - */ - -static int of_bus_pci_match(struct device_node *np) -{ - return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); -} - -static void of_bus_pci_count_cells(struct device_node *np, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 3; - if (sizec) - *sizec = 2; -} - -static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) -{ - u64 cp, s, da; - - /* Check address type match */ - if ((addr[0] ^ range[0]) & 0x03000000) - return OF_BAD_ADDR; - - /* Read address values, skipping high cell */ - cp = of_read_addr(range + 1, na - 1); - s = of_read_addr(range + na + pna, ns); - da = of_read_addr(addr + 1, na - 1); - - if (da < cp || da >= (cp + s)) - return OF_BAD_ADDR; - return da - cp; -} - -static int of_bus_pci_translate(u32 *addr, u64 offset, int na) -{ - return of_bus_default_translate(addr + 1, offset, na - 1); -} - -static unsigned int of_bus_pci_get_flags(u32 *addr) -{ - unsigned int flags = 0; - u32 w = addr[0]; - - switch((w >> 24) & 0x03) { - case 0x01: - flags |= IORESOURCE_IO; - case 0x02: /* 32 bits */ - case 0x03: /* 64 bits */ - flags |= IORESOURCE_MEM; - } - if (w & 0x40000000) - flags |= IORESOURCE_PREFETCH; - return flags; -} - -/* - * SBUS bus specific translator - */ - -static int of_bus_sbus_match(struct device_node *np) -{ - return !strcmp(np->name, "sbus") || - !strcmp(np->name, "sbi"); -} - -static void of_bus_sbus_count_cells(struct device_node *child, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 2; - if (sizec) - *sizec = 1; -} - -static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) -{ - return of_bus_default_map(addr, range, na, ns, pna); -} - -static int of_bus_sbus_translate(u32 *addr, u64 offset, int na) -{ - return of_bus_default_translate(addr, offset, na); -} - -static unsigned int of_bus_sbus_get_flags(u32 *addr) -{ - return IORESOURCE_MEM; -} - - -/* - * Array of bus specific translators - */ - -static struct of_bus of_busses[] = { - /* PCI */ - { - .name = "pci", - .addr_prop_name = "assigned-addresses", - .match = of_bus_pci_match, - .count_cells = of_bus_pci_count_cells, - .map = of_bus_pci_map, - .translate = of_bus_pci_translate, - .get_flags = of_bus_pci_get_flags, - }, - /* SBUS */ - { - .name = "sbus", - .addr_prop_name = "reg", - .match = of_bus_sbus_match, - .count_cells = of_bus_sbus_count_cells, - .map = of_bus_sbus_map, - .translate = of_bus_sbus_translate, - .get_flags = of_bus_sbus_get_flags, - }, - /* Default */ - { - .name = "default", - .addr_prop_name = "reg", - .match = NULL, - .count_cells = of_bus_default_count_cells, - .map = of_bus_default_map, - .translate = of_bus_default_translate, - .get_flags = of_bus_default_get_flags, - }, -}; - -static struct of_bus *of_match_bus(struct device_node *np) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(of_busses); i ++) - if (!of_busses[i].match || of_busses[i].match(np)) - return &of_busses[i]; - BUG(); - return NULL; -} - -static int __init build_one_resource(struct device_node *parent, - struct of_bus *bus, - struct of_bus *pbus, - u32 *addr, - int na, int ns, int pna) -{ - u32 *ranges; - unsigned int rlen; - int rone; - u64 offset = OF_BAD_ADDR; - - ranges = of_get_property(parent, "ranges", &rlen); - if (ranges == NULL || rlen == 0) { - offset = of_read_addr(addr, na); - memset(addr, 0, pna * 4); - goto finish; - } - - /* Now walk through the ranges */ - rlen /= 4; - rone = na + pna + ns; - for (; rlen >= rone; rlen -= rone, ranges += rone) { - offset = bus->map(addr, ranges, na, ns, pna); - if (offset != OF_BAD_ADDR) - break; - } - if (offset == OF_BAD_ADDR) - return 1; - - memcpy(addr, ranges + na, 4 * pna); - -finish: - /* Translate it into parent bus space */ - return pbus->translate(addr, offset, pna); -} - -static void __init build_device_resources(struct of_device *op, - struct device *parent) -{ - struct of_device *p_op; - struct of_bus *bus; - int na, ns; - int index, num_reg; - void *preg; - - if (!parent) - return; - - p_op = to_of_device(parent); - bus = of_match_bus(p_op->node); - bus->count_cells(op->node, &na, &ns); - - preg = of_get_property(op->node, bus->addr_prop_name, &num_reg); - if (!preg || num_reg == 0) - return; - - /* Convert to num-cells. */ - num_reg /= 4; - - /* Conver to num-entries. */ - num_reg /= na + ns; - - for (index = 0; index < num_reg; index++) { - struct resource *r = &op->resource[index]; - u32 addr[OF_MAX_ADDR_CELLS]; - u32 *reg = (preg + (index * ((na + ns) * 4))); - struct device_node *dp = op->node; - struct device_node *pp = p_op->node; - struct of_bus *pbus; - u64 size, result = OF_BAD_ADDR; - unsigned long flags; - int dna, dns; - int pna, pns; - - size = of_read_addr(reg + na, ns); - flags = bus->get_flags(reg); - - memcpy(addr, reg, na * 4); - - /* If the immediate parent has no ranges property to apply, - * just use a 1<->1 mapping. - */ - if (of_find_property(pp, "ranges", NULL) == NULL) { - result = of_read_addr(addr, na); - goto build_res; - } - - dna = na; - dns = ns; - - while (1) { - dp = pp; - pp = dp->parent; - if (!pp) { - result = of_read_addr(addr, dna); - break; - } - - pbus = of_match_bus(pp); - pbus->count_cells(dp, &pna, &pns); - - if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) - break; - - dna = pna; - dns = pns; - bus = pbus; - } - - build_res: - memset(r, 0, sizeof(*r)); - if (result != OF_BAD_ADDR) { - r->start = result & 0xffffffff; - r->end = result + size - 1; - r->flags = flags | ((result >> 32ULL) & 0xffUL); - } else { - r->start = ~0UL; - r->end = ~0UL; - } - r->name = op->node->name; - } -} - -static struct of_device * __init scan_one_device(struct device_node *dp, - struct device *parent) -{ - struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); - struct linux_prom_irqs *intr; - int len, i; - - if (!op) - return NULL; - - op->node = dp; - - op->clock_freq = of_getintprop_default(dp, "clock-frequency", - (25*1000*1000)); - op->portid = of_getintprop_default(dp, "upa-portid", -1); - if (op->portid == -1) - op->portid = of_getintprop_default(dp, "portid", -1); - - intr = of_get_property(dp, "intr", &len); - if (intr) { - op->num_irqs = len / sizeof(struct linux_prom_irqs); - for (i = 0; i < op->num_irqs; i++) - op->irqs[i] = intr[i].pri; - } else { - unsigned int *irq = of_get_property(dp, "interrupts", &len); - - if (irq) { - op->num_irqs = len / sizeof(unsigned int); - for (i = 0; i < op->num_irqs; i++) - op->irqs[i] = irq[i]; - } else { - op->num_irqs = 0; - } - } - if (sparc_cpu_model == sun4d) { - static int pil_to_sbus[] = { - 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0, - }; - struct device_node *busp = dp->parent; - struct linux_prom_registers *regs; - int board = of_getintprop_default(busp, "board#", 0); - int slot; - - regs = of_get_property(dp, "reg", NULL); - slot = regs->which_io; - - for (i = 0; i < op->num_irqs; i++) { - int this_irq = op->irqs[i]; - int sbusl = pil_to_sbus[this_irq]; - - if (sbusl) - this_irq = (((board + 1) << 5) + - (sbusl << 2) + - slot); - - op->irqs[i] = this_irq; - } - } - - build_device_resources(op, parent); - - op->dev.parent = parent; - op->dev.bus = &of_bus_type; - if (!parent) - strcpy(op->dev.bus_id, "root"); - else - strcpy(op->dev.bus_id, dp->path_component_name); - - if (of_device_register(op)) { - printk("%s: Could not register of device.\n", - dp->full_name); - kfree(op); - op = NULL; - } - - return op; -} - -static void __init scan_tree(struct device_node *dp, struct device *parent) -{ - while (dp) { - struct of_device *op = scan_one_device(dp, parent); - - if (op) - scan_tree(dp->child, &op->dev); - - dp = dp->sibling; - } -} - -static void __init scan_of_devices(void) -{ - struct device_node *root = of_find_node_by_path("/"); - struct of_device *parent; - - parent = scan_one_device(root, NULL); - if (!parent) - return; - - scan_tree(root->child, &parent->dev); -} - static int __init of_bus_driver_init(void) { - int err; + int err = 0; - err = bus_register(&of_bus_type); #ifdef CONFIG_PCI if (!err) err = bus_register(&ebus_bus_type); @@ -634,11 +165,7 @@ static int __init of_bus_driver_init(void) if (!err) err = bus_register(&sbus_bus_type); #endif - - if (!err) - scan_of_devices(); - - return err; + return 0; } postcore_initcall(of_bus_driver_init); diff --git a/trunk/arch/sparc/kernel/prom.c b/trunk/arch/sparc/kernel/prom.c index 4b06dcb00ebd..946ce6d15819 100644 --- a/trunk/arch/sparc/kernel/prom.c +++ b/trunk/arch/sparc/kernel/prom.c @@ -190,36 +190,6 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) } EXPORT_SYMBOL(of_getintprop_default); -int of_n_addr_cells(struct device_node *np) -{ - int* ip; - do { - if (np->parent) - np = np->parent; - ip = of_get_property(np, "#address-cells", NULL); - if (ip != NULL) - return *ip; - } while (np->parent); - /* No #address-cells property for the root node, default to 2 */ - return 2; -} -EXPORT_SYMBOL(of_n_addr_cells); - -int of_n_size_cells(struct device_node *np) -{ - int* ip; - do { - if (np->parent) - np = np->parent; - ip = of_get_property(np, "#size-cells", NULL); - if (ip != NULL) - return *ip; - } while (np->parent); - /* No #size-cells property for the root node, default to 1 */ - return 1; -} -EXPORT_SYMBOL(of_n_size_cells); - int of_set_property(struct device_node *dp, const char *name, void *val, int len) { struct property **prevp; diff --git a/trunk/arch/sparc/kernel/time.c b/trunk/arch/sparc/kernel/time.c index 9631e8f4ae60..7dadcdb4ca42 100644 --- a/trunk/arch/sparc/kernel/time.c +++ b/trunk/arch/sparc/kernel/time.c @@ -42,7 +42,6 @@ #include #include #include -#include extern unsigned long wall_jiffies; @@ -274,31 +273,83 @@ static __inline__ void sun4_clock_probe(void) #endif } -static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) +/* Probe for the mostek real time clock chip. */ +static __inline__ void clock_probe(void) { - struct device_node *dp = op->node; - char *model = of_get_property(dp, "model", NULL); + struct linux_prom_registers clk_reg[2]; + char model[128]; + register int node, cpuunit, bootbus; + struct resource r; - if (!model) - return -ENODEV; + cpuunit = bootbus = 0; + memset(&r, 0, sizeof(r)); - if (!strcmp(model, "mk48t02")) { - sp_clock_typ = MSTK48T02; + /* Determine the correct starting PROM node for the probe. */ + node = prom_getchild(prom_root_node); + switch (sparc_cpu_model) { + case sun4c: + break; + case sun4m: + node = prom_getchild(prom_searchsiblings(node, "obio")); + break; + case sun4d: + node = prom_getchild(bootbus = prom_searchsiblings(prom_getchild(cpuunit = prom_searchsiblings(node, "cpu-unit")), "bootbus")); + break; + default: + prom_printf("CLOCK: Unsupported architecture!\n"); + prom_halt(); + } + + /* Find the PROM node describing the real time clock. */ + sp_clock_typ = MSTK_INVALID; + node = prom_searchsiblings(node,"eeprom"); + if (!node) { + prom_printf("CLOCK: No clock found!\n"); + prom_halt(); + } + /* Get the model name and setup everything up. */ + model[0] = '\0'; + prom_getstring(node, "model", model, sizeof(model)); + if (strcmp(model, "mk48t02") == 0) { + sp_clock_typ = MSTK48T02; + if (prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) { + prom_printf("clock_probe: FAILED!\n"); + prom_halt(); + } + if (sparc_cpu_model == sun4d) + prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1); + else + prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ - mstk48t02_regs = of_ioremap(&op->resource[0], 0, - sizeof(struct mostek48t02), - "mk48t02"); + r.flags = clk_reg[0].which_io; + r.start = clk_reg[0].phys_addr; + mstk48t02_regs = sbus_ioremap(&r, 0, + sizeof(struct mostek48t02), "mk48t02"); mstk48t08_regs = NULL; /* To catch weirdness */ - } else if (!strcmp(model, "mk48t08")) { + } else if (strcmp(model, "mk48t08") == 0) { sp_clock_typ = MSTK48T08; - mstk48t08_regs = of_ioremap(&op->resource[0], 0, - sizeof(struct mostek48t08), - "mk48t08"); + if(prom_getproperty(node, "reg", (char *) clk_reg, + sizeof(clk_reg)) == -1) { + prom_printf("clock_probe: FAILED!\n"); + prom_halt(); + } + if (sparc_cpu_model == sun4d) + prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1); + else + prom_apply_obio_ranges(clk_reg, 1); + /* Map the clock register io area read-only */ + /* XXX r/o attribute is somewhere in r.flags */ + r.flags = clk_reg[0].which_io; + r.start = clk_reg[0].phys_addr; + mstk48t08_regs = sbus_ioremap(&r, 0, + sizeof(struct mostek48t08), "mk48t08"); mstk48t02_regs = &mstk48t08_regs->regs; - } else - return -ENODEV; + } else { + prom_printf("CLOCK: Unknown model name '%s'\n",model); + prom_halt(); + } /* Report a low battery voltage condition. */ if (has_low_battery()) @@ -307,28 +358,6 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id /* Kick start the clock if it is completely stopped. */ if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) kick_start_clock(); - - return 0; -} - -static struct of_device_id clock_match[] = { - { - .name = "eeprom", - }, - {}, -}; - -static struct of_platform_driver clock_driver = { - .name = "clock", - .match_table = clock_match, - .probe = clock_probe, -}; - - -/* Probe for the mostek real time clock chip. */ -static void clock_init(void) -{ - of_register_driver(&clock_driver, &of_bus_type); } void __init sbus_time_init(void) @@ -347,7 +376,7 @@ void __init sbus_time_init(void) if (ARCH_SUN4) sun4_clock_probe(); else - clock_init(); + clock_probe(); sparc_init_timers(timer_interrupt); diff --git a/trunk/arch/sparc64/kernel/auxio.c b/trunk/arch/sparc64/kernel/auxio.c index 718350aba1ec..c2c69c167d18 100644 --- a/trunk/arch/sparc64/kernel/auxio.c +++ b/trunk/arch/sparc64/kernel/auxio.c @@ -11,9 +11,10 @@ #include #include -#include -#include +#include #include +#include +#include #include void __iomem *auxio_register = NULL; @@ -110,6 +111,12 @@ void auxio_set_lte(int on) } } +static void __devinit auxio_report_dev(struct device_node *dp) +{ + printk(KERN_INFO "AUXIO: Found device at %s\n", + dp->full_name); +} + static struct of_device_id auxio_match[] = { { .name = "auxio", @@ -119,48 +126,67 @@ static struct of_device_id auxio_match[] = { MODULE_DEVICE_TABLE(of, auxio_match); -static int __devinit auxio_probe(struct of_device *dev, const struct of_device_id *match) +#ifdef CONFIG_SBUS +static int __devinit auxio_sbus_probe(struct of_device *dev, const struct of_device_id *match) { - struct device_node *dp = dev->node; - unsigned long size; - - if (!strcmp(dp->parent->name, "ebus")) { - auxio_devtype = AUXIO_TYPE_EBUS; - size = sizeof(u32); - } else if (!strcmp(dp->parent->name, "sbus")) { - auxio_devtype = AUXIO_TYPE_SBUS; - size = 1; - } else { - printk("auxio: Unknown parent bus type [%s]\n", - dp->parent->name); + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + + auxio_devtype = AUXIO_TYPE_SBUS; + auxio_register = sbus_ioremap(&sdev->resource[0], 0, + sdev->reg_addrs[0].reg_size, + "auxiliaryIO"); + if (!auxio_register) return -ENODEV; - } - auxio_register = of_ioremap(&dev->resource[0], 0, size, "auxio"); + + auxio_report_dev(dev->node); + return 0; +} + +static struct of_platform_driver auxio_sbus_driver = { + .name = "auxio", + .match_table = auxio_match, + .probe = auxio_sbus_probe, +}; +#endif + +#ifdef CONFIG_PCI +static int __devinit auxio_ebus_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct linux_ebus_device *edev = to_ebus_device(&dev->dev); + + auxio_devtype = AUXIO_TYPE_EBUS; + auxio_register = ioremap(edev->resource[0].start, sizeof(u32)); if (!auxio_register) return -ENODEV; - printk(KERN_INFO "AUXIO: Found device at %s\n", - dp->full_name); + auxio_report_dev(dev->node); - if (auxio_devtype == AUXIO_TYPE_EBUS) - auxio_set_led(AUXIO_LED_ON); + auxio_set_led(AUXIO_LED_ON); return 0; } -static struct of_platform_driver auxio_driver = { +static struct of_platform_driver auxio_ebus_driver = { .name = "auxio", .match_table = auxio_match, - .probe = auxio_probe, + .probe = auxio_ebus_probe, }; +#endif -static int __init auxio_init(void) +static int __init auxio_probe(void) { - return of_register_driver(&auxio_driver, &of_bus_type); +#ifdef CONFIG_SBUS + of_register_driver(&auxio_sbus_driver, &sbus_bus_type); +#endif +#ifdef CONFIG_PCI + of_register_driver(&auxio_ebus_driver, &ebus_bus_type); +#endif + + return 0; } /* Must be after subsys_initcall() so that busses are probed. Must * be before device_initcall() because things like the floppy driver * need to use the AUXIO register. */ -fs_initcall(auxio_init); +fs_initcall(auxio_probe); diff --git a/trunk/arch/sparc64/kernel/ebus.c b/trunk/arch/sparc64/kernel/ebus.c index aac014d15ad3..98e0a8cbeecd 100644 --- a/trunk/arch/sparc64/kernel/ebus.c +++ b/trunk/arch/sparc64/kernel/ebus.c @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include #include @@ -281,12 +279,45 @@ static inline void *ebus_alloc(size_t size) return mem; } -static void __init fill_ebus_child(struct device_node *dp, - struct linux_ebus_child *dev, - int non_standard_regs) +int __init ebus_intmap_match(struct linux_ebus *ebus, + struct linux_prom_registers *reg, + int *interrupt) +{ + struct linux_prom_ebus_intmap *imap; + struct linux_prom_ebus_intmask *imask; + unsigned int hi, lo, irq; + int i, len, n_imap; + + imap = of_get_property(ebus->prom_node, "interrupt-map", &len); + if (!imap) + return 0; + n_imap = len / sizeof(imap[0]); + + imask = of_get_property(ebus->prom_node, "interrupt-map-mask", NULL); + if (!imask) + return 0; + + hi = reg->which_io & imask->phys_hi; + lo = reg->phys_addr & imask->phys_lo; + irq = *interrupt & imask->interrupt; + for (i = 0; i < n_imap; i++) { + if ((imap[i].phys_hi == hi) && + (imap[i].phys_lo == lo) && + (imap[i].interrupt == irq)) { + *interrupt = imap[i].cinterrupt; + return 0; + } + } + return -1; +} + +void __init fill_ebus_child(struct device_node *dp, + struct linux_prom_registers *preg, + struct linux_ebus_child *dev, + int non_standard_regs) { - struct of_device *op; int *regs; + int *irqs; int i, len; dev->prom_node = dp; @@ -323,16 +354,12 @@ static void __init fill_ebus_child(struct device_node *dp, } } - op = of_find_device_by_node(dp); - if (!op) { - dev->num_irqs = 0; - } else { - dev->num_irqs = op->num_irqs; - for (i = 0; i < dev->num_irqs; i++) - dev->irqs[i] = op->irqs[i]; - } + for (i = 0; i < PROMINTR_MAX; i++) + dev->irqs[i] = PCI_IRQ_NONE; - if (!dev->num_irqs) { + irqs = of_get_property(dp, "interrupts", &len); + if (!irqs) { + dev->num_irqs = 0; /* * Oh, well, some PROMs don't export interrupts * property to children of EBus devices... @@ -348,6 +375,23 @@ static void __init fill_ebus_child(struct device_node *dp, dev->irqs[0] = dev->parent->irqs[1]; } } + } else { + dev->num_irqs = len / sizeof(irqs[0]); + for (i = 0; i < dev->num_irqs; i++) { + struct pci_pbm_info *pbm = dev->bus->parent; + struct pci_controller_info *p = pbm->parent; + + if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) { + dev->irqs[i] = p->irq_build(pbm, + dev->bus->self, + irqs[i]); + } else { + /* If we get a bogus interrupt property, just + * record the raw value instead of punting. + */ + dev->irqs[i] = irqs[i]; + } + } } } @@ -359,32 +403,72 @@ static int __init child_regs_nonstandard(struct linux_ebus_device *dev) return 0; } -static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) +void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) { + struct linux_prom_registers *regs; struct linux_ebus_child *child; - struct of_device *op; - int i, len; + int *irqs; + int i, n, len; dev->prom_node = dp; printk(" [%s", dp->name); - op = of_find_device_by_node(dp); - if (!op) { + regs = of_get_property(dp, "reg", &len); + if (!regs) { dev->num_addrs = 0; - dev->num_irqs = 0; - } else { - (void) of_get_property(dp, "reg", &len); - dev->num_addrs = len / sizeof(struct linux_prom_registers); + goto probe_interrupts; + } - for (i = 0; i < dev->num_addrs; i++) - memcpy(&dev->resource[i], - &op->resource[i], - sizeof(struct resource)); + if (len % sizeof(struct linux_prom_registers)) { + prom_printf("UGH: proplen for %s was %d, need multiple of %d\n", + dev->prom_node->name, len, + (int)sizeof(struct linux_prom_registers)); + prom_halt(); + } + dev->num_addrs = len / sizeof(struct linux_prom_registers); + + for (i = 0; i < dev->num_addrs; i++) { + /* XXX Learn how to interpret ebus ranges... -DaveM */ + if (regs[i].which_io >= 0x10) + n = (regs[i].which_io - 0x10) >> 2; + else + n = regs[i].which_io; + + dev->resource[i].start = dev->bus->self->resource[n].start; + dev->resource[i].start += (unsigned long)regs[i].phys_addr; + dev->resource[i].end = + (dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL); + dev->resource[i].flags = IORESOURCE_MEM; + dev->resource[i].name = dev->prom_node->name; + request_resource(&dev->bus->self->resource[n], + &dev->resource[i]); + } - dev->num_irqs = op->num_irqs; - for (i = 0; i < dev->num_irqs; i++) - dev->irqs[i] = op->irqs[i]; +probe_interrupts: + for (i = 0; i < PROMINTR_MAX; i++) + dev->irqs[i] = PCI_IRQ_NONE; + + irqs = of_get_property(dp, "interrupts", &len); + if (!irqs) { + dev->num_irqs = 0; + } else { + dev->num_irqs = len / sizeof(irqs[0]); + for (i = 0; i < dev->num_irqs; i++) { + struct pci_pbm_info *pbm = dev->bus->parent; + struct pci_controller_info *p = pbm->parent; + + if (ebus_intmap_match(dev->bus, ®s[0], &irqs[i]) != -1) { + dev->irqs[i] = p->irq_build(pbm, + dev->bus->self, + irqs[i]); + } else { + /* If we get a bogus interrupt property, just + * record the raw value instead of punting. + */ + dev->irqs[i] = irqs[i]; + } + } } dev->ofdev.node = dp; @@ -406,7 +490,7 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de child->next = NULL; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(dp, child, + fill_ebus_child(dp, regs, child, child_regs_nonstandard(dev)); while ((dp = dp->sibling) != NULL) { @@ -416,7 +500,7 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de child->next = NULL; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(dp, child, + fill_ebus_child(dp, regs, child, child_regs_nonstandard(dev)); } } diff --git a/trunk/arch/sparc64/kernel/irq.c b/trunk/arch/sparc64/kernel/irq.c index eebe02f3f4cb..ab9e640df228 100644 --- a/trunk/arch/sparc64/kernel/irq.c +++ b/trunk/arch/sparc64/kernel/irq.c @@ -414,10 +414,6 @@ void irq_install_pre_handler(int virt_irq, data->pre_handler_arg1 = arg1; data->pre_handler_arg2 = arg2; - if (desc->chip == &sun4u_irq_ack || - desc->chip == &sun4v_irq_ack) - return; - desc->chip = (desc->chip == &sun4u_irq ? &sun4u_irq_ack : &sun4v_irq_ack); } diff --git a/trunk/arch/sparc64/kernel/isa.c b/trunk/arch/sparc64/kernel/isa.c index 0f3aec72ef5f..6f16dee280a8 100644 --- a/trunk/arch/sparc64/kernel/isa.c +++ b/trunk/arch/sparc64/kernel/isa.c @@ -3,8 +3,6 @@ #include #include #include -#include -#include #include struct sparc_isa_bridge *isa_chain; @@ -48,16 +46,107 @@ isa_dev_get_resource(struct sparc_isa_device *isa_dev) return pregs; } +/* I can't believe they didn't put a real INO in the isa device + * interrupts property. The whole point of the OBP properties + * is to shield the kernel from IRQ routing details. + * + * The P1275 standard for ISA devices seems to also have been + * totally ignored. + * + * On later systems, an interrupt-map and interrupt-map-mask scheme + * akin to EBUS is used. + */ +static struct { + int obp_irq; + int pci_ino; +} grover_irq_table[] = { + { 1, 0x00 }, /* dma, unknown ino at this point */ + { 2, 0x27 }, /* floppy */ + { 3, 0x22 }, /* parallel */ + { 4, 0x2b }, /* serial */ + { 5, 0x25 }, /* acpi power management */ + + { 0, 0x00 } /* end of table */ +}; + +static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev, + struct sparc_isa_bridge *isa_br, + int *interrupt, + struct linux_prom_registers *reg) +{ + struct linux_prom_ebus_intmap *imap; + struct linux_prom_ebus_intmap *imask; + unsigned int hi, lo, irq; + int i, len, n_imap; + + imap = of_get_property(isa_br->prom_node, "interrupt-map", &len); + if (!imap) + return 0; + n_imap = len / sizeof(imap[0]); + + imask = of_get_property(isa_br->prom_node, "interrupt-map-mask", NULL); + if (!imask) + return 0; + + hi = reg->which_io & imask->phys_hi; + lo = reg->phys_addr & imask->phys_lo; + irq = *interrupt & imask->interrupt; + for (i = 0; i < n_imap; i++) { + if ((imap[i].phys_hi == hi) && + (imap[i].phys_lo == lo) && + (imap[i].interrupt == irq)) { + *interrupt = imap[i].cinterrupt; + return 0; + } + } + return -1; +} + static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev, struct linux_prom_registers *pregs) { - struct of_device *op = of_find_device_by_node(isa_dev->prom_node); + int irq_prop; - if (!op || !op->num_irqs) { - isa_dev->irq = PCI_IRQ_NONE; + irq_prop = of_getintprop_default(isa_dev->prom_node, + "interrupts", -1); + if (irq_prop <= 0) { + goto no_irq; } else { - isa_dev->irq = op->irqs[0]; + struct pci_controller_info *pcic; + struct pci_pbm_info *pbm; + int i; + + if (of_find_property(isa_dev->bus->prom_node, + "interrupt-map", NULL)) { + if (!isa_dev_get_irq_using_imap(isa_dev, + isa_dev->bus, + &irq_prop, + pregs)) + goto route_irq; + } + + for (i = 0; grover_irq_table[i].obp_irq != 0; i++) { + if (grover_irq_table[i].obp_irq == irq_prop) { + int ino = grover_irq_table[i].pci_ino; + + if (ino == 0) + goto no_irq; + + irq_prop = ino; + goto route_irq; + } + } + goto no_irq; + +route_irq: + pbm = isa_dev->bus->parent; + pcic = pbm->parent; + isa_dev->irq = pcic->irq_build(pbm, NULL, irq_prop); + return; } + +no_irq: + isa_dev->irq = PCI_IRQ_NONE; } static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev) diff --git a/trunk/arch/sparc64/kernel/of_device.c b/trunk/arch/sparc64/kernel/of_device.c index 3670dc8a7d5f..768475bbce82 100644 --- a/trunk/arch/sparc64/kernel/of_device.c +++ b/trunk/arch/sparc64/kernel/of_device.c @@ -129,43 +129,6 @@ static int of_device_resume(struct device * dev) return error; } -void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name) -{ - unsigned long ret = res->start + offset; - - if (!request_region(ret, size, name)) - ret = 0; - - return (void __iomem *) ret; -} -EXPORT_SYMBOL(of_ioremap); - -void of_iounmap(void __iomem *base, unsigned long size) -{ - release_region((unsigned long) base, size); -} -EXPORT_SYMBOL(of_iounmap); - -static int node_match(struct device *dev, void *data) -{ - struct of_device *op = to_of_device(dev); - struct device_node *dp = data; - - return (op->node == dp); -} - -struct of_device *of_find_device_by_node(struct device_node *dp) -{ - struct device *dev = bus_find_device(&of_bus_type, NULL, - dp, node_match); - - if (dev) - return to_of_device(dev); - - return NULL; -} -EXPORT_SYMBOL(of_find_device_by_node); - #ifdef CONFIG_PCI struct bus_type isa_bus_type = { .name = "isa", @@ -200,654 +163,10 @@ struct bus_type sbus_bus_type = { EXPORT_SYMBOL(sbus_bus_type); #endif -struct bus_type of_bus_type = { - .name = "of", - .match = of_platform_bus_match, - .probe = of_device_probe, - .remove = of_device_remove, - .suspend = of_device_suspend, - .resume = of_device_resume, -}; -EXPORT_SYMBOL(of_bus_type); - -static inline u64 of_read_addr(u32 *cell, int size) -{ - u64 r = 0; - while (size--) - r = (r << 32) | *(cell++); - return r; -} - -static void __init get_cells(struct device_node *dp, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = of_n_addr_cells(dp); - if (sizec) - *sizec = of_n_size_cells(dp); -} - -/* Max address size we deal with */ -#define OF_MAX_ADDR_CELLS 4 - -struct of_bus { - const char *name; - const char *addr_prop_name; - int (*match)(struct device_node *parent); - void (*count_cells)(struct device_node *child, - int *addrc, int *sizec); - u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); - int (*translate)(u32 *addr, u64 offset, int na); - unsigned int (*get_flags)(u32 *addr); -}; - -/* - * Default translator (generic bus) - */ - -static void of_bus_default_count_cells(struct device_node *dev, - int *addrc, int *sizec) -{ - get_cells(dev, addrc, sizec); -} - -static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) -{ - u64 cp, s, da; - - cp = of_read_addr(range, na); - s = of_read_addr(range + na + pna, ns); - da = of_read_addr(addr, na); - - if (da < cp || da >= (cp + s)) - return OF_BAD_ADDR; - return da - cp; -} - -static int of_bus_default_translate(u32 *addr, u64 offset, int na) -{ - u64 a = of_read_addr(addr, na); - memset(addr, 0, na * 4); - a += offset; - if (na > 1) - addr[na - 2] = a >> 32; - addr[na - 1] = a & 0xffffffffu; - - return 0; -} - -static unsigned int of_bus_default_get_flags(u32 *addr) -{ - return IORESOURCE_MEM; -} - -/* - * PCI bus specific translator - */ - -static int of_bus_pci_match(struct device_node *np) -{ - return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); -} - -static void of_bus_pci_count_cells(struct device_node *np, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 3; - if (sizec) - *sizec = 2; -} - -static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) -{ - u64 cp, s, da; - - /* Check address type match */ - if ((addr[0] ^ range[0]) & 0x03000000) - return OF_BAD_ADDR; - - /* Read address values, skipping high cell */ - cp = of_read_addr(range + 1, na - 1); - s = of_read_addr(range + na + pna, ns); - da = of_read_addr(addr + 1, na - 1); - - if (da < cp || da >= (cp + s)) - return OF_BAD_ADDR; - return da - cp; -} - -static int of_bus_pci_translate(u32 *addr, u64 offset, int na) -{ - return of_bus_default_translate(addr + 1, offset, na - 1); -} - -static unsigned int of_bus_pci_get_flags(u32 *addr) -{ - unsigned int flags = 0; - u32 w = addr[0]; - - switch((w >> 24) & 0x03) { - case 0x01: - flags |= IORESOURCE_IO; - case 0x02: /* 32 bits */ - case 0x03: /* 64 bits */ - flags |= IORESOURCE_MEM; - } - if (w & 0x40000000) - flags |= IORESOURCE_PREFETCH; - return flags; -} - -/* - * ISA bus specific translator - */ - -static int of_bus_isa_match(struct device_node *np) -{ - return !strcmp(np->name, "isa"); -} - -static void of_bus_isa_count_cells(struct device_node *child, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 2; - if (sizec) - *sizec = 1; -} - -static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna) -{ - u64 cp, s, da; - - /* Check address type match */ - if ((addr[0] ^ range[0]) & 0x00000001) - return OF_BAD_ADDR; - - /* Read address values, skipping high cell */ - cp = of_read_addr(range + 1, na - 1); - s = of_read_addr(range + na + pna, ns); - da = of_read_addr(addr + 1, na - 1); - - if (da < cp || da >= (cp + s)) - return OF_BAD_ADDR; - return da - cp; -} - -static int of_bus_isa_translate(u32 *addr, u64 offset, int na) -{ - return of_bus_default_translate(addr + 1, offset, na - 1); -} - -static unsigned int of_bus_isa_get_flags(u32 *addr) -{ - unsigned int flags = 0; - u32 w = addr[0]; - - if (w & 1) - flags |= IORESOURCE_IO; - else - flags |= IORESOURCE_MEM; - return flags; -} - -/* - * SBUS bus specific translator - */ - -static int of_bus_sbus_match(struct device_node *np) -{ - return !strcmp(np->name, "sbus") || - !strcmp(np->name, "sbi"); -} - -static void of_bus_sbus_count_cells(struct device_node *child, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 2; - if (sizec) - *sizec = 1; -} - -static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) -{ - return of_bus_default_map(addr, range, na, ns, pna); -} - -static int of_bus_sbus_translate(u32 *addr, u64 offset, int na) -{ - return of_bus_default_translate(addr, offset, na); -} - -static unsigned int of_bus_sbus_get_flags(u32 *addr) -{ - return IORESOURCE_MEM; -} - - -/* - * Array of bus specific translators - */ - -static struct of_bus of_busses[] = { - /* PCI */ - { - .name = "pci", - .addr_prop_name = "assigned-addresses", - .match = of_bus_pci_match, - .count_cells = of_bus_pci_count_cells, - .map = of_bus_pci_map, - .translate = of_bus_pci_translate, - .get_flags = of_bus_pci_get_flags, - }, - /* ISA */ - { - .name = "isa", - .addr_prop_name = "reg", - .match = of_bus_isa_match, - .count_cells = of_bus_isa_count_cells, - .map = of_bus_isa_map, - .translate = of_bus_isa_translate, - .get_flags = of_bus_isa_get_flags, - }, - /* SBUS */ - { - .name = "sbus", - .addr_prop_name = "reg", - .match = of_bus_sbus_match, - .count_cells = of_bus_sbus_count_cells, - .map = of_bus_sbus_map, - .translate = of_bus_sbus_translate, - .get_flags = of_bus_sbus_get_flags, - }, - /* Default */ - { - .name = "default", - .addr_prop_name = "reg", - .match = NULL, - .count_cells = of_bus_default_count_cells, - .map = of_bus_default_map, - .translate = of_bus_default_translate, - .get_flags = of_bus_default_get_flags, - }, -}; - -static struct of_bus *of_match_bus(struct device_node *np) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(of_busses); i ++) - if (!of_busses[i].match || of_busses[i].match(np)) - return &of_busses[i]; - BUG(); - return NULL; -} - -static int __init build_one_resource(struct device_node *parent, - struct of_bus *bus, - struct of_bus *pbus, - u32 *addr, - int na, int ns, int pna) -{ - u32 *ranges; - unsigned int rlen; - int rone; - u64 offset = OF_BAD_ADDR; - - ranges = of_get_property(parent, "ranges", &rlen); - if (ranges == NULL || rlen == 0) { - offset = of_read_addr(addr, na); - memset(addr, 0, pna * 4); - goto finish; - } - - /* Now walk through the ranges */ - rlen /= 4; - rone = na + pna + ns; - for (; rlen >= rone; rlen -= rone, ranges += rone) { - offset = bus->map(addr, ranges, na, ns, pna); - if (offset != OF_BAD_ADDR) - break; - } - if (offset == OF_BAD_ADDR) - return 1; - - memcpy(addr, ranges + na, 4 * pna); - -finish: - /* Translate it into parent bus space */ - return pbus->translate(addr, offset, pna); -} - -static void __init build_device_resources(struct of_device *op, - struct device *parent) -{ - struct of_device *p_op; - struct of_bus *bus; - int na, ns; - int index, num_reg; - void *preg; - - if (!parent) - return; - - p_op = to_of_device(parent); - bus = of_match_bus(p_op->node); - bus->count_cells(op->node, &na, &ns); - - preg = of_get_property(op->node, bus->addr_prop_name, &num_reg); - if (!preg || num_reg == 0) - return; - - /* Convert to num-cells. */ - num_reg /= 4; - - /* Conver to num-entries. */ - num_reg /= na + ns; - - for (index = 0; index < num_reg; index++) { - struct resource *r = &op->resource[index]; - u32 addr[OF_MAX_ADDR_CELLS]; - u32 *reg = (preg + (index * ((na + ns) * 4))); - struct device_node *dp = op->node; - struct device_node *pp = p_op->node; - struct of_bus *pbus; - u64 size, result = OF_BAD_ADDR; - unsigned long flags; - int dna, dns; - int pna, pns; - - size = of_read_addr(reg + na, ns); - flags = bus->get_flags(reg); - - memcpy(addr, reg, na * 4); - - /* If the immediate parent has no ranges property to apply, - * just use a 1<->1 mapping. Unless it is the 'dma' child - * of an isa bus, which must be passed up towards the root. - * - * Also, don't try to translate PMU bus device registers. - */ - if ((of_find_property(pp, "ranges", NULL) == NULL && - strcmp(pp->name, "dma") != 0) || - !strcmp(pp->name, "pmu")) { - result = of_read_addr(addr, na); - goto build_res; - } - - dna = na; - dns = ns; - - while (1) { - dp = pp; - pp = dp->parent; - if (!pp) { - result = of_read_addr(addr, dna); - break; - } - - pbus = of_match_bus(pp); - pbus->count_cells(dp, &pna, &pns); - - if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) - break; - - dna = pna; - dns = pns; - bus = pbus; - } - - build_res: - memset(r, 0, sizeof(*r)); - if (result != OF_BAD_ADDR) { - r->start = result; - r->end = result + size - 1; - r->flags = flags; - } else { - r->start = ~0UL; - r->end = ~0UL; - } - r->name = op->node->name; - } -} - -static struct device_node * __init -apply_interrupt_map(struct device_node *dp, struct device_node *pp, - u32 *imap, int imlen, u32 *imask, - unsigned int *irq_p) -{ - struct device_node *cp; - unsigned int irq = *irq_p; - struct of_bus *bus; - phandle handle; - u32 *reg; - int na, num_reg, i; - - bus = of_match_bus(pp); - bus->count_cells(dp, &na, NULL); - - reg = of_get_property(dp, "reg", &num_reg); - if (!reg || !num_reg) - return NULL; - - imlen /= ((na + 3) * 4); - handle = 0; - for (i = 0; i < imlen; i++) { - int j; - - for (j = 0; j < na; j++) { - if ((reg[j] & imask[j]) != imap[j]) - goto next; - } - if (imap[na] == irq) { - handle = imap[na + 1]; - irq = imap[na + 2]; - break; - } - - next: - imap += (na + 3); - } - if (i == imlen) - return NULL; - - *irq_p = irq; - cp = of_find_node_by_phandle(handle); - - return cp; -} - -static unsigned int __init pci_irq_swizzle(struct device_node *dp, - struct device_node *pp, - unsigned int irq) -{ - struct linux_prom_pci_registers *regs; - unsigned int devfn, slot, ret; - - if (irq < 1 || irq > 4) - return irq; - - regs = of_get_property(dp, "reg", NULL); - if (!regs) - return irq; - - devfn = (regs->phys_hi >> 8) & 0xff; - slot = (devfn >> 3) & 0x1f; - - ret = ((irq - 1 + (slot & 3)) & 3) + 1; - - return ret; -} - -static unsigned int __init build_one_device_irq(struct of_device *op, - struct device *parent, - unsigned int irq) -{ - struct device_node *dp = op->node; - struct device_node *pp, *ip; - unsigned int orig_irq = irq; - - if (irq == 0xffffffff) - return irq; - - if (dp->irq_trans) { - irq = dp->irq_trans->irq_build(dp, irq, - dp->irq_trans->data); -#if 1 - printk("%s: direct translate %x --> %x\n", - dp->full_name, orig_irq, irq); -#endif - return irq; - } - - /* Something more complicated. Walk up to the root, applying - * interrupt-map or bus specific translations, until we hit - * an IRQ translator. - * - * If we hit a bus type or situation we cannot handle, we - * stop and assume that the original IRQ number was in a - * format which has special meaning to it's immediate parent. - */ - pp = dp->parent; - ip = NULL; - while (pp) { - void *imap, *imsk; - int imlen; - - imap = of_get_property(pp, "interrupt-map", &imlen); - imsk = of_get_property(pp, "interrupt-map-mask", NULL); - if (imap && imsk) { - struct device_node *iret; - int this_orig_irq = irq; - - iret = apply_interrupt_map(dp, pp, - imap, imlen, imsk, - &irq); -#if 1 - printk("%s: Apply [%s:%x] imap --> [%s:%x]\n", - op->node->full_name, - pp->full_name, this_orig_irq, - (iret ? iret->full_name : "NULL"), irq); -#endif - if (!iret) - break; - - if (iret->irq_trans) { - ip = iret; - break; - } - } else { - if (!strcmp(pp->type, "pci") || - !strcmp(pp->type, "pciex")) { - unsigned int this_orig_irq = irq; - - irq = pci_irq_swizzle(dp, pp, irq); -#if 1 - printk("%s: PCI swizzle [%s] %x --> %x\n", - op->node->full_name, - pp->full_name, this_orig_irq, irq); -#endif - } - - if (pp->irq_trans) { - ip = pp; - break; - } - } - dp = pp; - pp = pp->parent; - } - if (!ip) - return orig_irq; - - irq = ip->irq_trans->irq_build(op->node, irq, - ip->irq_trans->data); -#if 1 - printk("%s: Apply IRQ trans [%s] %x --> %x\n", - op->node->full_name, ip->full_name, orig_irq, irq); -#endif - - return irq; -} - -static struct of_device * __init scan_one_device(struct device_node *dp, - struct device *parent) -{ - struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); - unsigned int *irq; - int len, i; - - if (!op) - return NULL; - - op->node = dp; - - op->clock_freq = of_getintprop_default(dp, "clock-frequency", - (25*1000*1000)); - op->portid = of_getintprop_default(dp, "upa-portid", -1); - if (op->portid == -1) - op->portid = of_getintprop_default(dp, "portid", -1); - - irq = of_get_property(dp, "interrupts", &len); - if (irq) { - memcpy(op->irqs, irq, len); - op->num_irqs = len / 4; - } else { - op->num_irqs = 0; - } - - build_device_resources(op, parent); - for (i = 0; i < op->num_irqs; i++) - op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]); - - op->dev.parent = parent; - op->dev.bus = &of_bus_type; - if (!parent) - strcpy(op->dev.bus_id, "root"); - else - strcpy(op->dev.bus_id, dp->path_component_name); - - if (of_device_register(op)) { - printk("%s: Could not register of device.\n", - dp->full_name); - kfree(op); - op = NULL; - } - - return op; -} - -static void __init scan_tree(struct device_node *dp, struct device *parent) -{ - while (dp) { - struct of_device *op = scan_one_device(dp, parent); - - if (op) - scan_tree(dp->child, &op->dev); - - dp = dp->sibling; - } -} - -static void __init scan_of_devices(void) -{ - struct device_node *root = of_find_node_by_path("/"); - struct of_device *parent; - - parent = scan_one_device(root, NULL); - if (!parent) - return; - - scan_tree(root->child, &parent->dev); -} - static int __init of_bus_driver_init(void) { - int err; + int err = 0; - err = bus_register(&of_bus_type); #ifdef CONFIG_PCI if (!err) err = bus_register(&isa_bus_type); @@ -858,11 +177,7 @@ static int __init of_bus_driver_init(void) if (!err) err = bus_register(&sbus_bus_type); #endif - - if (!err) - scan_of_devices(); - - return err; + return 0; } postcore_initcall(of_bus_driver_init); diff --git a/trunk/arch/sparc64/kernel/pci.c b/trunk/arch/sparc64/kernel/pci.c index 04ea6c2eb7a1..20ca9ec8fd3b 100644 --- a/trunk/arch/sparc64/kernel/pci.c +++ b/trunk/arch/sparc64/kernel/pci.c @@ -307,6 +307,7 @@ static void __init pci_scan_each_controller_bus(void) p->scan_bus(p); } +extern void clock_probe(void); extern void power_init(void); static int __init pcibios_init(void) @@ -319,6 +320,7 @@ static int __init pcibios_init(void) isa_init(); ebus_init(); + clock_probe(); power_init(); return 0; @@ -404,8 +406,14 @@ void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res, } EXPORT_SYMBOL(pcibios_bus_to_resource); +extern int pci_irq_verbose; + char * __init pcibios_setup(char *str) { + if (!strcmp(str, "irq_verbose")) { + pci_irq_verbose = 1; + return NULL; + } return str; } diff --git a/trunk/arch/sparc64/kernel/pci_common.c b/trunk/arch/sparc64/kernel/pci_common.c index 7a59cc72c844..b06a2955bf5f 100644 --- a/trunk/arch/sparc64/kernel/pci_common.c +++ b/trunk/arch/sparc64/kernel/pci_common.c @@ -10,10 +10,12 @@ #include #include -#include #include "pci_impl.h" +/* Pass "pci=irq_verbose" on the kernel command line to enable this. */ +int pci_irq_verbose; + /* Fix self device of BUS and hook it into BUS->self. * The pci_scan_bus does not do this for the host bridge. */ @@ -167,7 +169,6 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, } pcp->pbm = pbm; pcp->prom_node = dp; - pcp->op = of_find_device_by_node(dp); memcpy(pcp->prom_regs, pregs, nregs * sizeof(struct linux_prom_pci_registers)); pcp->num_prom_regs = nregs; @@ -548,18 +549,296 @@ void __init pci_assign_unassigned(struct pci_pbm_info *pbm, pci_assign_unassigned(pbm, bus); } +static inline unsigned int pci_slot_swivel(struct pci_pbm_info *pbm, + struct pci_dev *toplevel_pdev, + struct pci_dev *pdev, + unsigned int interrupt) +{ + unsigned int ret; + + if (unlikely(interrupt < 1 || interrupt > 4)) { + printk("%s: Device %s interrupt value of %u is strange.\n", + pbm->name, pci_name(pdev), interrupt); + return interrupt; + } + + ret = ((interrupt - 1 + (PCI_SLOT(pdev->devfn) & 3)) & 3) + 1; + + if (pci_irq_verbose) + printk("%s: %s IRQ Swivel %s [%x:%x] -> [%x]\n", + pbm->name, pci_name(toplevel_pdev), pci_name(pdev), + interrupt, PCI_SLOT(pdev->devfn), ret); + + return ret; +} + +static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm, + struct pci_dev *toplevel_pdev, + struct pci_dev *pbus, + struct pci_dev *pdev, + unsigned int interrupt, + struct device_node **cnode) +{ + struct linux_prom_pci_intmap *imap; + struct linux_prom_pci_intmask *imask; + struct pcidev_cookie *pbus_pcp = pbus->sysdata; + struct pcidev_cookie *pdev_pcp = pdev->sysdata; + struct linux_prom_pci_registers *pregs = pdev_pcp->prom_regs; + struct property *prop; + int plen, num_imap, i; + unsigned int hi, mid, lo, irq, orig_interrupt; + + *cnode = pbus_pcp->prom_node; + + prop = of_find_property(pbus_pcp->prom_node, "interrupt-map", &plen); + if (!prop || + (plen % sizeof(struct linux_prom_pci_intmap)) != 0) { + printk("%s: Device %s interrupt-map has bad len %d\n", + pbm->name, pci_name(pbus), plen); + goto no_intmap; + } + imap = prop->value; + num_imap = plen / sizeof(struct linux_prom_pci_intmap); + + prop = of_find_property(pbus_pcp->prom_node, "interrupt-map-mask", &plen); + if (!prop || + (plen % sizeof(struct linux_prom_pci_intmask)) != 0) { + printk("%s: Device %s interrupt-map-mask has bad len %d\n", + pbm->name, pci_name(pbus), plen); + goto no_intmap; + } + imask = prop->value; + + orig_interrupt = interrupt; + + hi = pregs->phys_hi & imask->phys_hi; + mid = pregs->phys_mid & imask->phys_mid; + lo = pregs->phys_lo & imask->phys_lo; + irq = interrupt & imask->interrupt; + + for (i = 0; i < num_imap; i++) { + if (imap[i].phys_hi == hi && + imap[i].phys_mid == mid && + imap[i].phys_lo == lo && + imap[i].interrupt == irq) { + *cnode = of_find_node_by_phandle(imap[i].cnode); + interrupt = imap[i].cinterrupt; + } + } + + if (pci_irq_verbose) + printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n", + pbm->name, pci_name(toplevel_pdev), + pci_name(pbus), pci_name(pdev), + orig_interrupt, interrupt); + +no_intmap: + return interrupt; +} + +/* For each PCI bus on the way to the root: + * 1) If it has an interrupt-map property, apply it. + * 2) Else, swivel the interrupt number based upon the PCI device number. + * + * Return the "IRQ controller" node. If this is the PBM's device node, + * all interrupt translations are complete, else we should use that node's + * "reg" property to apply the PBM's "interrupt-{map,mask}" to the interrupt. + */ +static struct device_node * __init +pci_intmap_match_to_root(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + unsigned int *interrupt) +{ + struct pci_dev *toplevel_pdev = pdev; + struct pcidev_cookie *toplevel_pcp = toplevel_pdev->sysdata; + struct device_node *cnode = toplevel_pcp->prom_node; + + while (pdev->bus->number != pbm->pci_first_busno) { + struct pci_dev *pbus = pdev->bus->self; + struct pcidev_cookie *pcp = pbus->sysdata; + struct property *prop; + + prop = of_find_property(pcp->prom_node, "interrupt-map", NULL); + if (!prop) { + *interrupt = pci_slot_swivel(pbm, toplevel_pdev, + pdev, *interrupt); + cnode = pcp->prom_node; + } else { + *interrupt = pci_apply_intmap(pbm, toplevel_pdev, + pbus, pdev, + *interrupt, &cnode); + + while (pcp->prom_node != cnode && + pbus->bus->number != pbm->pci_first_busno) { + pbus = pbus->bus->self; + pcp = pbus->sysdata; + } + } + pdev = pbus; + + if (cnode == pbm->prom_node) + break; + } + + return cnode; +} + +static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) +{ + struct pcidev_cookie *dev_pcp = pdev->sysdata; + struct pci_pbm_info *pbm = dev_pcp->pbm; + struct linux_prom_pci_registers *reg; + struct device_node *cnode; + struct property *prop; + unsigned int hi, mid, lo, irq; + int i, plen; + + cnode = pci_intmap_match_to_root(pbm, pdev, interrupt); + if (cnode == pbm->prom_node) + goto success; + + prop = of_find_property(cnode, "reg", &plen); + if (!prop || + (plen % sizeof(struct linux_prom_pci_registers)) != 0) { + printk("%s: OBP node %s reg property has bad len %d\n", + pbm->name, cnode->full_name, plen); + goto fail; + } + reg = prop->value; + + hi = reg[0].phys_hi & pbm->pbm_intmask->phys_hi; + mid = reg[0].phys_mid & pbm->pbm_intmask->phys_mid; + lo = reg[0].phys_lo & pbm->pbm_intmask->phys_lo; + irq = *interrupt & pbm->pbm_intmask->interrupt; + + for (i = 0; i < pbm->num_pbm_intmap; i++) { + struct linux_prom_pci_intmap *intmap; + + intmap = &pbm->pbm_intmap[i]; + + if (intmap->phys_hi == hi && + intmap->phys_mid == mid && + intmap->phys_lo == lo && + intmap->interrupt == irq) { + *interrupt = intmap->cinterrupt; + goto success; + } + } + +fail: + return 0; + +success: + if (pci_irq_verbose) + printk("%s: Routing bus[%2x] slot[%2x] to INO[%02x]\n", + pbm->name, + pdev->bus->number, PCI_SLOT(pdev->devfn), + *interrupt); + return 1; +} + static void __init pdev_fixup_irq(struct pci_dev *pdev) { struct pcidev_cookie *pcp = pdev->sysdata; - struct of_device *op = pcp->op; + struct pci_pbm_info *pbm = pcp->pbm; + struct pci_controller_info *p = pbm->parent; + unsigned int portid = pbm->portid; + unsigned int prom_irq; + struct device_node *dp = pcp->prom_node; + struct property *prop; + + /* If this is an empty EBUS device, sometimes OBP fails to + * give it a valid fully specified interrupts property. + * The EBUS hooked up to SunHME on PCI I/O boards of + * Ex000 systems is one such case. + * + * The interrupt is not important so just ignore it. + */ + if (pdev->vendor == PCI_VENDOR_ID_SUN && + pdev->device == PCI_DEVICE_ID_SUN_EBUS && + !dp->child) { + pdev->irq = 0; + return; + } - if (op->irqs[0] == 0xffffffff) { - pdev->irq = PCI_IRQ_NONE; + prop = of_find_property(dp, "interrupts", NULL); + if (!prop) { + pdev->irq = 0; return; } + prom_irq = *(unsigned int *) prop->value; + + if (tlb_type != hypervisor) { + /* Fully specified already? */ + if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) { + pdev->irq = p->irq_build(pbm, pdev, prom_irq); + goto have_irq; + } + + /* An onboard device? (bit 5 set) */ + if ((prom_irq & PCI_IRQ_INO) & 0x20) { + pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq)); + goto have_irq; + } + } + + /* Can we find a matching entry in the interrupt-map? */ + if (pci_intmap_match(pdev, &prom_irq)) { + pdev->irq = p->irq_build(pbm, pdev, (portid << 6) | prom_irq); + goto have_irq; + } + + /* Ok, we have to do it the hard way. */ + { + unsigned int bus, slot, line; + + bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0; + + /* If we have a legal interrupt property, use it as + * the IRQ line. + */ + if (prom_irq > 0 && prom_irq < 5) { + line = ((prom_irq - 1) & 3); + } else { + u8 pci_irq_line; - pdev->irq = op->irqs[0]; + /* Else just directly consult PCI config space. */ + pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line); + line = ((pci_irq_line - 1) & 3); + } + + /* Now figure out the slot. + * + * Basically, device number zero on the top-level bus is + * always the PCI host controller. Slot 0 is then device 1. + * PBM A supports two external slots (0 and 1), and PBM B + * supports 4 external slots (0, 1, 2, and 3). On-board PCI + * devices are wired to device numbers outside of these + * ranges. -DaveM + */ + if (pdev->bus->number == pbm->pci_first_busno) { + slot = PCI_SLOT(pdev->devfn) - pbm->pci_first_slot; + } else { + struct pci_dev *bus_dev; + + /* Underneath a bridge, use slot number of parent + * bridge which is closest to the PBM. + */ + bus_dev = pdev->bus->self; + while (bus_dev->bus && + bus_dev->bus->number != pbm->pci_first_busno) + bus_dev = bus_dev->bus->self; + + slot = PCI_SLOT(bus_dev->devfn) - pbm->pci_first_slot; + } + slot = slot << 2; + + pdev->irq = p->irq_build(pbm, pdev, + ((portid << 6) & PCI_IRQ_IGN) | + (bus | slot | line)); + } +have_irq: pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq & PCI_IRQ_INO); } diff --git a/trunk/arch/sparc64/kernel/pci_psycho.c b/trunk/arch/sparc64/kernel/pci_psycho.c index bf7b32b36705..5b2261ebda6f 100644 --- a/trunk/arch/sparc64/kernel/pci_psycho.c +++ b/trunk/arch/sparc64/kernel/pci_psycho.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "pci_impl.h" #include "iommu_common.h" @@ -209,6 +208,110 @@ static struct pci_ops psycho_ops = { .write = psycho_write_pci_cfg, }; +/* PSYCHO interrupt mapping support. */ +#define PSYCHO_IMAP_A_SLOT0 0x0c00UL +#define PSYCHO_IMAP_B_SLOT0 0x0c20UL +static unsigned long psycho_pcislot_imap_offset(unsigned long ino) +{ + unsigned int bus = (ino & 0x10) >> 4; + unsigned int slot = (ino & 0x0c) >> 2; + + if (bus == 0) + return PSYCHO_IMAP_A_SLOT0 + (slot * 8); + else + return PSYCHO_IMAP_B_SLOT0 + (slot * 8); +} + +#define PSYCHO_IMAP_SCSI 0x1000UL +#define PSYCHO_IMAP_ETH 0x1008UL +#define PSYCHO_IMAP_BPP 0x1010UL +#define PSYCHO_IMAP_AU_REC 0x1018UL +#define PSYCHO_IMAP_AU_PLAY 0x1020UL +#define PSYCHO_IMAP_PFAIL 0x1028UL +#define PSYCHO_IMAP_KMS 0x1030UL +#define PSYCHO_IMAP_FLPY 0x1038UL +#define PSYCHO_IMAP_SHW 0x1040UL +#define PSYCHO_IMAP_KBD 0x1048UL +#define PSYCHO_IMAP_MS 0x1050UL +#define PSYCHO_IMAP_SER 0x1058UL +#define PSYCHO_IMAP_TIM0 0x1060UL +#define PSYCHO_IMAP_TIM1 0x1068UL +#define PSYCHO_IMAP_UE 0x1070UL +#define PSYCHO_IMAP_CE 0x1078UL +#define PSYCHO_IMAP_A_ERR 0x1080UL +#define PSYCHO_IMAP_B_ERR 0x1088UL +#define PSYCHO_IMAP_PMGMT 0x1090UL +#define PSYCHO_IMAP_GFX 0x1098UL +#define PSYCHO_IMAP_EUPA 0x10a0UL + +static unsigned long __onboard_imap_off[] = { +/*0x20*/ PSYCHO_IMAP_SCSI, +/*0x21*/ PSYCHO_IMAP_ETH, +/*0x22*/ PSYCHO_IMAP_BPP, +/*0x23*/ PSYCHO_IMAP_AU_REC, +/*0x24*/ PSYCHO_IMAP_AU_PLAY, +/*0x25*/ PSYCHO_IMAP_PFAIL, +/*0x26*/ PSYCHO_IMAP_KMS, +/*0x27*/ PSYCHO_IMAP_FLPY, +/*0x28*/ PSYCHO_IMAP_SHW, +/*0x29*/ PSYCHO_IMAP_KBD, +/*0x2a*/ PSYCHO_IMAP_MS, +/*0x2b*/ PSYCHO_IMAP_SER, +/*0x2c*/ PSYCHO_IMAP_TIM0, +/*0x2d*/ PSYCHO_IMAP_TIM1, +/*0x2e*/ PSYCHO_IMAP_UE, +/*0x2f*/ PSYCHO_IMAP_CE, +/*0x30*/ PSYCHO_IMAP_A_ERR, +/*0x31*/ PSYCHO_IMAP_B_ERR, +/*0x32*/ PSYCHO_IMAP_PMGMT +}; +#define PSYCHO_ONBOARD_IRQ_BASE 0x20 +#define PSYCHO_ONBOARD_IRQ_LAST 0x32 +#define psycho_onboard_imap_offset(__ino) \ + __onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] + +#define PSYCHO_ICLR_A_SLOT0 0x1400UL +#define PSYCHO_ICLR_SCSI 0x1800UL + +#define psycho_iclr_offset(ino) \ + ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ + (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) + +static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + unsigned int ino) +{ + unsigned long imap, iclr; + unsigned long imap_off, iclr_off; + int inofixup = 0; + + ino &= PCI_IRQ_INO; + if (ino < PSYCHO_ONBOARD_IRQ_BASE) { + /* PCI slot */ + imap_off = psycho_pcislot_imap_offset(ino); + } else { + /* Onboard device */ + if (ino > PSYCHO_ONBOARD_IRQ_LAST) { + prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); + prom_halt(); + } + imap_off = psycho_onboard_imap_offset(ino); + } + + /* Now build the IRQ bucket. */ + imap = pbm->controller_regs + imap_off; + imap += 4; + + iclr_off = psycho_iclr_offset(ino); + iclr = pbm->controller_regs + iclr_off; + iclr += 4; + + if ((ino & 0x20) == 0) + inofixup = ino & 0x03; + + return build_irq(inofixup, iclr, imap); +} + /* PSYCHO error handling support. */ enum psycho_error_type { UE_ERR, CE_ERR, PCI_ERR @@ -841,34 +944,51 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *reg #define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */ #define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */ #define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */ +#define PSYCHO_UE_INO 0x2e +#define PSYCHO_CE_INO 0x2f +#define PSYCHO_PCIERR_A_INO 0x30 +#define PSYCHO_PCIERR_B_INO 0x31 static void psycho_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ - struct of_device *op = of_find_device_by_node(pbm->prom_node); unsigned long base = p->pbm_A.controller_regs; + unsigned int irq, portid = pbm->portid; u64 tmp; - if (!op) - return; + /* Build IRQs and register handlers. */ + irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_UE_INO); + if (request_irq(irq, psycho_ue_intr, + SA_SHIRQ, "PSYCHO UE", p) < 0) { + prom_printf("PSYCHO%d: Cannot register UE interrupt.\n", + p->index); + prom_halt(); + } - /* Psycho interrupt property order is: - * 0: PCIERR PBM B INO - * 1: UE ERR - * 2: CE ERR - * 3: POWER FAIL - * 4: SPARE HARDWARE - * 5: PCIERR PBM A INO - */ + irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_CE_INO); + if (request_irq(irq, psycho_ce_intr, + SA_SHIRQ, "PSYCHO CE", p) < 0) { + prom_printf("PSYCHO%d: Cannot register CE interrupt.\n", + p->index); + prom_halt(); + } - if (op->num_irqs < 6) - return; + pbm = &p->pbm_A; + irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO); + if (request_irq(irq, psycho_pcierr_intr, + SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) { + prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } - request_irq(op->irqs[1], psycho_ue_intr, SA_SHIRQ, "PSYCHO UE", p); - request_irq(op->irqs[2], psycho_ce_intr, SA_SHIRQ, "PSYCHO CE", p); - request_irq(op->irqs[5], psycho_pcierr_intr, SA_SHIRQ, - "PSYCHO PCIERR-A", &p->pbm_A); - request_irq(op->irqs[0], psycho_pcierr_intr, SA_SHIRQ, - "PSYCHO PCIERR-B", &p->pbm_B); + pbm = &p->pbm_B; + irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO); + if (request_irq(irq, psycho_pcierr_intr, + SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) { + prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } /* Enable UE and CE interrupts for controller. */ psycho_write(base + PSYCHO_ECC_CTRL, @@ -1051,7 +1171,9 @@ static void psycho_iommu_init(struct pci_controller_info *p) /* If necessary, hook us up for starfire IRQ translations. */ if (this_is_starfire) - starfire_hookup(p->pbm_A.portid); + p->starfire_cookie = starfire_hookup(p->pbm_A.portid); + else + p->starfire_cookie = NULL; } #define PSYCHO_IRQ_RETRY 0x1a00UL @@ -1286,6 +1408,7 @@ void psycho_init(struct device_node *dp, char *model_name) p->index = pci_num_controllers++; p->pbms_same_domain = 0; p->scan_bus = psycho_scan_bus; + p->irq_build = psycho_irq_build; p->base_address_update = psycho_base_address_update; p->resource_adjust = psycho_resource_adjust; p->pci_ops = &psycho_ops; diff --git a/trunk/arch/sparc64/kernel/pci_sabre.c b/trunk/arch/sparc64/kernel/pci_sabre.c index 5e087b0fb4c9..26f194ce4400 100644 --- a/trunk/arch/sparc64/kernel/pci_sabre.c +++ b/trunk/arch/sparc64/kernel/pci_sabre.c @@ -485,6 +485,114 @@ static struct pci_ops sabre_ops = { .write = sabre_write_pci_cfg, }; +static unsigned long sabre_pcislot_imap_offset(unsigned long ino) +{ + unsigned int bus = (ino & 0x10) >> 4; + unsigned int slot = (ino & 0x0c) >> 2; + + if (bus == 0) + return SABRE_IMAP_A_SLOT0 + (slot * 8); + else + return SABRE_IMAP_B_SLOT0 + (slot * 8); +} + +static unsigned long __onboard_imap_off[] = { +/*0x20*/ SABRE_IMAP_SCSI, +/*0x21*/ SABRE_IMAP_ETH, +/*0x22*/ SABRE_IMAP_BPP, +/*0x23*/ SABRE_IMAP_AU_REC, +/*0x24*/ SABRE_IMAP_AU_PLAY, +/*0x25*/ SABRE_IMAP_PFAIL, +/*0x26*/ SABRE_IMAP_KMS, +/*0x27*/ SABRE_IMAP_FLPY, +/*0x28*/ SABRE_IMAP_SHW, +/*0x29*/ SABRE_IMAP_KBD, +/*0x2a*/ SABRE_IMAP_MS, +/*0x2b*/ SABRE_IMAP_SER, +/*0x2c*/ 0 /* reserved */, +/*0x2d*/ 0 /* reserved */, +/*0x2e*/ SABRE_IMAP_UE, +/*0x2f*/ SABRE_IMAP_CE, +/*0x30*/ SABRE_IMAP_PCIERR, +}; +#define SABRE_ONBOARD_IRQ_BASE 0x20 +#define SABRE_ONBOARD_IRQ_LAST 0x30 +#define sabre_onboard_imap_offset(__ino) \ + __onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE] + +#define sabre_iclr_offset(ino) \ + ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ + (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) + +/* When a device lives behind a bridge deeper in the PCI bus topology + * than APB, a special sequence must run to make sure all pending DMA + * transfers at the time of IRQ delivery are visible in the coherency + * domain by the cpu. This sequence is to perform a read on the far + * side of the non-APB bridge, then perform a read of Sabre's DMA + * write-sync register. + */ +static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) +{ + struct pci_dev *pdev = _arg1; + unsigned long sync_reg = (unsigned long) _arg2; + u16 _unused; + + pci_read_config_word(pdev, PCI_VENDOR_ID, &_unused); + sabre_read(sync_reg); +} + +static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + unsigned int ino) +{ + unsigned long imap, iclr; + unsigned long imap_off, iclr_off; + int inofixup = 0; + int virt_irq; + + ino &= PCI_IRQ_INO; + if (ino < SABRE_ONBOARD_IRQ_BASE) { + /* PCI slot */ + imap_off = sabre_pcislot_imap_offset(ino); + } else { + /* onboard device */ + if (ino > SABRE_ONBOARD_IRQ_LAST) { + prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino); + prom_halt(); + } + imap_off = sabre_onboard_imap_offset(ino); + } + + /* Now build the IRQ bucket. */ + imap = pbm->controller_regs + imap_off; + imap += 4; + + iclr_off = sabre_iclr_offset(ino); + iclr = pbm->controller_regs + iclr_off; + iclr += 4; + + if ((ino & 0x20) == 0) + inofixup = ino & 0x03; + + virt_irq = build_irq(inofixup, iclr, imap); + + if (pdev) { + struct pcidev_cookie *pcp = pdev->sysdata; + + if (pdev->bus->number != pcp->pbm->pci_first_busno) { + struct pci_controller_info *p = pcp->pbm->parent; + + irq_install_pre_handler(virt_irq, + sabre_wsync_handler, + pdev, + (void *) + p->pbm_A.controller_regs + + SABRE_WRSYNC); + } + } + return virt_irq; +} + /* SABRE error handling support. */ static void sabre_check_iommu_error(struct pci_controller_info *p, unsigned long afsr, @@ -821,30 +929,17 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs return IRQ_HANDLED; } +/* XXX What about PowerFail/PowerManagement??? -DaveM */ +#define SABRE_UE_INO 0x2e +#define SABRE_CE_INO 0x2f +#define SABRE_PCIERR_INO 0x30 static void sabre_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ - struct device_node *dp = pbm->prom_node; - struct of_device *op; unsigned long base = pbm->controller_regs; + unsigned long irq, portid = pbm->portid; u64 tmp; - if (pbm->chip_type == PBM_CHIP_TYPE_SABRE) - dp = dp->parent; - - op = of_find_device_by_node(dp); - if (!op) - return; - - /* Sabre/Hummingbird IRQ property layout is: - * 0: PCI ERR - * 1: UE ERR - * 2: CE ERR - * 3: POWER FAIL - */ - if (op->num_irqs < 4) - return; - /* We clear the error bits in the appropriate AFSR before * registering the handler so that we don't get spurious * interrupts. @@ -853,16 +948,32 @@ static void sabre_register_error_handlers(struct pci_controller_info *p) (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE)); - - request_irq(op->irqs[1], sabre_ue_intr, SA_SHIRQ, "SABRE UE", p); + irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_UE_INO); + if (request_irq(irq, sabre_ue_intr, + SA_SHIRQ, "SABRE UE", p) < 0) { + prom_printf("SABRE%d: Cannot register UE interrupt.\n", + p->index); + prom_halt(); + } sabre_write(base + SABRE_CE_AFSR, (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR)); + irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_CE_INO); + if (request_irq(irq, sabre_ce_intr, + SA_SHIRQ, "SABRE CE", p) < 0) { + prom_printf("SABRE%d: Cannot register CE interrupt.\n", + p->index); + prom_halt(); + } - request_irq(op->irqs[2], sabre_ce_intr, SA_SHIRQ, "SABRE CE", p); - request_irq(op->irqs[0], sabre_pcierr_intr, SA_SHIRQ, - "SABRE PCIERR", p); + irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_PCIERR_INO); + if (request_irq(irq, sabre_pcierr_intr, + SA_SHIRQ, "SABRE PCIERR", p) < 0) { + prom_printf("SABRE%d: Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } tmp = sabre_read(base + SABRE_PCICTRL); tmp |= SABRE_PCICTRL_ERREN; @@ -1381,6 +1492,7 @@ void sabre_init(struct device_node *dp, char *model_name) p->index = pci_num_controllers++; p->pbms_same_domain = 1; p->scan_bus = sabre_scan_bus; + p->irq_build = sabre_irq_build; p->base_address_update = sabre_base_address_update; p->resource_adjust = sabre_resource_adjust; p->pci_ops = &sabre_ops; diff --git a/trunk/arch/sparc64/kernel/pci_schizo.c b/trunk/arch/sparc64/kernel/pci_schizo.c index 5c6e2a9b91f8..f16449ccd7bc 100644 --- a/trunk/arch/sparc64/kernel/pci_schizo.c +++ b/trunk/arch/sparc64/kernel/pci_schizo.c @@ -217,6 +217,116 @@ static struct pci_ops schizo_ops = { .write = schizo_write_pci_cfg, }; +/* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the + * imap/iclr registers are per-PBM. + */ +#define SCHIZO_IMAP_BASE 0x1000UL +#define SCHIZO_ICLR_BASE 0x1400UL + +static unsigned long schizo_imap_offset(unsigned long ino) +{ + return SCHIZO_IMAP_BASE + (ino * 8UL); +} + +static unsigned long schizo_iclr_offset(unsigned long ino) +{ + return SCHIZO_ICLR_BASE + (ino * 8UL); +} + +static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) +{ + unsigned long sync_reg = (unsigned long) _arg2; + u64 mask = 1UL << (ino & IMAP_INO); + u64 val; + int limit; + + schizo_write(sync_reg, mask); + + limit = 100000; + val = 0; + while (--limit) { + val = schizo_read(sync_reg); + if (!(val & mask)) + break; + } + if (limit <= 0) { + printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n", + val, mask); + } + + if (_arg1) { + static unsigned char cacheline[64] + __attribute__ ((aligned (64))); + + __asm__ __volatile__("rd %%fprs, %0\n\t" + "or %0, %4, %1\n\t" + "wr %1, 0x0, %%fprs\n\t" + "stda %%f0, [%5] %6\n\t" + "wr %0, 0x0, %%fprs\n\t" + "membar #Sync" + : "=&r" (mask), "=&r" (val) + : "0" (mask), "1" (val), + "i" (FPRS_FEF), "r" (&cacheline[0]), + "i" (ASI_BLK_COMMIT_P)); + } +} + +static unsigned long schizo_ino_to_iclr(struct pci_pbm_info *pbm, + unsigned int ino) +{ + ino &= PCI_IRQ_INO; + return pbm->pbm_regs + schizo_iclr_offset(ino) + 4; +} + +static unsigned long schizo_ino_to_imap(struct pci_pbm_info *pbm, + unsigned int ino) +{ + ino &= PCI_IRQ_INO; + return pbm->pbm_regs + schizo_imap_offset(ino) + 4; +} + +static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + unsigned int ino) +{ + unsigned long imap, iclr; + int ign_fixup; + int virt_irq; + + ino &= PCI_IRQ_INO; + + /* Now build the IRQ bucket. */ + imap = schizo_ino_to_imap(pbm, ino); + iclr = schizo_ino_to_iclr(pbm, ino); + + /* On Schizo, no inofixup occurs. This is because each + * INO has it's own IMAP register. On Psycho and Sabre + * there is only one IMAP register for each PCI slot even + * though four different INOs can be generated by each + * PCI slot. + * + * But, for JBUS variants (essentially, Tomatillo), we have + * to fixup the lowest bit of the interrupt group number. + */ + ign_fixup = 0; + if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { + if (pbm->portid & 1) + ign_fixup = (1 << 6); + } + + virt_irq = build_irq(ign_fixup, iclr, imap); + + if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { + irq_install_pre_handler(virt_irq, + tomatillo_wsync_handler, + ((pbm->chip_version <= 4) ? + (void *) 1 : (void *) 0), + (void *) pbm->sync_reg); + } + + return virt_irq; +} + /* SCHIZO error handling support. */ enum schizo_error_type { UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR @@ -252,6 +362,34 @@ struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino) return &p->pbm_A; } +static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq) +{ + struct pci_pbm_info *pbm; + unsigned long iclr; + + /* Do not clear the interrupt for the other PCI bus. + * + * This "ACK both PBM IRQs" only needs to be performed + * for chip-wide error interrupts. + */ + if ((irq & IMAP_INO) == SCHIZO_PCIERR_A_INO || + (irq & IMAP_INO) == SCHIZO_PCIERR_B_INO) + return; + + pbm = pbm_for_ino(p, irq); + if (pbm == &p->pbm_A) + pbm = &p->pbm_B; + else + pbm = &p->pbm_A; + + schizo_irq_build(pbm, NULL, + (pbm->portid << 6) | (irq & IMAP_INO)); + + iclr = schizo_ino_to_iclr(pbm, + (pbm->portid << 6) | (irq & IMAP_INO)); + upa_writel(ICLR_IDLE, iclr); +} + #define SCHIZO_STC_ERR 0xb800UL /* --> 0xba00 */ #define SCHIZO_STC_TAG 0xba00UL /* --> 0xba80 */ #define SCHIZO_STC_LINE 0xbb00UL /* --> 0xbb80 */ @@ -582,6 +720,8 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs) /* Interrogate IOMMU for error status. */ schizo_check_iommu_error(p, UE_ERR); + schizo_clear_other_err_intr(p, irq); + return IRQ_HANDLED; } @@ -671,6 +811,8 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs) printk("(none)"); printk("]\n"); + schizo_clear_other_err_intr(p, irq); + return IRQ_HANDLED; } @@ -891,6 +1033,8 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *reg if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR)) pci_scan_for_parity_error(p, pbm, pbm->pci_bus); + schizo_clear_other_err_intr(p, irq); + return IRQ_HANDLED; } @@ -946,6 +1090,7 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs * printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n", p->index, errlog); + schizo_clear_other_err_intr(p, irq); return IRQ_HANDLED; } @@ -953,6 +1098,7 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs * p->index); schizo_check_iommu_error(p, SAFARI_ERR); + schizo_clear_other_err_intr(p, irq); return IRQ_HANDLED; } @@ -984,47 +1130,74 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs * static void tomatillo_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm; - struct of_device *op; + unsigned int irq; u64 tmp, err_mask, err_no_mask; - /* Tomatillo IRQ property layout is: - * 0: PCIERR - * 1: UE ERR - * 2: CE ERR - * 3: SERR - * 4: POWER FAIL? - */ - + /* Build IRQs and register handlers. */ pbm = pbm_for_ino(p, SCHIZO_UE_INO); - op = of_find_device_by_node(pbm->prom_node); - if (op) - request_irq(op->irqs[1], schizo_ue_intr, SA_SHIRQ, - "TOMATILLO_UE", p); + irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_UE_INO); + if (request_irq(irq, schizo_ue_intr, + SA_SHIRQ, "TOMATILLO UE", p) < 0) { + prom_printf("%s: Cannot register UE interrupt.\n", + pbm->name); + prom_halt(); + } + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO)); + upa_writel(tmp, (pbm->pbm_regs + + schizo_imap_offset(SCHIZO_UE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_CE_INO); - op = of_find_device_by_node(pbm->prom_node); - if (op) - request_irq(op->irqs[2], schizo_ce_intr, SA_SHIRQ, - "TOMATILLO CE", p); + irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_CE_INO); + if (request_irq(irq, schizo_ce_intr, + SA_SHIRQ, "TOMATILLO CE", p) < 0) { + prom_printf("%s: Cannot register CE interrupt.\n", + pbm->name); + prom_halt(); + } + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO)); + upa_writel(tmp, (pbm->pbm_regs + + schizo_imap_offset(SCHIZO_CE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); - op = of_find_device_by_node(pbm->prom_node); - if (op) - request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, - "TOMATILLO PCIERR-A", pbm); - + irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) | + SCHIZO_PCIERR_A_INO)); + if (request_irq(irq, schizo_pcierr_intr, + SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) { + prom_printf("%s: Cannot register PBM A PciERR interrupt.\n", + pbm->name); + prom_halt(); + } + tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | + SCHIZO_PCIERR_A_INO))); + upa_writel(tmp, (pbm->pbm_regs + + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); - op = of_find_device_by_node(pbm->prom_node); - if (op) - request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, - "TOMATILLO PCIERR-B", pbm); + irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) | + SCHIZO_PCIERR_B_INO)); + if (request_irq(irq, schizo_pcierr_intr, + SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) { + prom_printf("%s: Cannot register PBM B PciERR interrupt.\n", + pbm->name); + prom_halt(); + } + tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | + SCHIZO_PCIERR_B_INO))); + upa_writel(tmp, (pbm->pbm_regs + + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); - op = of_find_device_by_node(pbm->prom_node); - if (op) - request_irq(op->irqs[3], schizo_safarierr_intr, SA_SHIRQ, - "TOMATILLO SERR", p); + irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO); + if (request_irq(irq, schizo_safarierr_intr, + SA_SHIRQ, "TOMATILLO SERR", p) < 0) { + prom_printf("%s: Cannot register SafariERR interrupt.\n", + pbm->name); + prom_halt(); + } + tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | + SCHIZO_SERR_INO))); + upa_writel(tmp, (pbm->pbm_regs + + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); /* Enable UE and CE interrupts for controller. */ schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL, @@ -1092,47 +1265,64 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) static void schizo_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm; - struct of_device *op; + unsigned int irq; u64 tmp, err_mask, err_no_mask; - /* Schizo IRQ property layout is: - * 0: PCIERR - * 1: UE ERR - * 2: CE ERR - * 3: SERR - * 4: POWER FAIL? - */ - + /* Build IRQs and register handlers. */ pbm = pbm_for_ino(p, SCHIZO_UE_INO); - op = of_find_device_by_node(pbm->prom_node); - if (op) - request_irq(op->irqs[1], schizo_ue_intr, SA_SHIRQ, - "SCHIZO_UE", p); + irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_UE_INO); + if (request_irq(irq, schizo_ue_intr, + SA_SHIRQ, "SCHIZO UE", p) < 0) { + prom_printf("%s: Cannot register UE interrupt.\n", + pbm->name); + prom_halt(); + } + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO)); + upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_CE_INO); - op = of_find_device_by_node(pbm->prom_node); - if (op) - request_irq(op->irqs[2], schizo_ce_intr, SA_SHIRQ, - "SCHIZO CE", p); + irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_CE_INO); + if (request_irq(irq, schizo_ce_intr, + SA_SHIRQ, "SCHIZO CE", p) < 0) { + prom_printf("%s: Cannot register CE interrupt.\n", + pbm->name); + prom_halt(); + } + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO)); + upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); - op = of_find_device_by_node(pbm->prom_node); - if (op) - request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, - "SCHIZO PCIERR-A", pbm); - + irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_PCIERR_A_INO); + if (request_irq(irq, schizo_pcierr_intr, + SA_SHIRQ, "SCHIZO PCIERR", pbm) < 0) { + prom_printf("%s: Cannot register PBM A PciERR interrupt.\n", + pbm->name); + prom_halt(); + } + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_A_INO)); + upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); - op = of_find_device_by_node(pbm->prom_node); - if (op) - request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, - "SCHIZO PCIERR-B", pbm); + irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_PCIERR_B_INO); + if (request_irq(irq, schizo_pcierr_intr, + SA_SHIRQ, "SCHIZO PCIERR", &p->pbm_B) < 0) { + prom_printf("%s: Cannot register PBM B PciERR interrupt.\n", + pbm->name); + prom_halt(); + } + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_B_INO)); + upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); - op = of_find_device_by_node(pbm->prom_node); - if (op) - request_irq(op->irqs[3], schizo_safarierr_intr, SA_SHIRQ, - "SCHIZO SERR", p); + irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO); + if (request_irq(irq, schizo_safarierr_intr, + SA_SHIRQ, "SCHIZO SERR", p) < 0) { + prom_printf("%s: Cannot register SafariERR interrupt.\n", + pbm->name); + prom_halt(); + } + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_SERR_INO)); + upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); /* Enable UE and CE interrupts for controller. */ schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL, @@ -1832,6 +2022,7 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ p->scan_bus = (chip_type == PBM_CHIP_TYPE_TOMATILLO ? tomatillo_scan_bus : schizo_scan_bus); + p->irq_build = schizo_irq_build; p->base_address_update = schizo_base_address_update; p->resource_adjust = schizo_resource_adjust; p->pci_ops = &schizo_ops; diff --git a/trunk/arch/sparc64/kernel/pci_sun4v.c b/trunk/arch/sparc64/kernel/pci_sun4v.c index 03ad4c06758e..b69e2270a721 100644 --- a/trunk/arch/sparc64/kernel/pci_sun4v.c +++ b/trunk/arch/sparc64/kernel/pci_sun4v.c @@ -843,6 +843,15 @@ static void pci_sun4v_scan_bus(struct pci_controller_info *p) /* XXX register error interrupt handlers XXX */ } +static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + unsigned int devino) +{ + u32 devhandle = pbm->devhandle; + + return sun4v_build_irq(devhandle, devino); +} + static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) { struct pcidev_cookie *pcp = pdev->sysdata; @@ -1191,6 +1200,7 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) p->pbms_same_domain = 0; p->scan_bus = pci_sun4v_scan_bus; + p->irq_build = pci_sun4v_irq_build; p->base_address_update = pci_sun4v_base_address_update; p->resource_adjust = pci_sun4v_resource_adjust; p->pci_ops = &pci_sun4v_ops; diff --git a/trunk/arch/sparc64/kernel/power.c b/trunk/arch/sparc64/kernel/power.c index 4febeda958a3..9496c7734014 100644 --- a/trunk/arch/sparc64/kernel/power.c +++ b/trunk/arch/sparc64/kernel/power.c @@ -17,10 +17,9 @@ #include #include +#include +#include #include -#include -#include -#include #include @@ -31,7 +30,6 @@ int scons_pwroff = 1; #ifdef CONFIG_PCI -#include static void __iomem *power_reg; static DECLARE_WAIT_QUEUE_HEAD(powerd_wait); @@ -117,33 +115,27 @@ static int __init has_button_interrupt(unsigned int irq, struct device_node *dp) return 1; } -static int __devinit power_probe(struct of_device *op, const struct of_device_id *match) +static void __devinit power_probe_common(struct of_device *dev, struct resource *res, unsigned int irq) { - struct resource *res = &op->resource[0]; - unsigned int irq= op->irqs[0]; + power_reg = ioremap(res->start, 0x4); - power_reg = of_ioremap(res, 0, 0x4, "power"); - - printk("%s: Control reg at %lx ... ", - op->node->name, res->start); + printk("power: Control reg at %p ... ", power_reg); poweroff_method = machine_halt; /* able to use the standard halt */ - if (has_button_interrupt(irq, op->node)) { + if (has_button_interrupt(irq, dev->node)) { if (kernel_thread(powerd, NULL, CLONE_FS) < 0) { printk("Failed to start power daemon.\n"); - return 0; + return; } printk("powerd running.\n"); if (request_irq(irq, - power_handler, 0, "power", NULL) < 0) + power_handler, SA_SHIRQ, "power", NULL) < 0) printk("power: Error, cannot register IRQ handler.\n"); } else { printk("not using powerd.\n"); } - - return 0; } static struct of_device_id power_match[] = { @@ -153,15 +145,44 @@ static struct of_device_id power_match[] = { {}, }; -static struct of_platform_driver power_driver = { +static int __devinit ebus_power_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct linux_ebus_device *edev = to_ebus_device(&dev->dev); + struct resource *res = &edev->resource[0]; + unsigned int irq = edev->irqs[0]; + + power_probe_common(dev, res,irq); + + return 0; +} + +static struct of_platform_driver ebus_power_driver = { + .name = "power", + .match_table = power_match, + .probe = ebus_power_probe, +}; + +static int __devinit isa_power_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct sparc_isa_device *idev = to_isa_device(&dev->dev); + struct resource *res = &idev->resource; + unsigned int irq = idev->irq; + + power_probe_common(dev, res,irq); + + return 0; +} + +static struct of_platform_driver isa_power_driver = { .name = "power", .match_table = power_match, - .probe = power_probe, + .probe = isa_power_probe, }; void __init power_init(void) { - of_register_driver(&power_driver, &of_bus_type); + of_register_driver(&ebus_power_driver, &ebus_bus_type); + of_register_driver(&isa_power_driver, &isa_bus_type); return; } #endif /* CONFIG_PCI */ diff --git a/trunk/arch/sparc64/kernel/prom.c b/trunk/arch/sparc64/kernel/prom.c index 8a70c52c0447..8e87e7ea0325 100644 --- a/trunk/arch/sparc64/kernel/prom.c +++ b/trunk/arch/sparc64/kernel/prom.c @@ -15,7 +15,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #include #include @@ -24,11 +23,7 @@ #include #include -#include #include -#include -#include -#include static struct device_node *allnodes; @@ -195,36 +190,6 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) } EXPORT_SYMBOL(of_getintprop_default); -int of_n_addr_cells(struct device_node *np) -{ - int* ip; - do { - if (np->parent) - np = np->parent; - ip = of_get_property(np, "#address-cells", NULL); - if (ip != NULL) - return *ip; - } while (np->parent); - /* No #address-cells property for the root node, default to 2 */ - return 2; -} -EXPORT_SYMBOL(of_n_addr_cells); - -int of_n_size_cells(struct device_node *np) -{ - int* ip; - do { - if (np->parent) - np = np->parent; - ip = of_get_property(np, "#size-cells", NULL); - if (ip != NULL) - return *ip; - } while (np->parent); - /* No #size-cells property for the root node, default to 1 */ - return 1; -} -EXPORT_SYMBOL(of_n_size_cells); - int of_set_property(struct device_node *dp, const char *name, void *val, int len) { struct property **prevp; @@ -288,754 +253,6 @@ static void * __init prom_early_alloc(unsigned long size) return ret; } -#ifdef CONFIG_PCI -/* PSYCHO interrupt mapping support. */ -#define PSYCHO_IMAP_A_SLOT0 0x0c00UL -#define PSYCHO_IMAP_B_SLOT0 0x0c20UL -static unsigned long psycho_pcislot_imap_offset(unsigned long ino) -{ - unsigned int bus = (ino & 0x10) >> 4; - unsigned int slot = (ino & 0x0c) >> 2; - - if (bus == 0) - return PSYCHO_IMAP_A_SLOT0 + (slot * 8); - else - return PSYCHO_IMAP_B_SLOT0 + (slot * 8); -} - -#define PSYCHO_IMAP_SCSI 0x1000UL -#define PSYCHO_IMAP_ETH 0x1008UL -#define PSYCHO_IMAP_BPP 0x1010UL -#define PSYCHO_IMAP_AU_REC 0x1018UL -#define PSYCHO_IMAP_AU_PLAY 0x1020UL -#define PSYCHO_IMAP_PFAIL 0x1028UL -#define PSYCHO_IMAP_KMS 0x1030UL -#define PSYCHO_IMAP_FLPY 0x1038UL -#define PSYCHO_IMAP_SHW 0x1040UL -#define PSYCHO_IMAP_KBD 0x1048UL -#define PSYCHO_IMAP_MS 0x1050UL -#define PSYCHO_IMAP_SER 0x1058UL -#define PSYCHO_IMAP_TIM0 0x1060UL -#define PSYCHO_IMAP_TIM1 0x1068UL -#define PSYCHO_IMAP_UE 0x1070UL -#define PSYCHO_IMAP_CE 0x1078UL -#define PSYCHO_IMAP_A_ERR 0x1080UL -#define PSYCHO_IMAP_B_ERR 0x1088UL -#define PSYCHO_IMAP_PMGMT 0x1090UL -#define PSYCHO_IMAP_GFX 0x1098UL -#define PSYCHO_IMAP_EUPA 0x10a0UL - -static unsigned long __psycho_onboard_imap_off[] = { -/*0x20*/ PSYCHO_IMAP_SCSI, -/*0x21*/ PSYCHO_IMAP_ETH, -/*0x22*/ PSYCHO_IMAP_BPP, -/*0x23*/ PSYCHO_IMAP_AU_REC, -/*0x24*/ PSYCHO_IMAP_AU_PLAY, -/*0x25*/ PSYCHO_IMAP_PFAIL, -/*0x26*/ PSYCHO_IMAP_KMS, -/*0x27*/ PSYCHO_IMAP_FLPY, -/*0x28*/ PSYCHO_IMAP_SHW, -/*0x29*/ PSYCHO_IMAP_KBD, -/*0x2a*/ PSYCHO_IMAP_MS, -/*0x2b*/ PSYCHO_IMAP_SER, -/*0x2c*/ PSYCHO_IMAP_TIM0, -/*0x2d*/ PSYCHO_IMAP_TIM1, -/*0x2e*/ PSYCHO_IMAP_UE, -/*0x2f*/ PSYCHO_IMAP_CE, -/*0x30*/ PSYCHO_IMAP_A_ERR, -/*0x31*/ PSYCHO_IMAP_B_ERR, -/*0x32*/ PSYCHO_IMAP_PMGMT -}; -#define PSYCHO_ONBOARD_IRQ_BASE 0x20 -#define PSYCHO_ONBOARD_IRQ_LAST 0x32 -#define psycho_onboard_imap_offset(__ino) \ - __psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] - -#define PSYCHO_ICLR_A_SLOT0 0x1400UL -#define PSYCHO_ICLR_SCSI 0x1800UL - -#define psycho_iclr_offset(ino) \ - ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ - (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) - -static unsigned int psycho_irq_build(struct device_node *dp, - unsigned int ino, - void *_data) -{ - unsigned long controller_regs = (unsigned long) _data; - unsigned long imap, iclr; - unsigned long imap_off, iclr_off; - int inofixup = 0; - - ino &= 0x3f; - if (ino < PSYCHO_ONBOARD_IRQ_BASE) { - /* PCI slot */ - imap_off = psycho_pcislot_imap_offset(ino); - } else { - /* Onboard device */ - if (ino > PSYCHO_ONBOARD_IRQ_LAST) { - prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); - prom_halt(); - } - imap_off = psycho_onboard_imap_offset(ino); - } - - /* Now build the IRQ bucket. */ - imap = controller_regs + imap_off; - imap += 4; - - iclr_off = psycho_iclr_offset(ino); - iclr = controller_regs + iclr_off; - iclr += 4; - - if ((ino & 0x20) == 0) - inofixup = ino & 0x03; - - return build_irq(inofixup, iclr, imap); -} - -static void psycho_irq_trans_init(struct device_node *dp) -{ - struct linux_prom64_registers *regs; - - dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); - dp->irq_trans->irq_build = psycho_irq_build; - - regs = of_get_property(dp, "reg", NULL); - dp->irq_trans->data = (void *) regs[2].phys_addr; -} - -#define sabre_read(__reg) \ -({ u64 __ret; \ - __asm__ __volatile__("ldxa [%1] %2, %0" \ - : "=r" (__ret) \ - : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ - : "memory"); \ - __ret; \ -}) - -struct sabre_irq_data { - unsigned long controller_regs; - unsigned int pci_first_busno; -}; -#define SABRE_CONFIGSPACE 0x001000000UL -#define SABRE_WRSYNC 0x1c20UL - -#define SABRE_CONFIG_BASE(CONFIG_SPACE) \ - (CONFIG_SPACE | (1UL << 24)) -#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \ - (((unsigned long)(BUS) << 16) | \ - ((unsigned long)(DEVFN) << 8) | \ - ((unsigned long)(REG))) - -/* When a device lives behind a bridge deeper in the PCI bus topology - * than APB, a special sequence must run to make sure all pending DMA - * transfers at the time of IRQ delivery are visible in the coherency - * domain by the cpu. This sequence is to perform a read on the far - * side of the non-APB bridge, then perform a read of Sabre's DMA - * write-sync register. - */ -static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) -{ - unsigned int phys_hi = (unsigned int) (unsigned long) _arg1; - struct sabre_irq_data *irq_data = _arg2; - unsigned long controller_regs = irq_data->controller_regs; - unsigned long sync_reg = controller_regs + SABRE_WRSYNC; - unsigned long config_space = controller_regs + SABRE_CONFIGSPACE; - unsigned int bus, devfn; - u16 _unused; - - config_space = SABRE_CONFIG_BASE(config_space); - - bus = (phys_hi >> 16) & 0xff; - devfn = (phys_hi >> 8) & 0xff; - - config_space |= SABRE_CONFIG_ENCODE(bus, devfn, 0x00); - - __asm__ __volatile__("membar #Sync\n\t" - "lduha [%1] %2, %0\n\t" - "membar #Sync" - : "=r" (_unused) - : "r" ((u16 *) config_space), - "i" (ASI_PHYS_BYPASS_EC_E_L) - : "memory"); - - sabre_read(sync_reg); -} - -#define SABRE_IMAP_A_SLOT0 0x0c00UL -#define SABRE_IMAP_B_SLOT0 0x0c20UL -#define SABRE_IMAP_SCSI 0x1000UL -#define SABRE_IMAP_ETH 0x1008UL -#define SABRE_IMAP_BPP 0x1010UL -#define SABRE_IMAP_AU_REC 0x1018UL -#define SABRE_IMAP_AU_PLAY 0x1020UL -#define SABRE_IMAP_PFAIL 0x1028UL -#define SABRE_IMAP_KMS 0x1030UL -#define SABRE_IMAP_FLPY 0x1038UL -#define SABRE_IMAP_SHW 0x1040UL -#define SABRE_IMAP_KBD 0x1048UL -#define SABRE_IMAP_MS 0x1050UL -#define SABRE_IMAP_SER 0x1058UL -#define SABRE_IMAP_UE 0x1070UL -#define SABRE_IMAP_CE 0x1078UL -#define SABRE_IMAP_PCIERR 0x1080UL -#define SABRE_IMAP_GFX 0x1098UL -#define SABRE_IMAP_EUPA 0x10a0UL -#define SABRE_ICLR_A_SLOT0 0x1400UL -#define SABRE_ICLR_B_SLOT0 0x1480UL -#define SABRE_ICLR_SCSI 0x1800UL -#define SABRE_ICLR_ETH 0x1808UL -#define SABRE_ICLR_BPP 0x1810UL -#define SABRE_ICLR_AU_REC 0x1818UL -#define SABRE_ICLR_AU_PLAY 0x1820UL -#define SABRE_ICLR_PFAIL 0x1828UL -#define SABRE_ICLR_KMS 0x1830UL -#define SABRE_ICLR_FLPY 0x1838UL -#define SABRE_ICLR_SHW 0x1840UL -#define SABRE_ICLR_KBD 0x1848UL -#define SABRE_ICLR_MS 0x1850UL -#define SABRE_ICLR_SER 0x1858UL -#define SABRE_ICLR_UE 0x1870UL -#define SABRE_ICLR_CE 0x1878UL -#define SABRE_ICLR_PCIERR 0x1880UL - -static unsigned long sabre_pcislot_imap_offset(unsigned long ino) -{ - unsigned int bus = (ino & 0x10) >> 4; - unsigned int slot = (ino & 0x0c) >> 2; - - if (bus == 0) - return SABRE_IMAP_A_SLOT0 + (slot * 8); - else - return SABRE_IMAP_B_SLOT0 + (slot * 8); -} - -static unsigned long __sabre_onboard_imap_off[] = { -/*0x20*/ SABRE_IMAP_SCSI, -/*0x21*/ SABRE_IMAP_ETH, -/*0x22*/ SABRE_IMAP_BPP, -/*0x23*/ SABRE_IMAP_AU_REC, -/*0x24*/ SABRE_IMAP_AU_PLAY, -/*0x25*/ SABRE_IMAP_PFAIL, -/*0x26*/ SABRE_IMAP_KMS, -/*0x27*/ SABRE_IMAP_FLPY, -/*0x28*/ SABRE_IMAP_SHW, -/*0x29*/ SABRE_IMAP_KBD, -/*0x2a*/ SABRE_IMAP_MS, -/*0x2b*/ SABRE_IMAP_SER, -/*0x2c*/ 0 /* reserved */, -/*0x2d*/ 0 /* reserved */, -/*0x2e*/ SABRE_IMAP_UE, -/*0x2f*/ SABRE_IMAP_CE, -/*0x30*/ SABRE_IMAP_PCIERR, -}; -#define SABRE_ONBOARD_IRQ_BASE 0x20 -#define SABRE_ONBOARD_IRQ_LAST 0x30 -#define sabre_onboard_imap_offset(__ino) \ - __sabre_onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE] - -#define sabre_iclr_offset(ino) \ - ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ - (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) - -static unsigned int sabre_irq_build(struct device_node *dp, - unsigned int ino, - void *_data) -{ - struct sabre_irq_data *irq_data = _data; - unsigned long controller_regs = irq_data->controller_regs; - struct linux_prom_pci_registers *regs; - unsigned long imap, iclr; - unsigned long imap_off, iclr_off; - int inofixup = 0; - int virt_irq; - - ino &= 0x3f; - if (ino < SABRE_ONBOARD_IRQ_BASE) { - /* PCI slot */ - imap_off = sabre_pcislot_imap_offset(ino); - } else { - /* onboard device */ - if (ino > SABRE_ONBOARD_IRQ_LAST) { - prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino); - prom_halt(); - } - imap_off = sabre_onboard_imap_offset(ino); - } - - /* Now build the IRQ bucket. */ - imap = controller_regs + imap_off; - imap += 4; - - iclr_off = sabre_iclr_offset(ino); - iclr = controller_regs + iclr_off; - iclr += 4; - - if ((ino & 0x20) == 0) - inofixup = ino & 0x03; - - virt_irq = build_irq(inofixup, iclr, imap); - - regs = of_get_property(dp, "reg", NULL); - if (regs && - ((regs->phys_hi >> 16) & 0xff) != irq_data->pci_first_busno) { - irq_install_pre_handler(virt_irq, - sabre_wsync_handler, - (void *) (long) regs->phys_hi, - (void *) - controller_regs + - SABRE_WRSYNC); - } - - return virt_irq; -} - -static void sabre_irq_trans_init(struct device_node *dp) -{ - struct linux_prom64_registers *regs; - struct sabre_irq_data *irq_data; - u32 *busrange; - - dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); - dp->irq_trans->irq_build = sabre_irq_build; - - irq_data = prom_early_alloc(sizeof(struct sabre_irq_data)); - - regs = of_get_property(dp, "reg", NULL); - irq_data->controller_regs = regs[0].phys_addr; - - busrange = of_get_property(dp, "bus-range", NULL); - irq_data->pci_first_busno = busrange[0]; - - dp->irq_trans->data = irq_data; -} - -/* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the - * imap/iclr registers are per-PBM. - */ -#define SCHIZO_IMAP_BASE 0x1000UL -#define SCHIZO_ICLR_BASE 0x1400UL - -static unsigned long schizo_imap_offset(unsigned long ino) -{ - return SCHIZO_IMAP_BASE + (ino * 8UL); -} - -static unsigned long schizo_iclr_offset(unsigned long ino) -{ - return SCHIZO_ICLR_BASE + (ino * 8UL); -} - -static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs, - unsigned int ino) -{ - return pbm_regs + schizo_iclr_offset(ino) + 4; -} - -static unsigned long schizo_ino_to_imap(unsigned long pbm_regs, - unsigned int ino) -{ - return pbm_regs + schizo_imap_offset(ino) + 4; -} - -#define schizo_read(__reg) \ -({ u64 __ret; \ - __asm__ __volatile__("ldxa [%1] %2, %0" \ - : "=r" (__ret) \ - : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ - : "memory"); \ - __ret; \ -}) -#define schizo_write(__reg, __val) \ - __asm__ __volatile__("stxa %0, [%1] %2" \ - : /* no outputs */ \ - : "r" (__val), "r" (__reg), \ - "i" (ASI_PHYS_BYPASS_EC_E) \ - : "memory") - -static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) -{ - unsigned long sync_reg = (unsigned long) _arg2; - u64 mask = 1UL << (ino & IMAP_INO); - u64 val; - int limit; - - schizo_write(sync_reg, mask); - - limit = 100000; - val = 0; - while (--limit) { - val = schizo_read(sync_reg); - if (!(val & mask)) - break; - } - if (limit <= 0) { - printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n", - val, mask); - } - - if (_arg1) { - static unsigned char cacheline[64] - __attribute__ ((aligned (64))); - - __asm__ __volatile__("rd %%fprs, %0\n\t" - "or %0, %4, %1\n\t" - "wr %1, 0x0, %%fprs\n\t" - "stda %%f0, [%5] %6\n\t" - "wr %0, 0x0, %%fprs\n\t" - "membar #Sync" - : "=&r" (mask), "=&r" (val) - : "0" (mask), "1" (val), - "i" (FPRS_FEF), "r" (&cacheline[0]), - "i" (ASI_BLK_COMMIT_P)); - } -} - -struct schizo_irq_data { - unsigned long pbm_regs; - unsigned long sync_reg; - u32 portid; - int chip_version; -}; - -static unsigned int schizo_irq_build(struct device_node *dp, - unsigned int ino, - void *_data) -{ - struct schizo_irq_data *irq_data = _data; - unsigned long pbm_regs = irq_data->pbm_regs; - unsigned long imap, iclr; - int ign_fixup; - int virt_irq; - int is_tomatillo; - - ino &= 0x3f; - - /* Now build the IRQ bucket. */ - imap = schizo_ino_to_imap(pbm_regs, ino); - iclr = schizo_ino_to_iclr(pbm_regs, ino); - - /* On Schizo, no inofixup occurs. This is because each - * INO has it's own IMAP register. On Psycho and Sabre - * there is only one IMAP register for each PCI slot even - * though four different INOs can be generated by each - * PCI slot. - * - * But, for JBUS variants (essentially, Tomatillo), we have - * to fixup the lowest bit of the interrupt group number. - */ - ign_fixup = 0; - - is_tomatillo = (irq_data->sync_reg != 0UL); - - if (is_tomatillo) { - if (irq_data->portid & 1) - ign_fixup = (1 << 6); - } - - virt_irq = build_irq(ign_fixup, iclr, imap); - - if (is_tomatillo) { - irq_install_pre_handler(virt_irq, - tomatillo_wsync_handler, - ((irq_data->chip_version <= 4) ? - (void *) 1 : (void *) 0), - (void *) irq_data->sync_reg); - } - - return virt_irq; -} - -static void schizo_irq_trans_init(struct device_node *dp) -{ - struct linux_prom64_registers *regs; - struct schizo_irq_data *irq_data; - - dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); - dp->irq_trans->irq_build = schizo_irq_build; - - irq_data = prom_early_alloc(sizeof(struct schizo_irq_data)); - - regs = of_get_property(dp, "reg", NULL); - dp->irq_trans->data = irq_data; - - irq_data->pbm_regs = regs[0].phys_addr; - irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL; - irq_data->portid = of_getintprop_default(dp, "portid", 0); - irq_data->chip_version = of_getintprop_default(dp, "version#", 0); -} - -static unsigned int pci_sun4v_irq_build(struct device_node *dp, - unsigned int devino, - void *_data) -{ - u32 devhandle = (u32) (unsigned long) _data; - - return sun4v_build_irq(devhandle, devino); -} - -static void pci_sun4v_irq_trans_init(struct device_node *dp) -{ - struct linux_prom64_registers *regs; - - dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); - dp->irq_trans->irq_build = pci_sun4v_irq_build; - - regs = of_get_property(dp, "reg", NULL); - dp->irq_trans->data = (void *) (unsigned long) - ((regs->phys_addr >> 32UL) & 0x0fffffff); -} -#endif /* CONFIG_PCI */ - -#ifdef CONFIG_SBUS -/* INO number to IMAP register offset for SYSIO external IRQ's. - * This should conform to both Sunfire/Wildfire server and Fusion - * desktop designs. - */ -#define SYSIO_IMAP_SLOT0 0x2c04UL -#define SYSIO_IMAP_SLOT1 0x2c0cUL -#define SYSIO_IMAP_SLOT2 0x2c14UL -#define SYSIO_IMAP_SLOT3 0x2c1cUL -#define SYSIO_IMAP_SCSI 0x3004UL -#define SYSIO_IMAP_ETH 0x300cUL -#define SYSIO_IMAP_BPP 0x3014UL -#define SYSIO_IMAP_AUDIO 0x301cUL -#define SYSIO_IMAP_PFAIL 0x3024UL -#define SYSIO_IMAP_KMS 0x302cUL -#define SYSIO_IMAP_FLPY 0x3034UL -#define SYSIO_IMAP_SHW 0x303cUL -#define SYSIO_IMAP_KBD 0x3044UL -#define SYSIO_IMAP_MS 0x304cUL -#define SYSIO_IMAP_SER 0x3054UL -#define SYSIO_IMAP_TIM0 0x3064UL -#define SYSIO_IMAP_TIM1 0x306cUL -#define SYSIO_IMAP_UE 0x3074UL -#define SYSIO_IMAP_CE 0x307cUL -#define SYSIO_IMAP_SBERR 0x3084UL -#define SYSIO_IMAP_PMGMT 0x308cUL -#define SYSIO_IMAP_GFX 0x3094UL -#define SYSIO_IMAP_EUPA 0x309cUL - -#define bogon ((unsigned long) -1) -static unsigned long sysio_irq_offsets[] = { - /* SBUS Slot 0 --> 3, level 1 --> 7 */ - SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, - SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, - SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, - SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, - SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, - SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, - SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, - SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, - - /* Onboard devices (not relevant/used on SunFire). */ - SYSIO_IMAP_SCSI, - SYSIO_IMAP_ETH, - SYSIO_IMAP_BPP, - bogon, - SYSIO_IMAP_AUDIO, - SYSIO_IMAP_PFAIL, - bogon, - bogon, - SYSIO_IMAP_KMS, - SYSIO_IMAP_FLPY, - SYSIO_IMAP_SHW, - SYSIO_IMAP_KBD, - SYSIO_IMAP_MS, - SYSIO_IMAP_SER, - bogon, - bogon, - SYSIO_IMAP_TIM0, - SYSIO_IMAP_TIM1, - bogon, - bogon, - SYSIO_IMAP_UE, - SYSIO_IMAP_CE, - SYSIO_IMAP_SBERR, - SYSIO_IMAP_PMGMT, -}; - -#undef bogon - -#define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets) - -/* Convert Interrupt Mapping register pointer to associated - * Interrupt Clear register pointer, SYSIO specific version. - */ -#define SYSIO_ICLR_UNUSED0 0x3400UL -#define SYSIO_ICLR_SLOT0 0x340cUL -#define SYSIO_ICLR_SLOT1 0x344cUL -#define SYSIO_ICLR_SLOT2 0x348cUL -#define SYSIO_ICLR_SLOT3 0x34ccUL -static unsigned long sysio_imap_to_iclr(unsigned long imap) -{ - unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; - return imap + diff; -} - -static unsigned int sbus_of_build_irq(struct device_node *dp, - unsigned int ino, - void *_data) -{ - unsigned long reg_base = (unsigned long) _data; - struct linux_prom_registers *regs; - unsigned long imap, iclr; - int sbus_slot = 0; - int sbus_level = 0; - - ino &= 0x3f; - - regs = of_get_property(dp, "reg", NULL); - if (regs) - sbus_slot = regs->which_io; - - if (ino < 0x20) - ino += (sbus_slot * 8); - - imap = sysio_irq_offsets[ino]; - if (imap == ((unsigned long)-1)) { - prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n", - ino); - prom_halt(); - } - imap += reg_base; - - /* SYSIO inconsistency. For external SLOTS, we have to select - * the right ICLR register based upon the lower SBUS irq level - * bits. - */ - if (ino >= 0x20) { - iclr = sysio_imap_to_iclr(imap); - } else { - sbus_level = ino & 0x7; - - switch(sbus_slot) { - case 0: - iclr = reg_base + SYSIO_ICLR_SLOT0; - break; - case 1: - iclr = reg_base + SYSIO_ICLR_SLOT1; - break; - case 2: - iclr = reg_base + SYSIO_ICLR_SLOT2; - break; - default: - case 3: - iclr = reg_base + SYSIO_ICLR_SLOT3; - break; - }; - - iclr += ((unsigned long)sbus_level - 1UL) * 8UL; - } - return build_irq(sbus_level, iclr, imap); -} - -static void sbus_irq_trans_init(struct device_node *dp) -{ - struct linux_prom64_registers *regs; - - dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); - dp->irq_trans->irq_build = sbus_of_build_irq; - - regs = of_get_property(dp, "reg", NULL); - dp->irq_trans->data = (void *) (unsigned long) regs->phys_addr; -} -#endif /* CONFIG_SBUS */ - - -static unsigned int central_build_irq(struct device_node *dp, - unsigned int ino, - void *_data) -{ - struct device_node *central_dp = _data; - struct of_device *central_op = of_find_device_by_node(central_dp); - struct resource *res; - unsigned long imap, iclr; - u32 tmp; - - if (!strcmp(dp->name, "eeprom")) { - res = ¢ral_op->resource[5]; - } else if (!strcmp(dp->name, "zs")) { - res = ¢ral_op->resource[4]; - } else if (!strcmp(dp->name, "clock-board")) { - res = ¢ral_op->resource[3]; - } else { - return ino; - } - - imap = res->start + 0x00UL; - iclr = res->start + 0x10UL; - - /* Set the INO state to idle, and disable. */ - upa_writel(0, iclr); - upa_readl(iclr); - - tmp = upa_readl(imap); - tmp &= ~0x80000000; - upa_writel(tmp, imap); - - return build_irq(0, iclr, imap); -} - -static void central_irq_trans_init(struct device_node *dp) -{ - dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); - dp->irq_trans->irq_build = central_build_irq; - - dp->irq_trans->data = dp; -} - -struct irq_trans { - const char *name; - void (*init)(struct device_node *); -}; - -#ifdef CONFIG_PCI -static struct irq_trans pci_irq_trans_table[] = { - { "SUNW,sabre", sabre_irq_trans_init }, - { "pci108e,a000", sabre_irq_trans_init }, - { "pci108e,a001", sabre_irq_trans_init }, - { "SUNW,psycho", psycho_irq_trans_init }, - { "pci108e,8000", psycho_irq_trans_init }, - { "SUNW,schizo", schizo_irq_trans_init }, - { "pci108e,8001", schizo_irq_trans_init }, - { "SUNW,schizo+", schizo_irq_trans_init }, - { "pci108e,8002", schizo_irq_trans_init }, - { "SUNW,tomatillo", schizo_irq_trans_init }, - { "pci108e,a801", schizo_irq_trans_init }, - { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init }, -}; -#endif - -static void irq_trans_init(struct device_node *dp) -{ - const char *model; - int i; - - model = of_get_property(dp, "model", NULL); - if (!model) - model = of_get_property(dp, "compatible", NULL); - if (!model) - return; - -#ifdef CONFIG_PCI - for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) { - struct irq_trans *t = &pci_irq_trans_table[i]; - - if (!strcmp(model, t->name)) - return t->init(dp); - } -#endif -#ifdef CONFIG_SBUS - if (!strcmp(dp->name, "sbus") || - !strcmp(dp->name, "sbi")) - return sbus_irq_trans_init(dp); -#endif - if (!strcmp(dp->name, "central")) - return central_irq_trans_init(dp->child); -} - static int is_root_node(const struct device_node *dp) { if (!dp) @@ -1459,9 +676,9 @@ static struct device_node * __init create_node(phandle node) dp->type = get_one_property(node, "device_type"); dp->node = node; - dp->properties = build_prop_list(node); + /* Build interrupts later... */ - irq_trans_init(dp); + dp->properties = build_prop_list(node); return dp; } diff --git a/trunk/arch/sparc64/kernel/sbus.c b/trunk/arch/sparc64/kernel/sbus.c index ef68aa4fec65..ac05e0f692ef 100644 --- a/trunk/arch/sparc64/kernel/sbus.c +++ b/trunk/arch/sparc64/kernel/sbus.c @@ -1221,7 +1221,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) /* Now some Xfire specific grot... */ if (this_is_starfire) - starfire_hookup(sbus->portid); + sbus->starfire_cookie = starfire_hookup(sbus->portid); + else + sbus->starfire_cookie = NULL; sysio_register_error_handlers(sbus); } @@ -1267,6 +1269,8 @@ int __init sbus_arch_preinit(void) void __init sbus_arch_postinit(void) { extern void firetruck_init(void); + extern void clock_probe(void); firetruck_init(); + clock_probe(); } diff --git a/trunk/arch/sparc64/kernel/starfire.c b/trunk/arch/sparc64/kernel/starfire.c index b930fee7708a..ae859d40771e 100644 --- a/trunk/arch/sparc64/kernel/starfire.c +++ b/trunk/arch/sparc64/kernel/starfire.c @@ -54,7 +54,7 @@ struct starfire_irqinfo { static struct starfire_irqinfo *sflist = NULL; /* Beam me up Scott(McNeil)y... */ -void starfire_hookup(int upaid) +void *starfire_hookup(int upaid) { struct starfire_irqinfo *p; unsigned long treg_base, hwmid, i; @@ -81,6 +81,8 @@ void starfire_hookup(int upaid) p->upaid = upaid; p->next = sflist; sflist = p; + + return (void *) p; } unsigned int starfire_translate(unsigned long imap, diff --git a/trunk/arch/sparc64/kernel/time.c b/trunk/arch/sparc64/kernel/time.c index 5f3dd4d800cd..348b82035561 100644 --- a/trunk/arch/sparc64/kernel/time.c +++ b/trunk/arch/sparc64/kernel/time.c @@ -38,8 +38,11 @@ #include #include #include -#include -#include +#include +#include +#include +#include +#include #include #include #include @@ -767,105 +770,236 @@ static int __init clock_model_matches(char *model) return 1; } -static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) +static void __init __clock_assign_common(void __iomem *addr, char *model) { - struct device_node *dp = op->node; - char *model = of_get_property(dp, "model", NULL); - unsigned long size, flags; - void __iomem *regs; + if (model[5] == '0' && model[6] == '2') { + mstk48t02_regs = addr; + } else if(model[5] == '0' && model[6] == '8') { + mstk48t08_regs = addr; + mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; + } else { + mstk48t59_regs = addr; + mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; + } +} - if (!model || !clock_model_matches(model)) - return -ENODEV; +static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg, + char *model) +{ + unsigned long addr; - /* On an Enterprise system there can be multiple mostek clocks. - * We should only match the one that is on the central FHC bus. - */ - if (!strcmp(dp->parent->name, "fhc") && - strcmp(dp->parent->parent->name, "central") != 0) - return -ENODEV; + addr = ((unsigned long) clk_reg[0].phys_addr | + (((unsigned long) clk_reg[0].which_io) << 32UL)); + + __clock_assign_common((void __iomem *) addr, model); +} + +static int __init clock_probe_central(void) +{ + struct linux_prom_registers clk_reg[2], *pr; + struct device_node *dp; + char *model; + + if (!central_bus) + return 0; + + /* Get Central FHC's prom node. */ + dp = central_bus->child->prom_node; + + /* Then get the first child device below it. */ + dp = dp->child; + + while (dp) { + model = of_get_property(dp, "model", NULL); + if (!model || !clock_model_matches(model)) + goto next_sibling; + + pr = of_get_property(dp, "reg", NULL); + memcpy(clk_reg, pr, sizeof(clk_reg)); + + apply_fhc_ranges(central_bus->child, clk_reg, 1); + apply_central_ranges(central_bus, clk_reg, 1); - size = (op->resource[0].end - op->resource[0].start) + 1; - regs = of_ioremap(&op->resource[0], 0, size, "clock"); - if (!regs) - return -ENOMEM; + clock_assign_clk_reg(clk_reg, model); + return 1; + next_sibling: + dp = dp->sibling; + } + + return 0; +} + +#ifdef CONFIG_PCI +static void __init clock_isa_ebus_assign_regs(struct resource *res, char *model) +{ if (!strcmp(model, "ds1287") || !strcmp(model, "m5819") || !strcmp(model, "m5819p") || !strcmp(model, "m5823")) { - ds1287_regs = (unsigned long) regs; - } else if (model[5] == '0' && model[6] == '2') { - mstk48t02_regs = regs; - } else if(model[5] == '0' && model[6] == '8') { - mstk48t08_regs = regs; - mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; + ds1287_regs = res->start; } else { - mstk48t59_regs = regs; + mstk48t59_regs = (void __iomem *) res->start; mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; } +} - printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs); +static int __init clock_probe_one_ebus_dev(struct linux_ebus_device *edev) +{ + struct device_node *dp = edev->prom_node; + char *model; - local_irq_save(flags); + model = of_get_property(dp, "model", NULL); + if (!clock_model_matches(model)) + return 0; - if (mstk48t02_regs != NULL) { - /* Report a low battery voltage condition. */ - if (has_low_battery()) - prom_printf("NVRAM: Low battery voltage!\n"); + clock_isa_ebus_assign_regs(&edev->resource[0], model); - /* Kick start the clock if it is completely stopped. */ - if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) - kick_start_clock(); + return 1; +} + +static int __init clock_probe_ebus(void) +{ + struct linux_ebus *ebus; + + for_each_ebus(ebus) { + struct linux_ebus_device *edev; + + for_each_ebusdev(edev, ebus) { + if (clock_probe_one_ebus_dev(edev)) + return 1; + } } - set_system_time(); - - local_irq_restore(flags); + return 0; +} + +static int __init clock_probe_one_isa_dev(struct sparc_isa_device *idev) +{ + struct device_node *dp = idev->prom_node; + char *model; + + model = of_get_property(dp, "model", NULL); + if (!clock_model_matches(model)) + return 0; + + clock_isa_ebus_assign_regs(&idev->resource, model); + + return 1; +} + +static int __init clock_probe_isa(void) +{ + struct sparc_isa_bridge *isa_br; + + for_each_isa(isa_br) { + struct sparc_isa_device *isa_dev; + + for_each_isadev(isa_dev, isa_br) { + if (clock_probe_one_isa_dev(isa_dev)) + return 1; + } + } return 0; } +#endif /* CONFIG_PCI */ -static struct of_device_id clock_match[] = { - { - .name = "eeprom", - }, - { - .name = "rtc", - }, - {}, -}; +#ifdef CONFIG_SBUS +static int __init clock_probe_one_sbus_dev(struct sbus_bus *sbus, struct sbus_dev *sdev) +{ + struct resource *res; + char model[64]; + void __iomem *addr; -static struct of_platform_driver clock_driver = { - .name = "clock", - .match_table = clock_match, - .probe = clock_probe, -}; + prom_getstring(sdev->prom_node, "model", model, sizeof(model)); + if (!clock_model_matches(model)) + return 0; + + res = &sdev->resource[0]; + addr = sbus_ioremap(res, 0, 0x800UL, "eeprom"); + + __clock_assign_common(addr, model); + + return 1; +} + +static int __init clock_probe_sbus(void) +{ + struct sbus_bus *sbus; + + for_each_sbus(sbus) { + struct sbus_dev *sdev; + + for_each_sbusdev(sdev, sbus) { + if (clock_probe_one_sbus_dev(sbus, sdev)) + return 1; + } + } + + return 0; +} +#endif -static int __init clock_init(void) +void __init clock_probe(void) { + static int invoked; + unsigned long flags; + + if (invoked) + return; + invoked = 1; + if (this_is_starfire) { xtime.tv_sec = starfire_get_time(); xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); - return 0; + return; } if (tlb_type == hypervisor) { xtime.tv_sec = hypervisor_get_time(); xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); - return 0; + return; } - return of_register_driver(&clock_driver, &of_bus_type); -} + /* Check FHC Central then EBUSs then ISA bridges then SBUSs. + * That way we handle the presence of multiple properly. + * + * As a special case, machines with Central must provide the + * timer chip there. + */ + if (!clock_probe_central() && +#ifdef CONFIG_PCI + !clock_probe_ebus() && + !clock_probe_isa() && +#endif +#ifdef CONFIG_SBUS + !clock_probe_sbus() +#endif + ) { + printk(KERN_WARNING "No clock chip found.\n"); + return; + } -/* Must be after subsys_initcall() so that busses are probed. Must - * be before device_initcall() because things like the RTC driver - * need to see the clock registers. - */ -fs_initcall(clock_init); + local_irq_save(flags); + + if (mstk48t02_regs != NULL) { + /* Report a low battery voltage condition. */ + if (has_low_battery()) + prom_printf("NVRAM: Low battery voltage!\n"); + + /* Kick start the clock if it is completely stopped. */ + if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) + kick_start_clock(); + } + + set_system_time(); + + local_irq_restore(flags); +} /* This is gets the master TICK_INT timer going. */ static unsigned long sparc64_init_timers(void) diff --git a/trunk/arch/sparc64/kernel/unaligned.c b/trunk/arch/sparc64/kernel/unaligned.c index a9b765271b85..bb2d68577855 100644 --- a/trunk/arch/sparc64/kernel/unaligned.c +++ b/trunk/arch/sparc64/kernel/unaligned.c @@ -20,7 +20,6 @@ #include #include #include -#include #include /* #define DEBUG_MNA */ @@ -292,8 +291,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) if (count < 5) { last_time = jiffies; count++; - printk("Kernel unaligned access at TPC[%lx] ", regs->tpc); - print_symbol("%s\n", regs->tpc); + printk("Kernel unaligned access at TPC[%lx]\n", regs->tpc); } if (!ok_for_kernel(insn) || dir == both) { diff --git a/trunk/drivers/input/serio/i8042-sparcio.h b/trunk/drivers/input/serio/i8042-sparcio.h index 9cad197a4e68..6d66351805a2 100644 --- a/trunk/drivers/input/serio/i8042-sparcio.h +++ b/trunk/drivers/input/serio/i8042-sparcio.h @@ -3,9 +3,11 @@ #include #include + +#ifdef CONFIG_PCI #include -#include -#include +#include +#endif static int i8042_kbd_irq = -1; static int i8042_aux_irq = -1; @@ -46,83 +48,54 @@ static inline void i8042_write_command(int val) #define OBP_PS2MS_NAME1 "kdmouse" #define OBP_PS2MS_NAME2 "mouse" -static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_device_id *match) -{ - struct device_node *dp = op->node; - - dp = dp->child; - while (dp) { - if (!strcmp(dp->name, OBP_PS2KBD_NAME1) || - !strcmp(dp->name, OBP_PS2KBD_NAME2)) { - struct of_device *kbd = of_find_device_by_node(dp); - unsigned int irq = kbd->irqs[0]; - if (irq == 0xffffffff) - irq = op->irqs[0]; - i8042_kbd_irq = irq; - kbd_iobase = of_ioremap(&kbd->resource[0], - 0, 8, "kbd"); - } else if (!strcmp(dp->name, OBP_PS2MS_NAME1) || - !strcmp(dp->name, OBP_PS2MS_NAME2)) { - struct of_device *ms = of_find_device_by_node(dp); - unsigned int irq = ms->irqs[0]; - if (irq == 0xffffffff) - irq = op->irqs[0]; - i8042_aux_irq = irq; - } - - dp = dp->sibling; - } - - return 0; -} - -static int __devexit sparc_i8042_remove(struct of_device *op) -{ - of_iounmap(kbd_iobase, 8); - - return 0; -} - -static struct of_device_id sparc_i8042_match[] = { - { - .name = "8042", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, i8042_match); - -static struct of_platform_driver sparc_i8042_driver = { - .name = "i8042", - .match_table = sparc_i8042_match, - .probe = sparc_i8042_probe, - .remove = __devexit_p(sparc_i8042_remove), -}; - static int __init i8042_platform_init(void) { #ifndef CONFIG_PCI return -ENODEV; #else - struct device_node *root = of_find_node_by_path("/"); + char prop[128]; + int len; - if (!strcmp(root->name, "SUNW,JavaStation-1")) { + len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); + if (len < 0) { + printk("i8042: Cannot get name property of root OBP node.\n"); + return -ENODEV; + } + if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) { /* Hardcoded values for MrCoffee. */ i8042_kbd_irq = i8042_aux_irq = 13 | 0x20; kbd_iobase = ioremap(0x71300060, 8); if (!kbd_iobase) return -ENODEV; } else { - int err = of_register_driver(&sparc_i8042_driver, - &of_bus_type); - if (err) - return err; - + struct linux_ebus *ebus; + struct linux_ebus_device *edev; + struct linux_ebus_child *child; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_node->name, "8042")) + goto edev_found; + } + } + return -ENODEV; + + edev_found: + for_each_edevchild(edev, child) { + if (!strcmp(child->prom_node->name, OBP_PS2KBD_NAME1) || + !strcmp(child->prom_node->name, OBP_PS2KBD_NAME2)) { + i8042_kbd_irq = child->irqs[0]; + kbd_iobase = + ioremap(child->resource[0].start, 8); + } + if (!strcmp(child->prom_node->name, OBP_PS2MS_NAME1) || + !strcmp(child->prom_node->name, OBP_PS2MS_NAME2)) + i8042_aux_irq = child->irqs[0]; + } if (i8042_kbd_irq == -1 || i8042_aux_irq == -1) { - if (kbd_iobase) { - of_iounmap(kbd_iobase, 8); - kbd_iobase = (void __iomem *) NULL; - } + printk("i8042: Error, 8042 device lacks both kbd and " + "mouse nodes.\n"); return -ENODEV; } } @@ -136,10 +109,7 @@ static int __init i8042_platform_init(void) static inline void i8042_platform_exit(void) { #ifdef CONFIG_PCI - struct device_node *root = of_find_node_by_path("/"); - - if (strcmp(root->name, "SUNW,JavaStation-1")) - of_unregister_driver(&sparc_i8042_driver); + iounmap(kbd_iobase); #endif } diff --git a/trunk/drivers/net/sunhme.c b/trunk/drivers/net/sunhme.c index 9b246e44f756..c33ead3470db 100644 --- a/trunk/drivers/net/sunhme.c +++ b/trunk/drivers/net/sunhme.c @@ -2523,7 +2523,7 @@ static struct ethtool_ops hme_ethtool_ops = { static int hme_version_printed; #ifdef CONFIG_SBUS -void __devinit quattro_get_ranges(struct quattro *qp) +void __init quattro_get_ranges(struct quattro *qp) { struct sbus_dev *sdev = qp->quattro_dev; int err; @@ -2539,7 +2539,7 @@ void __devinit quattro_get_ranges(struct quattro *qp) qp->nranges = (err / sizeof(struct linux_prom_ranges)); } -static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp) +static void __init quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp) { struct sbus_dev *sdev = hp->happy_dev; int rng; @@ -2566,7 +2566,7 @@ static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal * * Return NULL on failure. */ -static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev) +static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev) { struct sbus_dev *sdev; struct quattro *qp; @@ -2618,7 +2618,7 @@ static void __init quattro_sbus_register_irqs(void) } } -static void quattro_sbus_free_irqs(void) +static void __devexit quattro_sbus_free_irqs(void) { struct quattro *qp; @@ -2662,7 +2662,7 @@ static struct quattro * __init quattro_pci_find(struct pci_dev *pdev) #endif /* CONFIG_PCI */ #ifdef CONFIG_SBUS -static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe) +static int __init happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe) { struct device_node *dp = sdev->ofdev.node; struct quattro *qp = NULL; diff --git a/trunk/drivers/serial/sunsab.c b/trunk/drivers/serial/sunsab.c index 141fedbefbc4..7da02d11c364 100644 --- a/trunk/drivers/serial/sunsab.c +++ b/trunk/drivers/serial/sunsab.c @@ -1,7 +1,7 @@ /* sunsab.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2002 David S. Miller (davem@redhat.com) * * Rewrote buffer handling to use CIRC(Circular Buffer) macros. * Maxim Krasnyanskiy @@ -12,7 +12,7 @@ * Theodore Ts'o , 2001-Oct-12 * * Ported to new 2.5.x UART layer. - * David S. Miller + * David S. Miller */ #include @@ -37,8 +37,8 @@ #include #include -#include -#include +#include +#include #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -976,188 +976,199 @@ static inline struct console *SUNSAB_CONSOLE(void) #define sunsab_console_init() do { } while (0) #endif -static int __devinit sunsab_init_one(struct uart_sunsab_port *up, - struct of_device *op, - unsigned long offset, - int line) +static void __init for_each_sab_edev(void (*callback)(struct linux_ebus_device *, void *), void *arg) { - up->port.line = line; - up->port.dev = &op->dev; - - up->port.mapbase = op->resource[0].start + offset; - up->port.membase = of_ioremap(&op->resource[0], offset, - sizeof(union sab82532_async_regs), - "sab"); - if (!up->port.membase) - return -ENOMEM; - up->regs = (union sab82532_async_regs __iomem *) up->port.membase; + struct linux_ebus *ebus; + struct linux_ebus_device *edev = NULL; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_node->name, "se")) { + callback(edev, arg); + continue; + } else if (!strcmp(edev->prom_node->name, "serial")) { + char *compat; + int clen; + + /* On RIO this can be an SE, check it. We could + * just check ebus->is_rio, but this is more portable. + */ + compat = of_get_property(edev->prom_node, + "compatible", &clen); + if (compat && clen > 0) { + if (strncmp(compat, "sab82532", 8) == 0) { + callback(edev, arg); + continue; + } + } + } + } + } +} - up->port.irq = op->irqs[0]; +static void __init sab_count_callback(struct linux_ebus_device *edev, void *arg) +{ + int *count_p = arg; - up->port.fifosize = SAB82532_XMIT_FIFO_SIZE; - up->port.iotype = UPIO_MEM; + (*count_p)++; +} - writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc); +static void __init sab_attach_callback(struct linux_ebus_device *edev, void *arg) +{ + int *instance_p = arg; + struct uart_sunsab_port *up; + unsigned long regs, offset; + int i; - up->port.ops = &sunsab_pops; - up->port.type = PORT_SUNSAB; - up->port.uartclk = SAB_BASE_BAUD; + /* Note: ports are located in reverse order */ + regs = edev->resource[0].start; + offset = sizeof(union sab82532_async_regs); + for (i = 0; i < 2; i++) { + up = &sunsab_ports[(*instance_p * 2) + 1 - i]; - up->type = readb(&up->regs->r.vstr) & 0x0f; - writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr); - writeb(0xff, &up->regs->w.pim); - if ((up->port.line & 0x1) == 0) { - up->pvr_dsr_bit = (1 << 0); - up->pvr_dtr_bit = (1 << 1); - } else { - up->pvr_dsr_bit = (1 << 3); - up->pvr_dtr_bit = (1 << 2); - } - up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4); - writeb(up->cached_pvr, &up->regs->w.pvr); - up->cached_mode = readb(&up->regs->rw.mode); - up->cached_mode |= SAB82532_MODE_FRTS; - writeb(up->cached_mode, &up->regs->rw.mode); - up->cached_mode |= SAB82532_MODE_RTS; - writeb(up->cached_mode, &up->regs->rw.mode); + memset(up, 0, sizeof(*up)); + up->regs = ioremap(regs + offset, sizeof(union sab82532_async_regs)); + up->port.irq = edev->irqs[0]; + up->port.fifosize = SAB82532_XMIT_FIFO_SIZE; + up->port.mapbase = (unsigned long)up->regs; + up->port.iotype = UPIO_MEM; - up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; - up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; + writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc); - if (!(up->port.line & 0x01)) { - int err; - - err = request_irq(up->port.irq, sunsab_interrupt, - SA_SHIRQ, "sab", up); - if (err) { - of_iounmap(up->port.membase, - sizeof(union sab82532_async_regs)); - return err; - } + offset -= sizeof(union sab82532_async_regs); } - - return 0; + + (*instance_p)++; } -static int __devinit sab_probe(struct of_device *op, const struct of_device_id *match) +static int __init probe_for_sabs(void) { - static int inst; - struct uart_sunsab_port *up; - int err; - - up = &sunsab_ports[inst * 2]; - - err = sunsab_init_one(&up[0], op, - sizeof(union sab82532_async_regs), - (inst * 2) + 0); - if (err) - return err; - - err = sunsab_init_one(&up[0], op, 0, - (inst * 2) + 1); - if (err) { - of_iounmap(up[0].port.membase, - sizeof(union sab82532_async_regs)); - free_irq(up[0].port.irq, &up[0]); - return err; - } + int this_sab = 0; - uart_add_one_port(&sunsab_reg, &up[0].port); - uart_add_one_port(&sunsab_reg, &up[1].port); + /* Find device instances. */ + for_each_sab_edev(&sab_count_callback, &this_sab); + if (!this_sab) + return -ENODEV; - dev_set_drvdata(&op->dev, &up[0]); + /* Allocate tables. */ + sunsab_ports = kmalloc(sizeof(struct uart_sunsab_port) * this_sab * 2, + GFP_KERNEL); + if (!sunsab_ports) + return -ENOMEM; - inst++; + num_channels = this_sab * 2; + this_sab = 0; + for_each_sab_edev(&sab_attach_callback, &this_sab); return 0; } -static void __devexit sab_remove_one(struct uart_sunsab_port *up) +static void __init sunsab_init_hw(void) { - uart_remove_one_port(&sunsab_reg, &up->port); - if (!(up->port.line & 1)) - free_irq(up->port.irq, up); - of_iounmap(up->port.membase, - sizeof(union sab82532_async_regs)); + int i; + + for (i = 0; i < num_channels; i++) { + struct uart_sunsab_port *up = &sunsab_ports[i]; + + up->port.line = i; + up->port.ops = &sunsab_pops; + up->port.type = PORT_SUNSAB; + up->port.uartclk = SAB_BASE_BAUD; + + up->type = readb(&up->regs->r.vstr) & 0x0f; + writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr); + writeb(0xff, &up->regs->w.pim); + if (up->port.line == 0) { + up->pvr_dsr_bit = (1 << 0); + up->pvr_dtr_bit = (1 << 1); + } else { + up->pvr_dsr_bit = (1 << 3); + up->pvr_dtr_bit = (1 << 2); + } + up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4); + writeb(up->cached_pvr, &up->regs->w.pvr); + up->cached_mode = readb(&up->regs->rw.mode); + up->cached_mode |= SAB82532_MODE_FRTS; + writeb(up->cached_mode, &up->regs->rw.mode); + up->cached_mode |= SAB82532_MODE_RTS; + writeb(up->cached_mode, &up->regs->rw.mode); + + up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; + up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; + + if (!(up->port.line & 0x01)) { + if (request_irq(up->port.irq, sunsab_interrupt, + SA_SHIRQ, "serial(sab82532)", up)) { + printk("sunsab%d: can't get IRQ %x\n", + i, up->port.irq); + continue; + } + } + } } -static int __devexit sab_remove(struct of_device *op) +static int __init sunsab_init(void) { - struct uart_sunsab_port *up = dev_get_drvdata(&op->dev); + int ret = probe_for_sabs(); + int i; - sab_remove_one(&up[0]); - sab_remove_one(&up[1]); + if (ret < 0) + return ret; - dev_set_drvdata(&op->dev, NULL); + sunsab_init_hw(); - return 0; -} + sunsab_reg.minor = sunserial_current_minor; + sunsab_reg.nr = num_channels; -static struct of_device_id sab_match[] = { - { - .name = "se", - }, - { - .name = "serial", - .compatible = "sab82532", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, sab_match); + ret = uart_register_driver(&sunsab_reg); + if (ret < 0) { + int i; -static struct of_platform_driver sab_driver = { - .name = "sab", - .match_table = sab_match, - .probe = sab_probe, - .remove = __devexit_p(sab_remove), -}; + for (i = 0; i < num_channels; i++) { + struct uart_sunsab_port *up = &sunsab_ports[i]; -static int __init sunsab_init(void) -{ - struct device_node *dp; - int err; - - num_channels = 0; - for_each_node_by_name(dp, "su") - num_channels += 2; - for_each_node_by_name(dp, "serial") { - if (of_device_is_compatible(dp, "sab82532")) - num_channels += 2; - } + if (!(up->port.line & 0x01)) + free_irq(up->port.irq, up); + iounmap(up->regs); + } + kfree(sunsab_ports); + sunsab_ports = NULL; - if (num_channels) { - sunsab_ports = kzalloc(sizeof(struct uart_sunsab_port) * - num_channels, GFP_KERNEL); - if (!sunsab_ports) - return -ENOMEM; + return ret; + } - sunsab_reg.minor = sunserial_current_minor; - sunsab_reg.nr = num_channels; + sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64; - err = uart_register_driver(&sunsab_reg); - if (err) { - kfree(sunsab_ports); - sunsab_ports = NULL; + sunsab_reg.cons = SUNSAB_CONSOLE(); - return err; - } + sunserial_current_minor += num_channels; + + for (i = 0; i < num_channels; i++) { + struct uart_sunsab_port *up = &sunsab_ports[i]; - sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64; - sunsab_reg.cons = SUNSAB_CONSOLE(); - sunserial_current_minor += num_channels; + uart_add_one_port(&sunsab_reg, &up->port); } - return of_register_driver(&sab_driver, &of_bus_type); + return 0; } static void __exit sunsab_exit(void) { - of_unregister_driver(&sab_driver); - if (num_channels) { - sunserial_current_minor -= num_channels; - uart_unregister_driver(&sunsab_reg); + int i; + + for (i = 0; i < num_channels; i++) { + struct uart_sunsab_port *up = &sunsab_ports[i]; + + uart_remove_one_port(&sunsab_reg, &up->port); + + if (!(up->port.line & 0x01)) + free_irq(up->port.irq, up); + iounmap(up->regs); } + sunserial_current_minor -= num_channels; + uart_unregister_driver(&sunsab_reg); + kfree(sunsab_ports); sunsab_ports = NULL; } diff --git a/trunk/drivers/serial/sunsu.c b/trunk/drivers/serial/sunsu.c index 73a043b914ef..6e28c25138cf 100644 --- a/trunk/drivers/serial/sunsu.c +++ b/trunk/drivers/serial/sunsu.c @@ -12,7 +12,7 @@ * Theodore Ts'o , 2001-Oct-12 * * Converted to new 2.5.x UART layer. - * David S. Miller (davem@davemloft.net), 2002-Jul-29 + * David S. Miller (davem@redhat.com), 2002-Jul-29 */ #include @@ -40,8 +40,11 @@ #include #include -#include -#include +#include +#include +#ifdef CONFIG_SPARC64 +#include +#endif #if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -91,10 +94,10 @@ struct uart_sunsu_port { /* Probing information. */ enum su_type su_type; unsigned int type_probed; /* XXX Stupid */ - unsigned long reg_size; + int port_node; #ifdef CONFIG_SERIO - struct serio serio; + struct serio *serio; int serio_open; #endif }; @@ -506,7 +509,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg /* Stop-A is handled by drivers/char/keyboard.c now. */ if (up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif } else if (up->su_type == SU_PORT_MS) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -520,7 +523,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg case 0: #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif break; }; @@ -1028,14 +1031,99 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) { unsigned char status1, status2, scratch, scratch2, scratch3; unsigned char save_lcr, save_mcr; + struct linux_ebus_device *dev = NULL; + struct linux_ebus *ebus; +#ifdef CONFIG_SPARC64 + struct sparc_isa_bridge *isa_br; + struct sparc_isa_device *isa_dev; +#endif +#ifndef CONFIG_SPARC64 + struct linux_prom_registers reg0; +#endif unsigned long flags; - if (up->su_type == SU_PORT_NONE) + if (!up->port_node || !up->su_type) return; up->type_probed = PORT_UNKNOWN; up->port.iotype = UPIO_MEM; + /* + * First we look for Ebus-bases su's + */ + for_each_ebus(ebus) { + for_each_ebusdev(dev, ebus) { + if (dev->prom_node->node == up->port_node) { + /* + * The EBus is broken on sparc; it delivers + * virtual addresses in resources. Oh well... + * This is correct on sparc64, though. + */ + up->port.membase = (char *) dev->resource[0].start; + /* + * This is correct on both architectures. + */ + up->port.mapbase = dev->resource[0].start; + up->port.irq = dev->irqs[0]; + goto ebus_done; + } + } + } + +#ifdef CONFIG_SPARC64 + for_each_isa(isa_br) { + for_each_isadev(isa_dev, isa_br) { + if (isa_dev->prom_node->node == up->port_node) { + /* Same on sparc64. Cool architecure... */ + up->port.membase = (char *) isa_dev->resource.start; + up->port.mapbase = isa_dev->resource.start; + up->port.irq = isa_dev->irq; + goto ebus_done; + } + } + } +#endif + +#ifdef CONFIG_SPARC64 + /* + * Not on Ebus, bailing. + */ + return; +#else + /* + * Not on Ebus, must be OBIO. + */ + if (prom_getproperty(up->port_node, "reg", + (char *)®0, sizeof(reg0)) == -1) { + prom_printf("sunsu: no \"reg\" property\n"); + return; + } + prom_apply_obio_ranges(®0, 1); + if (reg0.which_io != 0) { /* Just in case... */ + prom_printf("sunsu: bus number nonzero: 0x%x:%x\n", + reg0.which_io, reg0.phys_addr); + return; + } + up->port.mapbase = reg0.phys_addr; + if ((up->port.membase = ioremap(reg0.phys_addr, reg0.reg_size)) == 0) { + prom_printf("sunsu: Cannot map registers.\n"); + return; + } + + /* + * 0x20 is sun4m thing, Dave Redman heritage. + * See arch/sparc/kernel/irq.c. + */ +#define IRQ_4M(n) ((n)|0x20) + + /* + * There is no intr property on MrCoffee, so hardwire it. + */ + up->port.irq = IRQ_4M(13); +#endif + +ebus_done: + spin_lock_irqsave(&up->port.lock, flags); if (!(up->port.flags & UPF_BUGGY_UART)) { @@ -1181,13 +1269,18 @@ static struct uart_driver sunsu_reg = { .major = TTY_MAJOR, }; -static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up) +static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) { int quot, baud; #ifdef CONFIG_SERIO struct serio *serio; #endif + spin_lock_init(&up->port.lock); + up->port.line = channel; + up->port.type = PORT_UNKNOWN; + up->port.uartclk = (SU_BASE_BAUD * 16); + if (up->su_type == SU_PORT_KBD) { up->cflag = B1200 | CS8 | CLOCAL | CREAD; baud = 1200; @@ -1199,31 +1292,41 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up) sunsu_autoconfig(up); if (up->port.type == PORT_UNKNOWN) - return -ENODEV; + return -1; + + printk(KERN_INFO "su%d at 0x%p (irq = %d) is a %s\n", + channel, + up->port.membase, up->port.irq, + sunsu_type(&up->port)); #ifdef CONFIG_SERIO - serio = &up->serio; - serio->port_data = up; + up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(*serio)); - serio->id.type = SERIO_RS232; - if (up->su_type == SU_PORT_KBD) { - serio->id.proto = SERIO_SUNKBD; - strlcpy(serio->name, "sukbd", sizeof(serio->name)); - } else { - serio->id.proto = SERIO_SUN; - serio->id.extra = 1; - strlcpy(serio->name, "sums", sizeof(serio->name)); - } - strlcpy(serio->phys, - (!(up->port.line & 1) ? "su/serio0" : "su/serio1"), - sizeof(serio->phys)); + serio->port_data = up; + + serio->id.type = SERIO_RS232; + if (up->su_type == SU_PORT_KBD) { + serio->id.proto = SERIO_SUNKBD; + strlcpy(serio->name, "sukbd", sizeof(serio->name)); + } else { + serio->id.proto = SERIO_SUN; + serio->id.extra = 1; + strlcpy(serio->name, "sums", sizeof(serio->name)); + } + strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"), + sizeof(serio->phys)); - serio->write = sunsu_serio_write; - serio->open = sunsu_serio_open; - serio->close = sunsu_serio_close; - serio->dev.parent = up->port.dev; + serio->write = sunsu_serio_write; + serio->open = sunsu_serio_open; + serio->close = sunsu_serio_close; - serio_register_port(serio); + serio_register_port(serio); + } else { + printk(KERN_WARNING "su%d: not enough memory for serio port\n", + channel); + } #endif sunsu_change_speed(&up->port, up->cflag, 0, quot); @@ -1355,20 +1458,22 @@ static struct console sunsu_cons = { * Register console. */ -static inline struct console *SUNSU_CONSOLE(int num_uart) +static inline struct console *SUNSU_CONSOLE(void) { int i; if (con_is_present()) return NULL; - for (i = 0; i < num_uart; i++) { + for (i = 0; i < UART_NR; i++) { int this_minor = sunsu_reg.minor + i; if ((this_minor - 64) == (serial_console - 1)) break; } - if (i == num_uart) + if (i == UART_NR) + return NULL; + if (sunsu_ports[i].port_node == 0) return NULL; sunsu_cons.index = i; @@ -1376,184 +1481,252 @@ static inline struct console *SUNSU_CONSOLE(int num_uart) return &sunsu_cons; } #else -#define SUNSU_CONSOLE(num_uart) (NULL) +#define SUNSU_CONSOLE() (NULL) #define sunsu_serial_console_init() do { } while (0) #endif -static enum su_type __devinit su_get_type(struct device_node *dp) +static int __init sunsu_serial_init(void) { - struct device_node *ap = of_find_node_by_path("/aliases"); + int instance, ret, i; - if (ap) { - char *keyb = of_get_property(ap, "keyboard", NULL); - char *ms = of_get_property(ap, "mouse", NULL); + /* How many instances do we need? */ + instance = 0; + for (i = 0; i < UART_NR; i++) { + struct uart_sunsu_port *up = &sunsu_ports[i]; - if (keyb) { - if (dp == of_find_node_by_path(keyb)) - return SU_PORT_KBD; - } - if (ms) { - if (dp == of_find_node_by_path(ms)) - return SU_PORT_MS; - } - } + if (up->su_type == SU_PORT_MS || + up->su_type == SU_PORT_KBD) + continue; - return SU_PORT_PORT; -} + spin_lock_init(&up->port.lock); + up->port.flags |= UPF_BOOT_AUTOCONF; + up->port.type = PORT_UNKNOWN; + up->port.uartclk = (SU_BASE_BAUD * 16); -static int __devinit su_probe(struct of_device *op, const struct of_device_id *match) -{ - static int inst; - struct device_node *dp = op->node; - struct uart_sunsu_port *up; - struct resource *rp; - int err; + sunsu_autoconfig(up); + if (up->port.type == PORT_UNKNOWN) + continue; - if (inst >= UART_NR) - return -EINVAL; + up->port.line = instance++; + up->port.ops = &sunsu_pops; + } - up = &sunsu_ports[inst]; - up->port.line = inst; + sunsu_reg.minor = sunserial_current_minor; - spin_lock_init(&up->port.lock); + sunsu_reg.nr = instance; - up->su_type = su_get_type(dp); + ret = uart_register_driver(&sunsu_reg); + if (ret < 0) + return ret; - rp = &op->resource[0]; - up->port.mapbase = op->resource[0].start; + sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64; - up->reg_size = (rp->end - rp->start) + 1; - up->port.membase = of_ioremap(rp, 0, up->reg_size, "su"); - if (!up->port.membase) - return -ENOMEM; + sunserial_current_minor += instance; - up->port.irq = op->irqs[0]; + sunsu_reg.cons = SUNSU_CONSOLE(); - up->port.dev = &op->dev; + for (i = 0; i < UART_NR; i++) { + struct uart_sunsu_port *up = &sunsu_ports[i]; - up->port.type = PORT_UNKNOWN; - up->port.uartclk = (SU_BASE_BAUD * 16); + /* Do not register Keyboard/Mouse lines with UART + * layer. + */ + if (up->su_type == SU_PORT_MS || + up->su_type == SU_PORT_KBD) + continue; - err = 0; - if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) { - err = sunsu_kbd_ms_init(up); - if (err) - goto out_unmap; - } + if (up->port.type == PORT_UNKNOWN) + continue; - up->port.flags |= UPF_BOOT_AUTOCONF; + uart_add_one_port(&sunsu_reg, &up->port); + } - sunsu_autoconfig(up); + return 0; +} - err = -ENODEV; - if (up->port.type == PORT_UNKNOWN) - goto out_unmap; +static int su_node_ok(int node, char *name, int namelen) +{ + if (strncmp(name, "su", namelen) == 0 || + strncmp(name, "su_pnp", namelen) == 0) + return 1; + + if (strncmp(name, "serial", namelen) == 0) { + char compat[32]; + int clen; + + /* Is it _really_ a 'su' device? */ + clen = prom_getproperty(node, "compatible", compat, sizeof(compat)); + if (clen > 0) { + if (strncmp(compat, "sab82532", 8) == 0) { + /* Nope, Siemens serial, not for us. */ + return 0; + } + } + return 1; + } - up->port.ops = &sunsu_pops; + return 0; +} - err = uart_add_one_port(&sunsu_reg, &up->port); - if (err) - goto out_unmap; +#define SU_PROPSIZE 128 - dev_set_drvdata(&op->dev, up); +/* + * Scan status structure. + * "prop" is a local variable but it eats stack to keep it in each + * stack frame of a recursive procedure. + */ +struct su_probe_scan { + int msnode, kbnode; /* PROM nodes for mouse and keyboard */ + int msx, kbx; /* minors for mouse and keyboard */ + int devices; /* scan index */ + char prop[SU_PROPSIZE]; +}; - inst++; +/* + * We have several platforms which present 'su' in different parts + * of the device tree. 'su' may be found under obio, ebus, isa and pci. + * We walk over the tree and find them wherever PROM hides them. + */ +static void __init su_probe_any(struct su_probe_scan *t, int sunode) +{ + struct uart_sunsu_port *up; + int len; - return 0; + if (t->devices >= UART_NR) + return; -out_unmap: - of_iounmap(up->port.membase, up->reg_size); - return err; + for (; sunode != 0; sunode = prom_getsibling(sunode)) { + len = prom_getproperty(sunode, "name", t->prop, SU_PROPSIZE); + if (len <= 1) + continue; /* Broken PROM node */ + + if (su_node_ok(sunode, t->prop, len)) { + up = &sunsu_ports[t->devices]; + if (t->kbnode != 0 && sunode == t->kbnode) { + t->kbx = t->devices; + up->su_type = SU_PORT_KBD; + } else if (t->msnode != 0 && sunode == t->msnode) { + t->msx = t->devices; + up->su_type = SU_PORT_MS; + } else { +#ifdef CONFIG_SPARC64 + /* + * Do not attempt to use the truncated + * keyboard/mouse ports as serial ports + * on Ultras with PC keyboard attached. + */ + if (prom_getbool(sunode, "mouse")) + continue; + if (prom_getbool(sunode, "keyboard")) + continue; +#endif + up->su_type = SU_PORT_PORT; + } + up->port_node = sunode; + ++t->devices; + } else { + su_probe_any(t, prom_getchild(sunode)); + } + } } -static int __devexit su_remove(struct of_device *dev) +static int __init sunsu_probe(void) { - struct uart_sunsu_port *up = dev_get_drvdata(&dev->dev);; + int node; + int len; + struct su_probe_scan scan; - if (up->su_type == SU_PORT_MS || - up->su_type == SU_PORT_KBD) { -#ifdef CONFIG_SERIO - serio_unregister_port(&up->serio); -#endif - } else if (up->port.type != PORT_UNKNOWN) - uart_remove_one_port(&sunsu_reg, &up->port); + /* + * First, we scan the tree. + */ + scan.devices = 0; + scan.msx = -1; + scan.kbx = -1; + scan.kbnode = 0; + scan.msnode = 0; - return 0; -} + /* + * Get the nodes for keyboard and mouse from 'aliases'... + */ + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "aliases"); + if (node != 0) { + len = prom_getproperty(node, "keyboard", scan.prop, SU_PROPSIZE); + if (len > 0) { + scan.prop[len] = 0; + scan.kbnode = prom_finddevice(scan.prop); + } -static struct of_device_id su_match[] = { - { - .name = "su", - }, - { - .name = "su_pnp", - }, - { - .name = "serial", - .compatible = "su", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, su_match); + len = prom_getproperty(node, "mouse", scan.prop, SU_PROPSIZE); + if (len > 0) { + scan.prop[len] = 0; + scan.msnode = prom_finddevice(scan.prop); + } + } -static struct of_platform_driver su_driver = { - .name = "su", - .match_table = su_match, - .probe = su_probe, - .remove = __devexit_p(su_remove), -}; + su_probe_any(&scan, prom_getchild(prom_root_node)); -static int num_uart; + /* + * Second, we process the special case of keyboard and mouse. + * + * Currently if we got keyboard and mouse hooked to "su" ports + * we do not use any possible remaining "su" as a serial port. + * Thus, we ignore values of .msx and .kbx, then compact ports. + */ + if (scan.msx != -1 && scan.kbx != -1) { + sunsu_ports[0].su_type = SU_PORT_MS; + sunsu_ports[0].port_node = scan.msnode; + sunsu_kbd_ms_init(&sunsu_ports[0], 0); -static int __init sunsu_init(void) -{ - struct device_node *dp; - int err; + sunsu_ports[1].su_type = SU_PORT_KBD; + sunsu_ports[1].port_node = scan.kbnode; + sunsu_kbd_ms_init(&sunsu_ports[1], 1); - num_uart = 0; - for_each_node_by_name(dp, "su") { - if (su_get_type(dp) == SU_PORT_PORT) - num_uart++; - } - for_each_node_by_name(dp, "su_pnp") { - if (su_get_type(dp) == SU_PORT_PORT) - num_uart++; - } - for_each_node_by_name(dp, "serial") { - if (of_device_is_compatible(dp, "su")) { - if (su_get_type(dp) == SU_PORT_PORT) - num_uart++; - } + return 0; } - if (num_uart) { - sunsu_reg.minor = sunserial_current_minor; - sunsu_reg.nr = num_uart; - err = uart_register_driver(&sunsu_reg); - if (err) - return err; - sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64; - sunserial_current_minor += num_uart; - sunsu_reg.cons = SUNSU_CONSOLE(num_uart); + if (scan.msx != -1 || scan.kbx != -1) { + printk("sunsu_probe: cannot match keyboard and mouse, confused\n"); + return -ENODEV; } - err = of_register_driver(&su_driver, &of_bus_type); - if (err && num_uart) - uart_unregister_driver(&sunsu_reg); + if (scan.devices == 0) + return -ENODEV; + + /* + * Console must be initiated after the generic initialization. + */ + sunsu_serial_init(); - return err; + return 0; } static void __exit sunsu_exit(void) { - if (num_uart) + int i, saw_uart; + + saw_uart = 0; + for (i = 0; i < UART_NR; i++) { + struct uart_sunsu_port *up = &sunsu_ports[i]; + + if (up->su_type == SU_PORT_MS || + up->su_type == SU_PORT_KBD) { +#ifdef CONFIG_SERIO + if (up->serio) { + serio_unregister_port(up->serio); + up->serio = NULL; + } +#endif + } else if (up->port.type != PORT_UNKNOWN) { + uart_remove_one_port(&sunsu_reg, &up->port); + saw_uart++; + } + } + + if (saw_uart) uart_unregister_driver(&sunsu_reg); } -module_init(sunsu_init); +module_init(sunsu_probe); module_exit(sunsu_exit); - -MODULE_AUTHOR("Eddie C. Dost, Peter Zaitcev, and David S. Miller"); -MODULE_DESCRIPTION("Sun SU serial port driver"); -MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/serial/sunzilog.c b/trunk/drivers/serial/sunzilog.c index 1caa286a6be6..9f42677287ad 100644 --- a/trunk/drivers/serial/sunzilog.c +++ b/trunk/drivers/serial/sunzilog.c @@ -1,4 +1,5 @@ -/* sunzilog.c: Zilog serial driver for Sparc systems. +/* + * sunzilog.c * * Driver for Zilog serial chips found on Sun workstations and * servers. This driver could actually be made more generic. @@ -9,7 +10,7 @@ * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their * work there. * - * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2002 David S. Miller (davem@redhat.com) */ #include @@ -37,8 +38,10 @@ #include #include -#include -#include +#ifdef CONFIG_SPARC64 +#include +#endif +#include #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -62,7 +65,7 @@ #define ZSDELAY() #define ZSDELAY_LONG() #define ZS_WSYNC(__channel) \ - readb(&((__channel)->control)) + sbus_readb(&((__channel)->control)) #endif static int num_sunzilog; @@ -104,7 +107,7 @@ struct uart_sunzilog_port { unsigned char prev_status; #ifdef CONFIG_SERIO - struct serio serio; + struct serio *serio; int serio_open; #endif }; @@ -135,9 +138,9 @@ static unsigned char read_zsreg(struct zilog_channel __iomem *channel, { unsigned char retval; - writeb(reg, &channel->control); + sbus_writeb(reg, &channel->control); ZSDELAY(); - retval = readb(&channel->control); + retval = sbus_readb(&channel->control); ZSDELAY(); return retval; @@ -146,9 +149,9 @@ static unsigned char read_zsreg(struct zilog_channel __iomem *channel, static void write_zsreg(struct zilog_channel __iomem *channel, unsigned char reg, unsigned char value) { - writeb(reg, &channel->control); + sbus_writeb(reg, &channel->control); ZSDELAY(); - writeb(value, &channel->control); + sbus_writeb(value, &channel->control); ZSDELAY(); } @@ -159,17 +162,17 @@ static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel) for (i = 0; i < 32; i++) { unsigned char regval; - regval = readb(&channel->control); + regval = sbus_readb(&channel->control); ZSDELAY(); if (regval & Rx_CH_AV) break; regval = read_zsreg(channel, R1); - readb(&channel->data); + sbus_readb(&channel->data); ZSDELAY(); if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) { - writeb(ERR_RES, &channel->control); + sbus_writeb(ERR_RES, &channel->control); ZSDELAY(); ZS_WSYNC(channel); } @@ -191,7 +194,7 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char * udelay(100); } - writeb(ERR_RES, &channel->control); + sbus_writeb(ERR_RES, &channel->control); ZSDELAY(); ZS_WSYNC(channel); @@ -288,7 +291,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, /* Stop-A is handled by drivers/char/keyboard.c now. */ #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif } else if (ZS_IS_MOUSE(up)) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -303,7 +306,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, case 0: #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif break; }; @@ -327,12 +330,12 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, r1 = read_zsreg(channel, R1); if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { - writeb(ERR_RES, &channel->control); + sbus_writeb(ERR_RES, &channel->control); ZSDELAY(); ZS_WSYNC(channel); } - ch = readb(&channel->control); + ch = sbus_readb(&channel->control); ZSDELAY(); /* This funny hack depends upon BRK_ABRT not interfering @@ -344,7 +347,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, if (!(ch & Rx_CH_AV)) break; - ch = readb(&channel->data); + ch = sbus_readb(&channel->data); ZSDELAY(); ch &= up->parity_mask; @@ -403,10 +406,10 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, { unsigned char status; - status = readb(&channel->control); + status = sbus_readb(&channel->control); ZSDELAY(); - writeb(RES_EXT_INT, &channel->control); + sbus_writeb(RES_EXT_INT, &channel->control); ZSDELAY(); ZS_WSYNC(channel); @@ -418,7 +421,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, * confusing the PROM. */ while (1) { - status = readb(&channel->control); + status = sbus_readb(&channel->control); ZSDELAY(); if (!(status & BRK_ABRT)) break; @@ -455,7 +458,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, struct circ_buf *xmit; if (ZS_IS_CONS(up)) { - unsigned char status = readb(&channel->control); + unsigned char status = sbus_readb(&channel->control); ZSDELAY(); /* TX still busy? Just wait for the next TX done interrupt. @@ -484,7 +487,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, if (up->port.x_char) { up->flags |= SUNZILOG_FLAG_TX_ACTIVE; - writeb(up->port.x_char, &channel->data); + sbus_writeb(up->port.x_char, &channel->data); ZSDELAY(); ZS_WSYNC(channel); @@ -503,7 +506,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, goto ack_tx_int; up->flags |= SUNZILOG_FLAG_TX_ACTIVE; - writeb(xmit->buf[xmit->tail], &channel->data); + sbus_writeb(xmit->buf[xmit->tail], &channel->data); ZSDELAY(); ZS_WSYNC(channel); @@ -516,7 +519,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, return; ack_tx_int: - writeb(RES_Tx_P, &channel->control); + sbus_writeb(RES_Tx_P, &channel->control); ZSDELAY(); ZS_WSYNC(channel); } @@ -537,7 +540,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg /* Channel A */ tty = NULL; if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { - writeb(RES_H_IUS, &channel->control); + sbus_writeb(RES_H_IUS, &channel->control); ZSDELAY(); ZS_WSYNC(channel); @@ -560,7 +563,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg spin_lock(&up->port.lock); tty = NULL; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { - writeb(RES_H_IUS, &channel->control); + sbus_writeb(RES_H_IUS, &channel->control); ZSDELAY(); ZS_WSYNC(channel); @@ -591,7 +594,7 @@ static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *p unsigned char status; channel = ZILOG_CHANNEL_FROM_PORT(port); - status = readb(&channel->control); + status = sbus_readb(&channel->control); ZSDELAY(); return status; @@ -679,7 +682,7 @@ static void sunzilog_start_tx(struct uart_port *port) up->flags |= SUNZILOG_FLAG_TX_ACTIVE; up->flags &= ~SUNZILOG_FLAG_TX_STOPPED; - status = readb(&channel->control); + status = sbus_readb(&channel->control); ZSDELAY(); /* TX busy? Just wait for the TX done interrupt. */ @@ -690,7 +693,7 @@ static void sunzilog_start_tx(struct uart_port *port) * IRQ sending engine. */ if (port->x_char) { - writeb(port->x_char, &channel->data); + sbus_writeb(port->x_char, &channel->data); ZSDELAY(); ZS_WSYNC(channel); @@ -699,7 +702,7 @@ static void sunzilog_start_tx(struct uart_port *port) } else { struct circ_buf *xmit = &port->info->xmit; - writeb(xmit->buf[xmit->tail], &channel->data); + sbus_writeb(xmit->buf[xmit->tail], &channel->data); ZSDELAY(); ZS_WSYNC(channel); @@ -776,7 +779,7 @@ static void __sunzilog_startup(struct uart_sunzilog_port *up) struct zilog_channel __iomem *channel; channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - up->prev_status = readb(&channel->control); + up->prev_status = sbus_readb(&channel->control); /* Enable receiver and transmitter. */ up->curregs[R3] |= RxENAB; @@ -960,7 +963,7 @@ sunzilog_set_termios(struct uart_port *port, struct termios *termios, static const char *sunzilog_type(struct uart_port *port) { - return "zs"; + return "SunZilog"; } /* We do not request/release mappings of the registers here, this @@ -1009,6 +1012,7 @@ static struct uart_sunzilog_port *sunzilog_port_table; static struct zilog_layout __iomem **sunzilog_chip_regs; static struct uart_sunzilog_port *sunzilog_irq_chain; +static int zilog_irq = -1; static struct uart_driver sunzilog_reg = { .owner = THIS_MODULE, @@ -1017,47 +1021,232 @@ static struct uart_driver sunzilog_reg = { .major = TTY_MAJOR, }; -static int __init sunzilog_alloc_tables(void) +static void * __init alloc_one_table(unsigned long size) { - struct uart_sunzilog_port *up; - unsigned long size; - int i; + void *ret; - size = NUM_CHANNELS * sizeof(struct uart_sunzilog_port); - sunzilog_port_table = kzalloc(size, GFP_KERNEL); - if (!sunzilog_port_table) - return -ENOMEM; + ret = kmalloc(size, GFP_KERNEL); + if (ret != NULL) + memset(ret, 0, size); - for (i = 0; i < NUM_CHANNELS; i++) { - up = &sunzilog_port_table[i]; + return ret; +} + +static void __init sunzilog_alloc_tables(void) +{ + sunzilog_port_table = + alloc_one_table(NUM_CHANNELS * sizeof(struct uart_sunzilog_port)); + sunzilog_chip_regs = + alloc_one_table(NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *)); + + if (sunzilog_port_table == NULL || sunzilog_chip_regs == NULL) { + prom_printf("SunZilog: Cannot allocate tables.\n"); + prom_halt(); + } +} - spin_lock_init(&up->port.lock); +#ifdef CONFIG_SPARC64 - if (i == 0) - sunzilog_irq_chain = up; +/* We used to attempt to use the address property of the Zilog device node + * but that totally is not necessary on sparc64. + */ +static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode) +{ + void __iomem *mapped_addr; + unsigned int sun4u_ino; + struct sbus_bus *sbus = NULL; + struct sbus_dev *sdev = NULL; + int err; - if (i < NUM_CHANNELS - 1) - up->next = up + 1; - else - up->next = NULL; + if (central_bus == NULL) { + for_each_sbus(sbus) { + for_each_sbusdev(sdev, sbus) { + if (sdev->prom_node == zsnode) + goto found; + } + } + } + found: + if (sdev == NULL && central_bus == NULL) { + prom_printf("SunZilog: sdev&¢ral == NULL for " + "Zilog %d in get_zs_sun4u.\n", chip); + prom_halt(); + } + if (central_bus == NULL) { + mapped_addr = + sbus_ioremap(&sdev->resource[0], 0, + PAGE_SIZE, + "Zilog Registers"); + } else { + struct linux_prom_registers zsregs[1]; + + err = prom_getproperty(zsnode, "reg", + (char *) &zsregs[0], + sizeof(zsregs)); + if (err == -1) { + prom_printf("SunZilog: Cannot map " + "Zilog %d regs on " + "central bus.\n", chip); + prom_halt(); + } + apply_fhc_ranges(central_bus->child, + &zsregs[0], 1); + apply_central_ranges(central_bus, &zsregs[0], 1); + mapped_addr = (void __iomem *) + ((((u64)zsregs[0].which_io)<<32UL) | + ((u64)zsregs[0].phys_addr)); } - size = NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *); - sunzilog_chip_regs = kzalloc(size, GFP_KERNEL); - if (!sunzilog_chip_regs) { - kfree(sunzilog_port_table); - sunzilog_irq_chain = NULL; - return -ENOMEM; + if (zilog_irq == -1) { + if (central_bus) { + unsigned long iclr, imap; + + iclr = central_bus->child->fhc_regs.uregs + + FHC_UREGS_ICLR; + imap = central_bus->child->fhc_regs.uregs + + FHC_UREGS_IMAP; + zilog_irq = build_irq(0, iclr, imap); + } else { + err = prom_getproperty(zsnode, "interrupts", + (char *) &sun4u_ino, + sizeof(sun4u_ino)); + zilog_irq = sbus_build_irq(sbus_root, sun4u_ino); + } } - return 0; + return (struct zilog_layout __iomem *) mapped_addr; } +#else /* CONFIG_SPARC64 */ -static void sunzilog_free_tables(void) +/* + * XXX The sun4d case is utterly screwed: it tries to re-walk the tree + * (for the 3rd time) in order to find bootbus and cpu. Streamline it. + */ +static struct zilog_layout __iomem * __init get_zs_sun4cmd(int chip, int node) { - kfree(sunzilog_port_table); - sunzilog_irq_chain = NULL; - kfree(sunzilog_chip_regs); + struct linux_prom_irqs irq_info[2]; + void __iomem *mapped_addr = NULL; + int zsnode, cpunode, bbnode; + struct linux_prom_registers zsreg[4]; + struct resource res; + + if (sparc_cpu_model == sun4d) { + int walk; + + zsnode = 0; + bbnode = 0; + cpunode = 0; + for (walk = prom_getchild(prom_root_node); + (walk = prom_searchsiblings(walk, "cpu-unit")) != 0; + walk = prom_getsibling(walk)) { + bbnode = prom_getchild(walk); + if (bbnode && + (bbnode = prom_searchsiblings(bbnode, "bootbus"))) { + if ((zsnode = prom_getchild(bbnode)) == node) { + cpunode = walk; + break; + } + } + } + if (!walk) { + prom_printf("SunZilog: Cannot find the %d'th bootbus on sun4d.\n", + (chip / 2)); + prom_halt(); + } + + if (prom_getproperty(zsnode, "reg", + (char *) zsreg, sizeof(zsreg)) == -1) { + prom_printf("SunZilog: Cannot map Zilog %d\n", chip); + prom_halt(); + } + /* XXX Looks like an off by one? */ + prom_apply_generic_ranges(bbnode, cpunode, zsreg, 1); + res.start = zsreg[0].phys_addr; + res.end = res.start + (8 - 1); + res.flags = zsreg[0].which_io | IORESOURCE_IO; + mapped_addr = sbus_ioremap(&res, 0, 8, "Zilog Serial"); + + } else { + zsnode = node; + +#if 0 /* XXX When was this used? */ + if (prom_getintdefault(zsnode, "slave", -1) != chipid) { + zsnode = prom_getsibling(zsnode); + continue; + } +#endif + + /* + * "address" is only present on ports that OBP opened + * (from Mitch Bradley's "Hitchhiker's Guide to OBP"). + * We do not use it. + */ + + if (prom_getproperty(zsnode, "reg", + (char *) zsreg, sizeof(zsreg)) == -1) { + prom_printf("SunZilog: Cannot map Zilog %d\n", chip); + prom_halt(); + } + if (sparc_cpu_model == sun4m) /* Crude. Pass parent. XXX */ + prom_apply_obio_ranges(zsreg, 1); + res.start = zsreg[0].phys_addr; + res.end = res.start + (8 - 1); + res.flags = zsreg[0].which_io | IORESOURCE_IO; + mapped_addr = sbus_ioremap(&res, 0, 8, "Zilog Serial"); + } + + if (prom_getproperty(zsnode, "intr", + (char *) irq_info, sizeof(irq_info)) + % sizeof(struct linux_prom_irqs)) { + prom_printf("SunZilog: Cannot get IRQ property for Zilog %d.\n", + chip); + prom_halt(); + } + if (zilog_irq == -1) { + zilog_irq = irq_info[0].pri; + } else if (zilog_irq != irq_info[0].pri) { + /* XXX. Dumb. Should handle per-chip IRQ, for add-ons. */ + prom_printf("SunZilog: Inconsistent IRQ layout for Zilog %d.\n", + chip); + prom_halt(); + } + + return (struct zilog_layout __iomem *) mapped_addr; +} +#endif /* !(CONFIG_SPARC64) */ + +/* Get the address of the registers for SunZilog instance CHIP. */ +static struct zilog_layout __iomem * __init get_zs(int chip, int node) +{ + if (chip < 0 || chip >= NUM_SUNZILOG) { + prom_printf("SunZilog: Illegal chip number %d in get_zs.\n", chip); + prom_halt(); + } + +#ifdef CONFIG_SPARC64 + return get_zs_sun4u(chip, node); +#else + + if (sparc_cpu_model == sun4) { + struct resource res; + + /* Not probe-able, hard code it. */ + switch (chip) { + case 0: + res.start = 0xf1000000; + break; + case 1: + res.start = 0xf0000000; + break; + }; + zilog_irq = 12; + res.end = (res.start + (8 - 1)); + res.flags = IORESOURCE_IO; + return sbus_ioremap(&res, 0, 8, "SunZilog"); + } + + return get_zs_sun4cmd(chip, node); +#endif } #define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ @@ -1071,7 +1260,7 @@ static void sunzilog_putchar(struct uart_port *port, int ch) * udelay with ZSDELAY as that is a NOP on some platforms. -DaveM */ do { - unsigned char val = readb(&channel->control); + unsigned char val = sbus_readb(&channel->control); if (val & Tx_BUF_EMP) { ZSDELAY(); break; @@ -1079,7 +1268,7 @@ static void sunzilog_putchar(struct uart_port *port, int ch) udelay(5); } while (--loops); - writeb(ch, &channel->data); + sbus_writeb(ch, &channel->data); ZSDELAY(); ZS_WSYNC(channel); } @@ -1196,6 +1385,28 @@ static struct console sunzilog_console = { .data = &sunzilog_reg, }; +static int __init sunzilog_console_init(void) +{ + int i; + + if (con_is_present()) + return 0; + + for (i = 0; i < NUM_CHANNELS; i++) { + int this_minor = sunzilog_reg.minor + i; + + if ((this_minor - 64) == (serial_console - 1)) + break; + } + if (i == NUM_CHANNELS) + return 0; + + sunzilog_console.index = i; + sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS; + register_console(&sunzilog_console); + return 0; +} + static inline struct console *SUNZILOG_CONSOLE(void) { int i; @@ -1220,8 +1431,101 @@ static inline struct console *SUNZILOG_CONSOLE(void) #else #define SUNZILOG_CONSOLE() (NULL) +#define sunzilog_console_init() do { } while (0) #endif +/* + * We scan the PROM tree recursively. This is the most reliable way + * to find Zilog nodes on various platforms. However, we face an extreme + * shortage of kernel stack, so we must be very careful. To that end, + * we scan only to a certain depth, and we use a common property buffer + * in the scan structure. + */ +#define ZS_PROPSIZE 128 +#define ZS_SCAN_DEPTH 5 + +struct zs_probe_scan { + int depth; + void (*scanner)(struct zs_probe_scan *t, int node); + + int devices; + char prop[ZS_PROPSIZE]; +}; + +static int __inline__ sunzilog_node_ok(int node, const char *name, int len) +{ + if (strncmp(name, "zs", len) == 0) + return 1; + /* Don't fold this procedure just yet. Compare to su_node_ok(). */ + return 0; +} + +static void __init sunzilog_scan(struct zs_probe_scan *t, int node) +{ + int len; + + for (; node != 0; node = prom_getsibling(node)) { + len = prom_getproperty(node, "name", t->prop, ZS_PROPSIZE); + if (len <= 1) + continue; /* Broken PROM node */ + if (sunzilog_node_ok(node, t->prop, len)) { + (*t->scanner)(t, node); + } else { + if (t->depth < ZS_SCAN_DEPTH) { + t->depth++; + sunzilog_scan(t, prom_getchild(node)); + --t->depth; + } + } + } +} + +static void __init sunzilog_prepare(void) +{ + struct uart_sunzilog_port *up; + struct zilog_layout __iomem *rp; + int channel, chip; + + /* + * Temporary fix. + */ + for (channel = 0; channel < NUM_CHANNELS; channel++) + spin_lock_init(&sunzilog_port_table[channel].port.lock); + + sunzilog_irq_chain = up = &sunzilog_port_table[0]; + for (channel = 0; channel < NUM_CHANNELS - 1; channel++) + up[channel].next = &up[channel + 1]; + up[channel].next = NULL; + + for (chip = 0; chip < NUM_SUNZILOG; chip++) { + rp = sunzilog_chip_regs[chip]; + up[(chip * 2) + 0].port.membase = (void __iomem *)&rp->channelA; + up[(chip * 2) + 1].port.membase = (void __iomem *)&rp->channelB; + + /* Channel A */ + up[(chip * 2) + 0].port.iotype = UPIO_MEM; + up[(chip * 2) + 0].port.irq = zilog_irq; + up[(chip * 2) + 0].port.uartclk = ZS_CLOCK; + up[(chip * 2) + 0].port.fifosize = 1; + up[(chip * 2) + 0].port.ops = &sunzilog_pops; + up[(chip * 2) + 0].port.type = PORT_SUNZILOG; + up[(chip * 2) + 0].port.flags = 0; + up[(chip * 2) + 0].port.line = (chip * 2) + 0; + up[(chip * 2) + 0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; + + /* Channel B */ + up[(chip * 2) + 1].port.iotype = UPIO_MEM; + up[(chip * 2) + 1].port.irq = zilog_irq; + up[(chip * 2) + 1].port.uartclk = ZS_CLOCK; + up[(chip * 2) + 1].port.fifosize = 1; + up[(chip * 2) + 1].port.ops = &sunzilog_pops; + up[(chip * 2) + 1].port.type = PORT_SUNZILOG; + up[(chip * 2) + 1].port.flags = 0; + up[(chip * 2) + 1].port.line = (chip * 2) + 1; + up[(chip * 2) + 1].flags |= 0; + } +} + static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel) { int baud, brg; @@ -1235,6 +1539,8 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe up->cflag = B4800 | CS8 | CLOCAL | CREAD; baud = 4800; } + printk(KERN_INFO "zs%d at 0x%p (irq = %d) is a SunZilog\n", + channel, up->port.membase, zilog_irq); up->curregs[R15] = BRKIE; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); @@ -1246,268 +1552,216 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe #ifdef CONFIG_SERIO static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel) { - struct serio *serio = &up->serio; + struct serio *serio; - serio->port_data = up; + up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(*serio)); - serio->id.type = SERIO_RS232; - if (channel == KEYBOARD_LINE) { - serio->id.proto = SERIO_SUNKBD; - strlcpy(serio->name, "zskbd", sizeof(serio->name)); - } else { - serio->id.proto = SERIO_SUN; - serio->id.extra = 1; - strlcpy(serio->name, "zsms", sizeof(serio->name)); - } - strlcpy(serio->phys, - (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"), - sizeof(serio->phys)); + serio->port_data = up; + + serio->id.type = SERIO_RS232; + if (channel == KEYBOARD_LINE) { + serio->id.proto = SERIO_SUNKBD; + strlcpy(serio->name, "zskbd", sizeof(serio->name)); + } else { + serio->id.proto = SERIO_SUN; + serio->id.extra = 1; + strlcpy(serio->name, "zsms", sizeof(serio->name)); + } + strlcpy(serio->phys, + (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"), + sizeof(serio->phys)); - serio->write = sunzilog_serio_write; - serio->open = sunzilog_serio_open; - serio->close = sunzilog_serio_close; - serio->dev.parent = up->port.dev; + serio->write = sunzilog_serio_write; + serio->open = sunzilog_serio_open; + serio->close = sunzilog_serio_close; - serio_register_port(serio); + serio_register_port(serio); + } else { + printk(KERN_WARNING "zs%d: not enough memory for serio port\n", + channel); + } } #endif -static void __init sunzilog_init_hw(struct uart_sunzilog_port *up) +static void __init sunzilog_init_hw(void) { - struct zilog_channel __iomem *channel; - unsigned long flags; - int baud, brg; + int i; - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + for (i = 0; i < NUM_CHANNELS; i++) { + struct uart_sunzilog_port *up = &sunzilog_port_table[i]; + struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + unsigned long flags; + int baud, brg; - spin_lock_irqsave(&up->port.lock, flags); - if (ZS_IS_CHANNEL_A(up)) { - write_zsreg(channel, R9, FHWRES); - ZSDELAY_LONG(); - (void) read_zsreg(channel, R0); - } + spin_lock_irqsave(&up->port.lock, flags); - if (up->port.line == KEYBOARD_LINE || - up->port.line == MOUSE_LINE) { - sunzilog_init_kbdms(up, up->port.line); - up->curregs[R9] |= (NV | MIE); - write_zsreg(channel, R9, up->curregs[R9]); - } else { - /* Normal serial TTY. */ - up->parity_mask = 0xff; - up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; - up->curregs[R4] = PAR_EVEN | X16CLK | SB1; - up->curregs[R3] = RxENAB | Rx8; - up->curregs[R5] = TxENAB | Tx8; - up->curregs[R9] = NV | MIE; - up->curregs[R10] = NRZ; - up->curregs[R11] = TCBR | RCBR; - baud = 9600; - brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); - up->curregs[R12] = (brg & 0xff); - up->curregs[R13] = (brg >> 8) & 0xff; - up->curregs[R14] = BRSRC | BRENAB; - __load_zsregs(channel, up->curregs); - write_zsreg(channel, R9, up->curregs[R9]); - } + if (ZS_IS_CHANNEL_A(up)) { + write_zsreg(channel, R9, FHWRES); + ZSDELAY_LONG(); + (void) read_zsreg(channel, R0); + } - spin_unlock_irqrestore(&up->port.lock, flags); + if (i == KEYBOARD_LINE || i == MOUSE_LINE) { + sunzilog_init_kbdms(up, i); + up->curregs[R9] |= (NV | MIE); + write_zsreg(channel, R9, up->curregs[R9]); + } else { + /* Normal serial TTY. */ + up->parity_mask = 0xff; + up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; + up->curregs[R4] = PAR_EVEN | X16CLK | SB1; + up->curregs[R3] = RxENAB | Rx8; + up->curregs[R5] = TxENAB | Tx8; + up->curregs[R9] = NV | MIE; + up->curregs[R10] = NRZ; + up->curregs[R11] = TCBR | RCBR; + baud = 9600; + brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); + up->curregs[R12] = (brg & 0xff); + up->curregs[R13] = (brg >> 8) & 0xff; + up->curregs[R14] = BRSRC | BRENAB; + __load_zsregs(channel, up->curregs); + write_zsreg(channel, R9, up->curregs[R9]); + } + + spin_unlock_irqrestore(&up->port.lock, flags); #ifdef CONFIG_SERIO - if (up->port.line == KEYBOARD_LINE || up->port.line == MOUSE_LINE) - sunzilog_register_serio(up, up->port.line); + if (i == KEYBOARD_LINE || i == MOUSE_LINE) + sunzilog_register_serio(up, i); #endif + } } -static int __devinit zs_get_instance(struct device_node *dp) +static struct zilog_layout __iomem * __init get_zs(int chip, int node); + +static void __init sunzilog_scan_probe(struct zs_probe_scan *t, int node) { - int ret; + sunzilog_chip_regs[t->devices] = get_zs(t->devices, node); + t->devices++; +} - ret = of_getintprop_default(dp, "slave", -1); - if (ret != -1) - return ret; +static int __init sunzilog_ports_init(void) +{ + struct zs_probe_scan scan; + int ret; + int uart_count; + int i; - if (of_find_property(dp, "keyboard", NULL)) - ret = 1; - else - ret = 0; + printk(KERN_DEBUG "SunZilog: %d chips.\n", NUM_SUNZILOG); - return ret; -} + scan.scanner = sunzilog_scan_probe; + scan.depth = 0; + scan.devices = 0; + sunzilog_scan(&scan, prom_getchild(prom_root_node)); -static int zilog_irq = -1; + sunzilog_prepare(); -static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); - struct uart_sunzilog_port *up; - struct zilog_layout __iomem *rp; - int inst = zs_get_instance(dev->node); - int err; + if (request_irq(zilog_irq, sunzilog_interrupt, SA_SHIRQ, + "SunZilog", sunzilog_irq_chain)) { + prom_printf("SunZilog: Unable to register zs interrupt handler.\n"); + prom_halt(); + } - sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0, - sizeof(struct zilog_layout), - "zs"); - if (!sunzilog_chip_regs[inst]) - return -ENOMEM; + sunzilog_init_hw(); - rp = sunzilog_chip_regs[inst]; + /* We can only init this once we have probed the Zilogs + * in the system. Do not count channels assigned to keyboards + * or mice when we are deciding how many ports to register. + */ + uart_count = 0; + for (i = 0; i < NUM_CHANNELS; i++) { + struct uart_sunzilog_port *up = &sunzilog_port_table[i]; - if (zilog_irq == -1) { - zilog_irq = op->irqs[0]; - err = request_irq(zilog_irq, sunzilog_interrupt, SA_SHIRQ, - "zs", sunzilog_irq_chain); - if (err) { - of_iounmap(rp, sizeof(struct zilog_layout)); + if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) + continue; - return err; - } + uart_count++; } + + sunzilog_reg.nr = uart_count; + sunzilog_reg.minor = sunserial_current_minor; - up = &sunzilog_port_table[inst * 2]; - - /* Channel A */ - up[0].port.mapbase = op->resource[0].start + 0x00; - up[0].port.membase = (void __iomem *) &rp->channelA; - up[0].port.iotype = UPIO_MEM; - up[0].port.irq = op->irqs[0]; - up[0].port.uartclk = ZS_CLOCK; - up[0].port.fifosize = 1; - up[0].port.ops = &sunzilog_pops; - up[0].port.type = PORT_SUNZILOG; - up[0].port.flags = 0; - up[0].port.line = (inst * 2) + 0; - up[0].port.dev = &op->dev; - up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; - if (inst == 1) - up[0].flags |= SUNZILOG_FLAG_CONS_KEYB; - sunzilog_init_hw(&up[0]); - - /* Channel B */ - up[1].port.mapbase = op->resource[0].start + 0x04; - up[1].port.membase = (void __iomem *) &rp->channelB; - up[1].port.iotype = UPIO_MEM; - up[1].port.irq = op->irqs[0]; - up[1].port.uartclk = ZS_CLOCK; - up[1].port.fifosize = 1; - up[1].port.ops = &sunzilog_pops; - up[1].port.type = PORT_SUNZILOG; - up[1].port.flags = 0; - up[1].port.line = (inst * 2) + 1; - up[1].port.dev = &op->dev; - up[1].flags |= 0; - if (inst == 1) - up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE; - sunzilog_init_hw(&up[1]); - - if (inst != 1) { - err = uart_add_one_port(&sunzilog_reg, &up[0].port); - if (err) { - of_iounmap(rp, sizeof(struct zilog_layout)); - return err; - } - err = uart_add_one_port(&sunzilog_reg, &up[1].port); - if (err) { - uart_remove_one_port(&sunzilog_reg, &up[0].port); - of_iounmap(rp, sizeof(struct zilog_layout)); - return err; + ret = uart_register_driver(&sunzilog_reg); + if (ret == 0) { + sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; + sunzilog_reg.cons = SUNZILOG_CONSOLE(); + + sunserial_current_minor += uart_count; + + for (i = 0; i < NUM_CHANNELS; i++) { + struct uart_sunzilog_port *up = &sunzilog_port_table[i]; + + if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) + continue; + + if (uart_add_one_port(&sunzilog_reg, &up->port)) { + printk(KERN_ERR + "SunZilog: failed to add port zs%d\n", i); + } } } - dev_set_drvdata(&dev->dev, &up[0]); - - return 0; + return ret; } -static void __devexit zs_remove_one(struct uart_sunzilog_port *up) +static void __init sunzilog_scan_count(struct zs_probe_scan *t, int node) { - if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { -#ifdef CONFIG_SERIO - serio_unregister_port(&up->serio); -#endif - } else - uart_remove_one_port(&sunzilog_reg, &up->port); + t->devices++; } -static int __devexit zs_remove(struct of_device *dev) +static int __init sunzilog_ports_count(void) { - struct uart_sunzilog_port *up = dev_get_drvdata(&dev->dev); - struct zilog_layout __iomem *regs; + struct zs_probe_scan scan; - zs_remove_one(&up[0]); - zs_remove_one(&up[1]); + /* Sun4 Zilog setup is hard coded, no probing to do. */ + if (sparc_cpu_model == sun4) + return 2; - regs = sunzilog_chip_regs[up[0].port.line / 2]; - of_iounmap(regs, sizeof(struct zilog_layout)); + scan.scanner = sunzilog_scan_count; + scan.depth = 0; + scan.devices = 0; - dev_set_drvdata(&dev->dev, NULL); + sunzilog_scan(&scan, prom_getchild(prom_root_node)); - return 0; + return scan.devices; } -static struct of_device_id zs_match[] = { - { - .name = "zs", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, zs_match); - -static struct of_platform_driver zs_driver = { - .name = "zs", - .match_table = zs_match, - .probe = zs_probe, - .remove = __devexit_p(zs_remove), -}; - static int __init sunzilog_init(void) { - struct device_node *dp; - int err; - - NUM_SUNZILOG = 0; - for_each_node_by_name(dp, "zs") - NUM_SUNZILOG++; - if (NUM_SUNZILOG) { - int uart_count; + NUM_SUNZILOG = sunzilog_ports_count(); + if (NUM_SUNZILOG == 0) + return -ENODEV; - err = sunzilog_alloc_tables(); - if (err) - return err; + sunzilog_alloc_tables(); - /* Subtract 1 for keyboard, 1 for mouse. */ - uart_count = (NUM_SUNZILOG * 2) - 2; + sunzilog_ports_init(); - sunzilog_reg.nr = uart_count; - sunzilog_reg.minor = sunserial_current_minor; - err = uart_register_driver(&sunzilog_reg); - if (err) { - sunzilog_free_tables(); - return err; - } - sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; - sunzilog_reg.cons = SUNZILOG_CONSOLE(); - - sunserial_current_minor += uart_count; - } - - return of_register_driver(&zs_driver, &of_bus_type); + return 0; } static void __exit sunzilog_exit(void) { - of_unregister_driver(&zs_driver); + int i; - if (zilog_irq != -1) { - free_irq(zilog_irq, sunzilog_irq_chain); - zilog_irq = -1; - } + for (i = 0; i < NUM_CHANNELS; i++) { + struct uart_sunzilog_port *up = &sunzilog_port_table[i]; - if (NUM_SUNZILOG) { - uart_unregister_driver(&sunzilog_reg); - sunzilog_free_tables(); + if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { +#ifdef CONFIG_SERIO + if (up->serio) { + serio_unregister_port(up->serio); + up->serio = NULL; + } +#endif + } else + uart_remove_one_port(&sunzilog_reg, &up->port); } + + uart_unregister_driver(&sunzilog_reg); } module_init(sunzilog_init); @@ -1515,5 +1769,4 @@ module_exit(sunzilog_exit); MODULE_AUTHOR("David S. Miller"); MODULE_DESCRIPTION("Sun Zilog serial port driver"); -MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/bw2.c b/trunk/drivers/video/bw2.c index c66e3d52cbf3..6577fdfdfc16 100644 --- a/trunk/drivers/video/bw2.c +++ b/trunk/drivers/video/bw2.c @@ -1,6 +1,6 @@ /* bw2.c: BWTWO frame buffer driver * - * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -19,11 +19,14 @@ #include #include +#include #include -#include -#include #include +#ifdef CONFIG_SPARC32 +#include +#endif + #include "sbuslib.h" /* @@ -56,30 +59,30 @@ static struct fb_ops bw2_ops = { #define BWTWO_REGISTER_OFFSET 0x400000 struct bt_regs { - u32 addr; - u32 color_map; - u32 control; - u32 cursor; + volatile u32 addr; + volatile u32 color_map; + volatile u32 control; + volatile u32 cursor; }; struct bw2_regs { struct bt_regs cmap; - u8 control; - u8 status; - u8 cursor_start; - u8 cursor_end; - u8 h_blank_start; - u8 h_blank_end; - u8 h_sync_start; - u8 h_sync_end; - u8 comp_sync_end; - u8 v_blank_start_high; - u8 v_blank_start_low; - u8 v_blank_end; - u8 v_sync_start; - u8 v_sync_end; - u8 xfer_holdoff_start; - u8 xfer_holdoff_end; + volatile u8 control; + volatile u8 status; + volatile u8 cursor_start; + volatile u8 cursor_end; + volatile u8 h_blank_start; + volatile u8 h_blank_end; + volatile u8 h_sync_start; + volatile u8 h_sync_end; + volatile u8 comp_sync_end; + volatile u8 v_blank_start_high; + volatile u8 v_blank_start_low; + volatile u8 v_blank_end; + volatile u8 v_sync_start; + volatile u8 v_sync_end; + volatile u8 xfer_holdoff_start; + volatile u8 xfer_holdoff_end; }; /* Status Register Constants */ @@ -114,8 +117,9 @@ struct bw2_par { #define BW2_FLAG_BLANKED 0x00000001 unsigned long physbase; - unsigned long which_io; unsigned long fbsize; + + struct sbus_dev *sdev; }; /** @@ -170,7 +174,9 @@ static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(bw2_mmap_map, par->physbase, par->fbsize, - par->which_io, + (par->sdev ? + par->sdev->reg_addrs[0].which_io : + 0), vma); } @@ -282,124 +288,139 @@ static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info, struct all_info { struct fb_info info; struct bw2_par par; + struct list_head list; }; +static LIST_HEAD(bw2_list); -static int __devinit bw2_init_one(struct of_device *op) +static void bw2_init_one(struct sbus_dev *sdev) { - struct device_node *dp = op->node; struct all_info *all; - int linebytes, err; - - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; - - spin_lock_init(&all->par.lock); + struct resource *resp; +#ifdef CONFIG_SUN4 + struct resource res; +#endif + int linebytes; - all->par.physbase = op->resource[0].start; - all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "bw2: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); - sbusfb_fill_var(&all->info.var, dp->node, 1); - linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); + INIT_LIST_HEAD(&all->list); + spin_lock_init(&all->par.lock); + all->par.sdev = sdev; + +#ifdef CONFIG_SUN4 + if (!sdev) { + all->par.physbase = sun4_bwtwo_physaddr; + res.start = sun4_bwtwo_physaddr; + res.end = res.start + BWTWO_REGISTER_OFFSET + sizeof(struct bw2_regs) - 1; + res.flags = IORESOURCE_IO; + resp = &res; + all->info.var.xres = all->info.var.xres_virtual = 1152; + all->info.var.yres = all->info.var.yres_virtual = 900; + all->info.var.bits_per_pixel = 1; + linebytes = 1152 / 8; + } else +#else + { + BUG_ON(!sdev); + all->par.physbase = sdev->reg_addrs[0].phys_addr; + resp = &sdev->resource[0]; + sbusfb_fill_var(&all->info.var, (sdev ? sdev->prom_node : 0), 1); + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); + } +#endif all->info.var.red.length = all->info.var.green.length = all->info.var.blue.length = all->info.var.bits_per_pixel; all->info.var.red.offset = all->info.var.green.offset = all->info.var.blue.offset = 0; - all->par.regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET, - sizeof(struct bw2_regs), "bw2 regs"); + all->par.regs = sbus_ioremap(resp, BWTWO_REGISTER_OFFSET, + sizeof(struct bw2_regs), "bw2 regs"); - if (!of_find_property(dp, "width", NULL)) + if (sdev && !prom_getbool(sdev->prom_node, "width")) bw2_do_default_mode(&all->par, &all->info, &linebytes); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); all->info.flags = FBINFO_DEFAULT; all->info.fbops = &bw2_ops; - - all->info.screen_base = - sbus_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram"); +#if defined(CONFIG_SPARC32) + if (sdev) + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = + sbus_ioremap(resp, 0, all->par.fbsize, "bw2 ram"); all->info.par = &all->par; bw2_blank(0, &all->info); bw2_init_fix(&all->info, linebytes); - err= register_framebuffer(&all->info); - if (err < 0) { - of_iounmap(all->par.regs, sizeof(struct bw2_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "bw2: Could not register framebuffer.\n"); kfree(all); - return err; + return; } - dev_set_drvdata(&op->dev, all); - - printk("%s: bwtwo at %lx:%lx\n", - dp->full_name, - all->par.which_io, all->par.physbase); - - return 0; -} - -static int __devinit bw2_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); + list_add(&all->list, &bw2_list); - return bw2_init_one(op); + printk("bw2: bwtwo at %lx:%lx\n", + (long) (sdev ? sdev->reg_addrs[0].which_io : 0), + (long) all->par.physbase); } -static int __devexit bw2_remove(struct of_device *dev) +int __init bw2_init(void) { - struct all_info *all = dev_get_drvdata(&dev->dev); + struct sbus_bus *sbus; + struct sbus_dev *sdev; - unregister_framebuffer(&all->info); - - of_iounmap(all->par.regs, sizeof(struct bw2_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); - - kfree(all); + if (fb_get_options("bw2fb", NULL)) + return -ENODEV; - dev_set_drvdata(&dev->dev, NULL); +#ifdef CONFIG_SUN4 + bw2_init_one(NULL); +#endif + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "bwtwo")) + bw2_init_one(sdev); + } return 0; } -static struct of_device_id bw2_match[] = { - { - .name = "bwtwo", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, bw2_match); - -static struct of_platform_driver bw2_driver = { - .name = "bw2", - .match_table = bw2_match, - .probe = bw2_probe, - .remove = __devexit_p(bw2_remove), -}; - -static int __init bw2_init(void) +void __exit bw2_exit(void) { - if (fb_get_options("bw2fb", NULL)) - return -ENODEV; + struct list_head *pos, *tmp; - return of_register_driver(&bw2_driver, &of_bus_type); + list_for_each_safe(pos, tmp, &bw2_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + kfree(all); + } } -static void __exit bw2_exit(void) +int __init +bw2_setup(char *arg) { - return of_unregister_driver(&bw2_driver); + /* No cmdline options yet... */ + return 0; } - module_init(bw2_init); + +#ifdef MODULE module_exit(bw2_exit); +#endif MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets"); -MODULE_AUTHOR("David S. Miller "); -MODULE_VERSION("2.0"); +MODULE_AUTHOR("David S. Miller "); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/cg14.c b/trunk/drivers/video/cg14.c index 7f926c619b61..63b6c79c8a0a 100644 --- a/trunk/drivers/video/cg14.c +++ b/trunk/drivers/video/cg14.c @@ -1,6 +1,6 @@ /* cg14.c: CGFOURTEEN frame buffer driver * - * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * @@ -18,8 +18,8 @@ #include #include -#include -#include +#include +#include #include #include "sbuslib.h" @@ -99,73 +99,73 @@ static struct fb_ops cg14_ops = { #define CG14_MCR_PIXMODE_32 3 struct cg14_regs{ - u8 mcr; /* Master Control Reg */ - u8 ppr; /* Packed Pixel Reg */ - u8 tms[2]; /* Test Mode Status Regs */ - u8 msr; /* Master Status Reg */ - u8 fsr; /* Fault Status Reg */ - u8 rev; /* Revision & Impl */ - u8 ccr; /* Clock Control Reg */ - u32 tmr; /* Test Mode Read Back */ - u8 mod; /* Monitor Operation Data Reg */ - u8 acr; /* Aux Control */ + volatile u8 mcr; /* Master Control Reg */ + volatile u8 ppr; /* Packed Pixel Reg */ + volatile u8 tms[2]; /* Test Mode Status Regs */ + volatile u8 msr; /* Master Status Reg */ + volatile u8 fsr; /* Fault Status Reg */ + volatile u8 rev; /* Revision & Impl */ + volatile u8 ccr; /* Clock Control Reg */ + volatile u32 tmr; /* Test Mode Read Back */ + volatile u8 mod; /* Monitor Operation Data Reg */ + volatile u8 acr; /* Aux Control */ u8 xxx0[6]; - u16 hct; /* Hor Counter */ - u16 vct; /* Vert Counter */ - u16 hbs; /* Hor Blank Start */ - u16 hbc; /* Hor Blank Clear */ - u16 hss; /* Hor Sync Start */ - u16 hsc; /* Hor Sync Clear */ - u16 csc; /* Composite Sync Clear */ - u16 vbs; /* Vert Blank Start */ - u16 vbc; /* Vert Blank Clear */ - u16 vss; /* Vert Sync Start */ - u16 vsc; /* Vert Sync Clear */ - u16 xcs; - u16 xcc; - u16 fsa; /* Fault Status Address */ - u16 adr; /* Address Registers */ + volatile u16 hct; /* Hor Counter */ + volatile u16 vct; /* Vert Counter */ + volatile u16 hbs; /* Hor Blank Start */ + volatile u16 hbc; /* Hor Blank Clear */ + volatile u16 hss; /* Hor Sync Start */ + volatile u16 hsc; /* Hor Sync Clear */ + volatile u16 csc; /* Composite Sync Clear */ + volatile u16 vbs; /* Vert Blank Start */ + volatile u16 vbc; /* Vert Blank Clear */ + volatile u16 vss; /* Vert Sync Start */ + volatile u16 vsc; /* Vert Sync Clear */ + volatile u16 xcs; + volatile u16 xcc; + volatile u16 fsa; /* Fault Status Address */ + volatile u16 adr; /* Address Registers */ u8 xxx1[0xce]; - u8 pcg[0x100]; /* Pixel Clock Generator */ - u32 vbr; /* Frame Base Row */ - u32 vmcr; /* VBC Master Control */ - u32 vcr; /* VBC refresh */ - u32 vca; /* VBC Config */ + volatile u8 pcg[0x100]; /* Pixel Clock Generator */ + volatile u32 vbr; /* Frame Base Row */ + volatile u32 vmcr; /* VBC Master Control */ + volatile u32 vcr; /* VBC refresh */ + volatile u32 vca; /* VBC Config */ }; #define CG14_CCR_ENABLE 0x04 #define CG14_CCR_SELECT 0x02 /* HW/Full screen */ struct cg14_cursor { - u32 cpl0[32]; /* Enable plane 0 */ - u32 cpl1[32]; /* Color selection plane */ - u8 ccr; /* Cursor Control Reg */ + volatile u32 cpl0[32]; /* Enable plane 0 */ + volatile u32 cpl1[32]; /* Color selection plane */ + volatile u8 ccr; /* Cursor Control Reg */ u8 xxx0[3]; - u16 cursx; /* Cursor x,y position */ - u16 cursy; /* Cursor x,y position */ - u32 color0; - u32 color1; + volatile u16 cursx; /* Cursor x,y position */ + volatile u16 cursy; /* Cursor x,y position */ + volatile u32 color0; + volatile u32 color1; u32 xxx1[0x1bc]; - u32 cpl0i[32]; /* Enable plane 0 autoinc */ - u32 cpl1i[32]; /* Color selection autoinc */ + volatile u32 cpl0i[32]; /* Enable plane 0 autoinc */ + volatile u32 cpl1i[32]; /* Color selection autoinc */ }; struct cg14_dac { - u8 addr; /* Address Register */ + volatile u8 addr; /* Address Register */ u8 xxx0[255]; - u8 glut; /* Gamma table */ + volatile u8 glut; /* Gamma table */ u8 xxx1[255]; - u8 select; /* Register Select */ + volatile u8 select; /* Register Select */ u8 xxx2[255]; - u8 mode; /* Mode Register */ + volatile u8 mode; /* Mode Register */ }; struct cg14_xlut{ - u8 x_xlut [256]; - u8 x_xlutd [256]; + volatile u8 x_xlut [256]; + volatile u8 x_xlutd [256]; u8 xxx0[0x600]; - u8 x_xlut_inc [256]; - u8 x_xlutd_inc [256]; + volatile u8 x_xlut_inc [256]; + volatile u8 x_xlutd_inc [256]; }; /* Color look up table (clut) */ @@ -204,6 +204,7 @@ struct cg14_par { int mode; int ramsize; + struct sbus_dev *sdev; }; static void __cg14_reset(struct cg14_par *par) @@ -354,9 +355,14 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) * Initialisation */ -static void cg14_init_fix(struct fb_info *info, int linebytes, struct device_node *dp) +static void cg14_init_fix(struct fb_info *info, int linebytes) { - const char *name = dp->name; + struct cg14_par *par = (struct cg14_par *)info->par; + const char *name; + + name = "cgfourteen"; + if (par->sdev) + name = par->sdev->prom_name; strlcpy(info->fix.id, name, sizeof(info->fix.id)); @@ -450,81 +456,98 @@ static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __initdata = { struct all_info { struct fb_info info; struct cg14_par par; + struct list_head list; }; +static LIST_HEAD(cg14_list); -static void cg14_unmap_regs(struct all_info *all) -{ - if (all->par.regs) - of_iounmap(all->par.regs, sizeof(struct cg14_regs)); - if (all->par.clut) - of_iounmap(all->par.clut, sizeof(struct cg14_clut)); - if (all->par.cursor) - of_iounmap(all->par.cursor, sizeof(struct cg14_cursor)); - if (all->info.screen_base) - of_iounmap(all->info.screen_base, all->par.fbsize); -} - -static int __devinit cg14_init_one(struct of_device *op) +static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node) { - struct device_node *dp = op->node; struct all_info *all; - int is_8mb, linebytes, i, err; + unsigned long phys, rphys; + u32 bases[6]; + int is_8mb, linebytes, i; + + if (!sdev) { + if (prom_getproperty(node, "address", + (char *) &bases[0], sizeof(bases)) <= 0 + || !bases[0]) { + printk(KERN_ERR "cg14: Device is not mapped.\n"); + return; + } + if (__get_iospace(bases[0]) != __get_iospace(bases[1])) { + printk(KERN_ERR "cg14: I/O spaces don't match.\n"); + return; + } + } + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "cg14: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + INIT_LIST_HEAD(&all->list); spin_lock_init(&all->par.lock); - sbusfb_fill_var(&all->info.var, dp->node, 8); + sbusfb_fill_var(&all->info.var, node, 8); all->info.var.red.length = 8; all->info.var.green.length = 8; all->info.var.blue.length = 8; - linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); + linebytes = prom_getintdefault(node, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - if (!strcmp(dp->parent->name, "sbus") || - !strcmp(dp->parent->name, "sbi")) { - all->par.physbase = op->resource[0].start; - all->par.iospace = op->resource[0].flags & IORESOURCE_BITS; + all->par.sdev = sdev; + if (sdev) { + rphys = sdev->reg_addrs[0].phys_addr; + all->par.physbase = phys = sdev->reg_addrs[1].phys_addr; + all->par.iospace = sdev->reg_addrs[0].which_io; + + all->par.regs = sbus_ioremap(&sdev->resource[0], 0, + sizeof(struct cg14_regs), + "cg14 regs"); + all->par.clut = sbus_ioremap(&sdev->resource[0], CG14_CLUT1, + sizeof(struct cg14_clut), + "cg14 clut"); + all->par.cursor = sbus_ioremap(&sdev->resource[0], CG14_CURSORREGS, + sizeof(struct cg14_cursor), + "cg14 cursor"); + all->info.screen_base = sbus_ioremap(&sdev->resource[1], 0, + all->par.fbsize, "cg14 ram"); } else { - all->par.physbase = op->resource[1].start; - all->par.iospace = op->resource[0].flags & IORESOURCE_BITS; + rphys = __get_phys(bases[0]); + all->par.physbase = phys = __get_phys(bases[1]); + all->par.iospace = __get_iospace(bases[0]); + all->par.regs = (struct cg14_regs __iomem *)(unsigned long)bases[0]; + all->par.clut = (struct cg14_clut __iomem *)((unsigned long)bases[0] + + CG14_CLUT1); + all->par.cursor = + (struct cg14_cursor __iomem *)((unsigned long)bases[0] + + CG14_CURSORREGS); + + all->info.screen_base = (char __iomem *)(unsigned long)bases[1]; } - all->par.regs = of_ioremap(&op->resource[0], 0, - sizeof(struct cg14_regs), "cg14 regs"); - all->par.clut = of_ioremap(&op->resource[0], CG14_CLUT1, - sizeof(struct cg14_clut), "cg14 clut"); - all->par.cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS, - sizeof(struct cg14_cursor), "cg14 cursor"); + prom_getproperty(node, "reg", (char *) &bases[0], sizeof(bases)); + is_8mb = (bases[5] == 0x800000); - all->info.screen_base = of_ioremap(&op->resource[1], 0, - all->par.fbsize, "cg14 ram"); + if (sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map)) { + extern void __cg14_mmap_sized_wrongly(void); - if (!all->par.regs || !all->par.clut || !all->par.cursor || - !all->info.screen_base) - cg14_unmap_regs(all); - - is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) == - (8 * 1024 * 1024)); - - BUILD_BUG_ON(sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map)); + __cg14_mmap_sized_wrongly(); + } - memcpy(&all->par.mmap_map, &__cg14_mmap_map, - sizeof(all->par.mmap_map)); - + memcpy(&all->par.mmap_map, &__cg14_mmap_map, sizeof(all->par.mmap_map)); for (i = 0; i < CG14_MMAP_ENTRIES; i++) { struct sbus_mmap_map *map = &all->par.mmap_map[i]; if (!map->size) break; if (map->poff & 0x80000000) - map->poff = (map->poff & 0x7fffffff) + - (op->resource[0].start - - op->resource[1].start); + map->poff = (map->poff & 0x7fffffff) + rphys - phys; if (is_8mb && map->size >= 0x100000 && map->size <= 0x400000) @@ -541,87 +564,84 @@ static int __devinit cg14_init_one(struct of_device *op) __cg14_reset(&all->par); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - cg14_unmap_regs(all); + printk(KERN_ERR "cg14: Could not allocate color map.\n"); kfree(all); - return -ENOMEM; + return; } fb_set_cmap(&all->info.cmap, &all->info); - cg14_init_fix(&all->info, linebytes, dp); + cg14_init_fix(&all->info, linebytes); - err = register_framebuffer(&all->info); - if (err < 0) { + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "cg14: Could not register framebuffer.\n"); fb_dealloc_cmap(&all->info.cmap); - cg14_unmap_regs(all); kfree(all); - return err; + return; } - dev_set_drvdata(&op->dev, all); - - printk("%s: cgfourteen at %lx:%lx, %dMB\n", - dp->full_name, - all->par.iospace, all->par.physbase, - all->par.ramsize >> 20); - - return 0; -} + list_add(&all->list, &cg14_list); -static int __devinit cg14_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); + printk("cg14: cgfourteen at %lx:%lx, %dMB\n", + all->par.iospace, all->par.physbase, all->par.ramsize >> 20); - return cg14_init_one(op); } -static int __devexit cg14_remove(struct of_device *dev) +int __init cg14_init(void) { - struct all_info *all = dev_get_drvdata(&dev->dev); - - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); - - cg14_unmap_regs(all); + struct sbus_bus *sbus; + struct sbus_dev *sdev; - kfree(all); + if (fb_get_options("cg14fb", NULL)) + return -ENODEV; - dev_set_drvdata(&dev->dev, NULL); +#ifdef CONFIG_SPARC32 + { + int root, node; + + root = prom_getchild(prom_root_node); + root = prom_searchsiblings(root, "obio"); + if (root) { + node = prom_searchsiblings(prom_getchild(root), + "cgfourteen"); + if (node) + cg14_init_one(NULL, node, root); + } + } +#endif + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "cgfourteen")) + cg14_init_one(sdev, sdev->prom_node, sbus->prom_node); + } return 0; } -static struct of_device_id cg14_match[] = { - { - .name = "cgfourteen", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, cg14_match); - -static struct of_platform_driver cg14_driver = { - .name = "cg14", - .match_table = cg14_match, - .probe = cg14_probe, - .remove = __devexit_p(cg14_remove), -}; - -int __init cg14_init(void) +void __exit cg14_exit(void) { - if (fb_get_options("cg14fb", NULL)) - return -ENODEV; + struct list_head *pos, *tmp; - return of_register_driver(&cg14_driver, &of_bus_type); + list_for_each_safe(pos, tmp, &cg14_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } } -void __exit cg14_exit(void) +int __init +cg14_setup(char *arg) { - of_unregister_driver(&cg14_driver); + /* No cmdline options yet... */ + return 0; } module_init(cg14_init); + +#ifdef MODULE module_exit(cg14_exit); +#endif MODULE_DESCRIPTION("framebuffer driver for CGfourteen chipsets"); -MODULE_AUTHOR("David S. Miller "); -MODULE_VERSION("2.0"); +MODULE_AUTHOR("David S. Miller "); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/cg3.c b/trunk/drivers/video/cg3.c index 9c8c753ef454..3de6e1b5ab2f 100644 --- a/trunk/drivers/video/cg3.c +++ b/trunk/drivers/video/cg3.c @@ -1,6 +1,6 @@ /* cg3.c: CGTHREE frame buffer driver * - * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -19,9 +19,8 @@ #include #include +#include #include -#include -#include #include #include "sbuslib.h" @@ -81,30 +80,30 @@ enum cg3_type { }; struct bt_regs { - u32 addr; - u32 color_map; - u32 control; - u32 cursor; + volatile u32 addr; + volatile u32 color_map; + volatile u32 control; + volatile u32 cursor; }; struct cg3_regs { struct bt_regs cmap; - u8 control; - u8 status; - u8 cursor_start; - u8 cursor_end; - u8 h_blank_start; - u8 h_blank_end; - u8 h_sync_start; - u8 h_sync_end; - u8 comp_sync_end; - u8 v_blank_start_high; - u8 v_blank_start_low; - u8 v_blank_end; - u8 v_sync_start; - u8 v_sync_end; - u8 xfer_holdoff_start; - u8 xfer_holdoff_end; + volatile u8 control; + volatile u8 status; + volatile u8 cursor_start; + volatile u8 cursor_end; + volatile u8 h_blank_start; + volatile u8 h_blank_end; + volatile u8 h_sync_start; + volatile u8 h_sync_end; + volatile u8 comp_sync_end; + volatile u8 v_blank_start_high; + volatile u8 v_blank_start_low; + volatile u8 v_blank_end; + volatile u8 v_sync_start; + volatile u8 v_sync_end; + volatile u8 xfer_holdoff_start; + volatile u8 xfer_holdoff_end; }; /* Offset of interesting structures in the OBIO space */ @@ -121,8 +120,9 @@ struct cg3_par { #define CG3_FLAG_RDI 0x00000002 unsigned long physbase; - unsigned long which_io; unsigned long fbsize; + + struct sbus_dev *sdev; }; /** @@ -235,7 +235,7 @@ static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(cg3_mmap_map, par->physbase, par->fbsize, - par->which_io, + par->sdev->reg_addrs[0].which_io, vma); } @@ -252,9 +252,11 @@ static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) */ static void -cg3_init_fix(struct fb_info *info, int linebytes, struct device_node *dp) +cg3_init_fix(struct fb_info *info, int linebytes) { - strlcpy(info->fix.id, dp->name, sizeof(info->fix.id)); + struct cg3_par *par = (struct cg3_par *)info->par; + + strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_PSEUDOCOLOR; @@ -265,15 +267,16 @@ cg3_init_fix(struct fb_info *info, int linebytes, struct device_node *dp) } static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var, - struct device_node *dp) + struct sbus_dev *sdev) { - char *params; + char buffer[40]; char *p; int ww, hh; - params = of_get_property(dp, "params", NULL); - if (params) { - ww = simple_strtoul(params, &p, 10); + *buffer = 0; + prom_getstring(sdev->prom_node, "params", buffer, sizeof(buffer)); + if (*buffer) { + ww = simple_strtoul(buffer, &p, 10); if (ww && *p == 'x') { hh = simple_strtoul(p + 1, &p, 10); if (hh && *p == '-') { @@ -345,11 +348,11 @@ static void cg3_do_default_mode(struct cg3_par *par) sbus_writeb(p[1], regp); } for (p = cg3_dacvals; *p; p += 2) { - u8 __iomem *regp; + volatile u8 __iomem *regp; - regp = (u8 __iomem *)&par->regs->cmap.addr; + regp = (volatile u8 __iomem *)&par->regs->cmap.addr; sbus_writeb(p[0], regp); - regp = (u8 __iomem *)&par->regs->cmap.control; + regp = (volatile u8 __iomem *)&par->regs->cmap.control; sbus_writeb(p[1], regp); } } @@ -357,137 +360,129 @@ static void cg3_do_default_mode(struct cg3_par *par) struct all_info { struct fb_info info; struct cg3_par par; + struct list_head list; }; +static LIST_HEAD(cg3_list); -static int __devinit cg3_init_one(struct of_device *op) +static void cg3_init_one(struct sbus_dev *sdev) { - struct device_node *dp = op->node; struct all_info *all; - int linebytes, err; + int linebytes; + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "cg3: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + INIT_LIST_HEAD(&all->list); spin_lock_init(&all->par.lock); + all->par.sdev = sdev; - all->par.physbase = op->resource[0].start; - all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; + all->par.physbase = sdev->reg_addrs[0].phys_addr; - sbusfb_fill_var(&all->info.var, dp->node, 8); + sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); all->info.var.red.length = 8; all->info.var.green.length = 8; all->info.var.blue.length = 8; - if (!strcmp(dp->name, "cgRDI")) + if (!strcmp(sdev->prom_name, "cgRDI")) all->par.flags |= CG3_FLAG_RDI; if (all->par.flags & CG3_FLAG_RDI) - cg3_rdi_maybe_fixup_var(&all->info.var, dp); + cg3_rdi_maybe_fixup_var(&all->info.var, sdev); - linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - all->par.regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, - sizeof(struct cg3_regs), "cg3 regs"); + all->par.regs = sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET, + sizeof(struct cg3_regs), "cg3 regs"); all->info.flags = FBINFO_DEFAULT; all->info.fbops = &cg3_ops; - all->info.screen_base = - of_ioremap(&op->resource[0], CG3_RAM_OFFSET, - all->par.fbsize, "cg3 ram"); +#ifdef CONFIG_SPARC32 + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = + sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET, + all->par.fbsize, "cg3 ram"); all->info.par = &all->par; cg3_blank(0, &all->info); - if (!of_find_property(dp, "width", NULL)) + if (!prom_getbool(sdev->prom_node, "width")) cg3_do_default_mode(&all->par); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - of_iounmap(all->par.regs, sizeof(struct cg3_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); + printk(KERN_ERR "cg3: Could not allocate color map.\n"); kfree(all); - return -ENOMEM; + return; } fb_set_cmap(&all->info.cmap, &all->info); - cg3_init_fix(&all->info, linebytes, dp); + cg3_init_fix(&all->info, linebytes); - err = register_framebuffer(&all->info); - if (err < 0) { + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "cg3: Could not register framebuffer.\n"); fb_dealloc_cmap(&all->info.cmap); - of_iounmap(all->par.regs, sizeof(struct cg3_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); kfree(all); - return err; + return; } - dev_set_drvdata(&op->dev, all); - - printk("%s: cg3 at %lx:%lx\n", - dp->full_name, all->par.which_io, all->par.physbase); + list_add(&all->list, &cg3_list); - return 0; + printk("cg3: %s at %lx:%lx\n", + sdev->prom_name, + (long) sdev->reg_addrs[0].which_io, + (long) sdev->reg_addrs[0].phys_addr); } -static int __devinit cg3_probe(struct of_device *dev, const struct of_device_id *match) +int __init cg3_init(void) { - struct of_device *op = to_of_device(&dev->dev); + struct sbus_bus *sbus; + struct sbus_dev *sdev; - return cg3_init_one(op); -} - -static int __devexit cg3_remove(struct of_device *dev) -{ - struct all_info *all = dev_get_drvdata(&dev->dev); - - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); - - of_iounmap(all->par.regs, sizeof(struct cg3_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); - - kfree(all); + if (fb_get_options("cg3fb", NULL)) + return -ENODEV; - dev_set_drvdata(&dev->dev, NULL); + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "cgthree") || + !strcmp(sdev->prom_name, "cgRDI")) + cg3_init_one(sdev); + } return 0; } -static struct of_device_id cg3_match[] = { - { - .name = "cgthree", - }, - { - .name = "cgRDI", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, cg3_match); - -static struct of_platform_driver cg3_driver = { - .name = "cg3", - .match_table = cg3_match, - .probe = cg3_probe, - .remove = __devexit_p(cg3_remove), -}; - -static int __init cg3_init(void) +void __exit cg3_exit(void) { - if (fb_get_options("cg3fb", NULL)) - return -ENODEV; + struct list_head *pos, *tmp; + + list_for_each_safe(pos, tmp, &cg3_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); - return of_register_driver(&cg3_driver, &of_bus_type); + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } } -static void __exit cg3_exit(void) +int __init +cg3_setup(char *arg) { - of_unregister_driver(&cg3_driver); + /* No cmdline options yet... */ + return 0; } module_init(cg3_init); + +#ifdef MODULE module_exit(cg3_exit); +#endif MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets"); -MODULE_AUTHOR("David S. Miller "); -MODULE_VERSION("2.0"); +MODULE_AUTHOR("David S. Miller "); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/cg6.c b/trunk/drivers/video/cg6.c index 64146be2eeb0..7aab91ead681 100644 --- a/trunk/drivers/video/cg6.c +++ b/trunk/drivers/video/cg6.c @@ -1,6 +1,6 @@ /* cg6.c: CGSIX (GX, GXplus, TGX) frame buffer driver * - * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include #include #include "sbuslib.h" @@ -164,89 +164,89 @@ static struct fb_ops cg6_ops = { /* The contents are unknown */ struct cg6_tec { - int tec_matrix; - int tec_clip; - int tec_vdc; + volatile int tec_matrix; + volatile int tec_clip; + volatile int tec_vdc; }; struct cg6_thc { - u32 thc_pad0[512]; - u32 thc_hs; /* hsync timing */ - u32 thc_hsdvs; - u32 thc_hd; - u32 thc_vs; /* vsync timing */ - u32 thc_vd; - u32 thc_refresh; - u32 thc_misc; - u32 thc_pad1[56]; - u32 thc_cursxy; /* cursor x,y position (16 bits each) */ - u32 thc_cursmask[32]; /* cursor mask bits */ - u32 thc_cursbits[32]; /* what to show where mask enabled */ + uint thc_pad0[512]; + volatile uint thc_hs; /* hsync timing */ + volatile uint thc_hsdvs; + volatile uint thc_hd; + volatile uint thc_vs; /* vsync timing */ + volatile uint thc_vd; + volatile uint thc_refresh; + volatile uint thc_misc; + uint thc_pad1[56]; + volatile uint thc_cursxy; /* cursor x,y position (16 bits each) */ + volatile uint thc_cursmask[32]; /* cursor mask bits */ + volatile uint thc_cursbits[32]; /* what to show where mask enabled */ }; struct cg6_fbc { - u32 xxx0[1]; - u32 mode; - u32 clip; - u32 xxx1[1]; - u32 s; - u32 draw; - u32 blit; - u32 font; - u32 xxx2[24]; - u32 x0, y0, z0, color0; - u32 x1, y1, z1, color1; - u32 x2, y2, z2, color2; - u32 x3, y3, z3, color3; - u32 offx, offy; - u32 xxx3[2]; - u32 incx, incy; - u32 xxx4[2]; - u32 clipminx, clipminy; - u32 xxx5[2]; - u32 clipmaxx, clipmaxy; - u32 xxx6[2]; - u32 fg; - u32 bg; - u32 alu; - u32 pm; - u32 pixelm; - u32 xxx7[2]; - u32 patalign; - u32 pattern[8]; - u32 xxx8[432]; - u32 apointx, apointy, apointz; - u32 xxx9[1]; - u32 rpointx, rpointy, rpointz; - u32 xxx10[5]; - u32 pointr, pointg, pointb, pointa; - u32 alinex, aliney, alinez; - u32 xxx11[1]; - u32 rlinex, rliney, rlinez; - u32 xxx12[5]; - u32 liner, lineg, lineb, linea; - u32 atrix, atriy, atriz; - u32 xxx13[1]; - u32 rtrix, rtriy, rtriz; - u32 xxx14[5]; - u32 trir, trig, trib, tria; - u32 aquadx, aquady, aquadz; - u32 xxx15[1]; - u32 rquadx, rquady, rquadz; - u32 xxx16[5]; - u32 quadr, quadg, quadb, quada; - u32 arectx, arecty, arectz; - u32 xxx17[1]; - u32 rrectx, rrecty, rrectz; - u32 xxx18[5]; - u32 rectr, rectg, rectb, recta; + u32 xxx0[1]; + volatile u32 mode; + volatile u32 clip; + u32 xxx1[1]; + volatile u32 s; + volatile u32 draw; + volatile u32 blit; + volatile u32 font; + u32 xxx2[24]; + volatile u32 x0, y0, z0, color0; + volatile u32 x1, y1, z1, color1; + volatile u32 x2, y2, z2, color2; + volatile u32 x3, y3, z3, color3; + volatile u32 offx, offy; + u32 xxx3[2]; + volatile u32 incx, incy; + u32 xxx4[2]; + volatile u32 clipminx, clipminy; + u32 xxx5[2]; + volatile u32 clipmaxx, clipmaxy; + u32 xxx6[2]; + volatile u32 fg; + volatile u32 bg; + volatile u32 alu; + volatile u32 pm; + volatile u32 pixelm; + u32 xxx7[2]; + volatile u32 patalign; + volatile u32 pattern[8]; + u32 xxx8[432]; + volatile u32 apointx, apointy, apointz; + u32 xxx9[1]; + volatile u32 rpointx, rpointy, rpointz; + u32 xxx10[5]; + volatile u32 pointr, pointg, pointb, pointa; + volatile u32 alinex, aliney, alinez; + u32 xxx11[1]; + volatile u32 rlinex, rliney, rlinez; + u32 xxx12[5]; + volatile u32 liner, lineg, lineb, linea; + volatile u32 atrix, atriy, atriz; + u32 xxx13[1]; + volatile u32 rtrix, rtriy, rtriz; + u32 xxx14[5]; + volatile u32 trir, trig, trib, tria; + volatile u32 aquadx, aquady, aquadz; + u32 xxx15[1]; + volatile u32 rquadx, rquady, rquadz; + u32 xxx16[5]; + volatile u32 quadr, quadg, quadb, quada; + volatile u32 arectx, arecty, arectz; + u32 xxx17[1]; + volatile u32 rrectx, rrecty, rrectz; + u32 xxx18[5]; + volatile u32 rectr, rectg, rectb, recta; }; struct bt_regs { - u32 addr; - u32 color_map; - u32 control; - u32 cursor; + volatile u32 addr; + volatile u32 color_map; + volatile u32 control; + volatile u32 cursor; }; struct cg6_par { @@ -255,14 +255,15 @@ struct cg6_par { struct cg6_fbc __iomem *fbc; struct cg6_thc __iomem *thc; struct cg6_tec __iomem *tec; - u32 __iomem *fhc; + volatile u32 __iomem *fhc; u32 flags; #define CG6_FLAG_BLANKED 0x00000001 unsigned long physbase; - unsigned long which_io; unsigned long fbsize; + + struct sbus_dev *sdev; }; static int cg6_sync(struct fb_info *info) @@ -528,7 +529,8 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(cg6_mmap_map, par->physbase, par->fbsize, - par->which_io, vma); + par->sdev->reg_addrs[0].which_io, + vma); } static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) @@ -656,75 +658,62 @@ static void cg6_chip_init(struct fb_info *info) struct all_info { struct fb_info info; struct cg6_par par; + struct list_head list; }; +static LIST_HEAD(cg6_list); -static void cg6_unmap_regs(struct all_info *all) -{ - if (all->par.fbc) - of_iounmap(all->par.fbc, 4096); - if (all->par.tec) - of_iounmap(all->par.tec, sizeof(struct cg6_tec)); - if (all->par.thc) - of_iounmap(all->par.thc, sizeof(struct cg6_thc)); - if (all->par.bt) - of_iounmap(all->par.bt, sizeof(struct bt_regs)); - if (all->par.fhc) - of_iounmap(all->par.fhc, sizeof(u32)); - - if (all->info.screen_base) - of_iounmap(all->info.screen_base, all->par.fbsize); -} - -static int __devinit cg6_init_one(struct of_device *op) +static void cg6_init_one(struct sbus_dev *sdev) { - struct device_node *dp = op->node; struct all_info *all; - int linebytes, err; + int linebytes; - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "cg6: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); + + INIT_LIST_HEAD(&all->list); spin_lock_init(&all->par.lock); + all->par.sdev = sdev; - all->par.physbase = op->resource[0].start; - all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; + all->par.physbase = sdev->reg_addrs[0].phys_addr; - sbusfb_fill_var(&all->info.var, dp->node, 8); + sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); all->info.var.red.length = 8; all->info.var.green.length = 8; all->info.var.blue.length = 8; - linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - if (of_find_property(dp, "dblbuf", NULL)) + if (prom_getbool(sdev->prom_node, "dblbuf")) all->par.fbsize *= 4; - all->par.fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, - 4096, "cgsix fbc"); - all->par.tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET, - sizeof(struct cg6_tec), "cgsix tec"); - all->par.thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET, - sizeof(struct cg6_thc), "cgsix thc"); - all->par.bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET, - sizeof(struct bt_regs), "cgsix dac"); - all->par.fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET, - sizeof(u32), "cgsix fhc"); + all->par.fbc = sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET, + 4096, "cgsix fbc"); + all->par.tec = sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET, + sizeof(struct cg6_tec), "cgsix tec"); + all->par.thc = sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET, + sizeof(struct cg6_thc), "cgsix thc"); + all->par.bt = sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET, + sizeof(struct bt_regs), "cgsix dac"); + all->par.fhc = sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET, + sizeof(u32), "cgsix fhc"); all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; all->info.fbops = &cg6_ops; - - all->info.screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, - all->par.fbsize, "cgsix ram"); - if (!all->par.fbc || !all->par.tec || !all->par.thc || - !all->par.bt || !all->par.fhc || !all->info.screen_base) { - cg6_unmap_regs(all); - kfree(all); - return -ENOMEM; - } - +#ifdef CONFIG_SPARC32 + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = + sbus_ioremap(&sdev->resource[0], CG6_RAM_OFFSET, + all->par.fbsize, "cgsix ram"); all->info.par = &all->par; all->info.var.accel_flags = FB_ACCELF_TEXT; @@ -734,90 +723,72 @@ static int __devinit cg6_init_one(struct of_device *op) cg6_blank(0, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - cg6_unmap_regs(all); + printk(KERN_ERR "cg6: Could not allocate color map.\n"); kfree(all); - return -ENOMEM; + return; } fb_set_cmap(&all->info.cmap, &all->info); cg6_init_fix(&all->info, linebytes); - err = register_framebuffer(&all->info); - if (err < 0) { - cg6_unmap_regs(all); + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "cg6: Could not register framebuffer.\n"); fb_dealloc_cmap(&all->info.cmap); kfree(all); - return err; + return; } - dev_set_drvdata(&op->dev, all); + list_add(&all->list, &cg6_list); - printk("%s: CGsix [%s] at %lx:%lx\n", - dp->full_name, + printk("cg6: CGsix [%s] at %lx:%lx\n", all->info.fix.id, - all->par.which_io, all->par.physbase); - - return 0; + (long) sdev->reg_addrs[0].which_io, + (long) sdev->reg_addrs[0].phys_addr); } -static int __devinit cg6_probe(struct of_device *dev, const struct of_device_id *match) +int __init cg6_init(void) { - struct of_device *op = to_of_device(&dev->dev); - - return cg6_init_one(op); -} - -static int __devexit cg6_remove(struct of_device *dev) -{ - struct all_info *all = dev_get_drvdata(&dev->dev); - - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + struct sbus_bus *sbus; + struct sbus_dev *sdev; - cg6_unmap_regs(all); - - kfree(all); + if (fb_get_options("cg6fb", NULL)) + return -ENODEV; - dev_set_drvdata(&dev->dev, NULL); + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "cgsix") || + !strcmp(sdev->prom_name, "cgthree+")) + cg6_init_one(sdev); + } return 0; } -static struct of_device_id cg6_match[] = { - { - .name = "cgsix", - }, - { - .name = "cgthree+", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, cg6_match); - -static struct of_platform_driver cg6_driver = { - .name = "cg6", - .match_table = cg6_match, - .probe = cg6_probe, - .remove = __devexit_p(cg6_remove), -}; - -static int __init cg6_init(void) +void __exit cg6_exit(void) { - if (fb_get_options("cg6fb", NULL)) - return -ENODEV; + struct list_head *pos, *tmp; - return of_register_driver(&cg6_driver, &of_bus_type); + list_for_each_safe(pos, tmp, &cg6_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } } -static void __exit cg6_exit(void) +int __init +cg6_setup(char *arg) { - of_unregister_driver(&cg6_driver); + /* No cmdline options yet... */ + return 0; } module_init(cg6_init); + +#ifdef MODULE module_exit(cg6_exit); +#endif MODULE_DESCRIPTION("framebuffer driver for CGsix chipsets"); -MODULE_AUTHOR("David S. Miller "); -MODULE_VERSION("2.0"); +MODULE_AUTHOR("David S. Miller "); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/ffb.c b/trunk/drivers/video/ffb.c index 2a0e8210d398..7633e41adda1 100644 --- a/trunk/drivers/video/ffb.c +++ b/trunk/drivers/video/ffb.c @@ -1,6 +1,6 @@ /* ffb.c: Creator/Elite3D frame buffer driver * - * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz) * * Driver layout based loosely on tgafb.c, see that file for credits. @@ -19,8 +19,7 @@ #include #include -#include -#include +#include #include #include "sbuslib.h" @@ -185,161 +184,161 @@ static struct fb_ops ffb_ops = { struct ffb_fbc { /* Next vertex registers */ - u32 xxx1[3]; - u32 alpha; - u32 red; - u32 green; - u32 blue; - u32 depth; - u32 y; - u32 x; - u32 xxx2[2]; - u32 ryf; - u32 rxf; - u32 xxx3[2]; + u32 xxx1[3]; + volatile u32 alpha; + volatile u32 red; + volatile u32 green; + volatile u32 blue; + volatile u32 depth; + volatile u32 y; + volatile u32 x; + u32 xxx2[2]; + volatile u32 ryf; + volatile u32 rxf; + u32 xxx3[2]; - u32 dmyf; - u32 dmxf; - u32 xxx4[2]; - u32 ebyi; - u32 ebxi; - u32 xxx5[2]; - u32 by; - u32 bx; - u32 dy; - u32 dx; - u32 bh; - u32 bw; - u32 xxx6[2]; + volatile u32 dmyf; + volatile u32 dmxf; + u32 xxx4[2]; + volatile u32 ebyi; + volatile u32 ebxi; + u32 xxx5[2]; + volatile u32 by; + volatile u32 bx; + u32 dy; + u32 dx; + volatile u32 bh; + volatile u32 bw; + u32 xxx6[2]; - u32 xxx7[32]; + u32 xxx7[32]; /* Setup unit vertex state register */ - u32 suvtx; - u32 xxx8[63]; + volatile u32 suvtx; + u32 xxx8[63]; /* Control registers */ - u32 ppc; - u32 wid; - u32 fg; - u32 bg; - u32 consty; - u32 constz; - u32 xclip; - u32 dcss; - u32 vclipmin; - u32 vclipmax; - u32 vclipzmin; - u32 vclipzmax; - u32 dcsf; - u32 dcsb; - u32 dczf; - u32 dczb; + volatile u32 ppc; + volatile u32 wid; + volatile u32 fg; + volatile u32 bg; + volatile u32 consty; + volatile u32 constz; + volatile u32 xclip; + volatile u32 dcss; + volatile u32 vclipmin; + volatile u32 vclipmax; + volatile u32 vclipzmin; + volatile u32 vclipzmax; + volatile u32 dcsf; + volatile u32 dcsb; + volatile u32 dczf; + volatile u32 dczb; - u32 xxx9; - u32 blendc; - u32 blendc1; - u32 blendc2; - u32 fbramitc; - u32 fbc; - u32 rop; - u32 cmp; - u32 matchab; - u32 matchc; - u32 magnab; - u32 magnc; - u32 fbcfg0; - u32 fbcfg1; - u32 fbcfg2; - u32 fbcfg3; + u32 xxx9; + volatile u32 blendc; + volatile u32 blendc1; + volatile u32 blendc2; + volatile u32 fbramitc; + volatile u32 fbc; + volatile u32 rop; + volatile u32 cmp; + volatile u32 matchab; + volatile u32 matchc; + volatile u32 magnab; + volatile u32 magnc; + volatile u32 fbcfg0; + volatile u32 fbcfg1; + volatile u32 fbcfg2; + volatile u32 fbcfg3; - u32 ppcfg; - u32 pick; - u32 fillmode; - u32 fbramwac; - u32 pmask; - u32 xpmask; - u32 ypmask; - u32 zpmask; - u32 clip0min; - u32 clip0max; - u32 clip1min; - u32 clip1max; - u32 clip2min; - u32 clip2max; - u32 clip3min; - u32 clip3max; + u32 ppcfg; + volatile u32 pick; + volatile u32 fillmode; + volatile u32 fbramwac; + volatile u32 pmask; + volatile u32 xpmask; + volatile u32 ypmask; + volatile u32 zpmask; + volatile u32 clip0min; + volatile u32 clip0max; + volatile u32 clip1min; + volatile u32 clip1max; + volatile u32 clip2min; + volatile u32 clip2max; + volatile u32 clip3min; + volatile u32 clip3max; /* New 3dRAM III support regs */ - u32 rawblend2; - u32 rawpreblend; - u32 rawstencil; - u32 rawstencilctl; - u32 threedram1; - u32 threedram2; - u32 passin; - u32 rawclrdepth; - u32 rawpmask; - u32 rawcsrc; - u32 rawmatch; - u32 rawmagn; - u32 rawropblend; - u32 rawcmp; - u32 rawwac; - u32 fbramid; + volatile u32 rawblend2; + volatile u32 rawpreblend; + volatile u32 rawstencil; + volatile u32 rawstencilctl; + volatile u32 threedram1; + volatile u32 threedram2; + volatile u32 passin; + volatile u32 rawclrdepth; + volatile u32 rawpmask; + volatile u32 rawcsrc; + volatile u32 rawmatch; + volatile u32 rawmagn; + volatile u32 rawropblend; + volatile u32 rawcmp; + volatile u32 rawwac; + volatile u32 fbramid; - u32 drawop; - u32 xxx10[2]; - u32 fontlpat; - u32 xxx11; - u32 fontxy; - u32 fontw; - u32 fontinc; - u32 font; - u32 xxx12[3]; - u32 blend2; - u32 preblend; - u32 stencil; - u32 stencilctl; - - u32 xxx13[4]; - u32 dcss1; - u32 dcss2; - u32 dcss3; - u32 widpmask; - u32 dcs2; - u32 dcs3; - u32 dcs4; - u32 xxx14; - u32 dcd2; - u32 dcd3; - u32 dcd4; - u32 xxx15; + volatile u32 drawop; + u32 xxx10[2]; + volatile u32 fontlpat; + u32 xxx11; + volatile u32 fontxy; + volatile u32 fontw; + volatile u32 fontinc; + volatile u32 font; + u32 xxx12[3]; + volatile u32 blend2; + volatile u32 preblend; + volatile u32 stencil; + volatile u32 stencilctl; + + u32 xxx13[4]; + volatile u32 dcss1; + volatile u32 dcss2; + volatile u32 dcss3; + volatile u32 widpmask; + volatile u32 dcs2; + volatile u32 dcs3; + volatile u32 dcs4; + u32 xxx14; + volatile u32 dcd2; + volatile u32 dcd3; + volatile u32 dcd4; + u32 xxx15; - u32 pattern[32]; + volatile u32 pattern[32]; - u32 xxx16[256]; + u32 xxx16[256]; - u32 devid; - u32 xxx17[63]; + volatile u32 devid; + u32 xxx17[63]; - u32 ucsr; - u32 xxx18[31]; + volatile u32 ucsr; + u32 xxx18[31]; - u32 mer; + volatile u32 mer; }; struct ffb_dac { - u32 type; - u32 value; - u32 type2; - u32 value2; + volatile u32 type; + volatile u32 value; + volatile u32 type2; + volatile u32 value2; }; struct ffb_par { spinlock_t lock; - struct ffb_fbc __iomem *fbc; - struct ffb_dac __iomem *dac; + struct ffb_fbc *fbc; + struct ffb_dac *dac; u32 flags; #define FFB_FLAG_AFB 0x00000001 @@ -354,13 +353,16 @@ struct ffb_par { unsigned long physbase; unsigned long fbsize; + char name[64]; + int prom_node; + int prom_parent_node; int dac_rev; int board_type; }; static void FFBFifo(struct ffb_par *par, int n) { - struct ffb_fbc __iomem *fbc; + struct ffb_fbc *fbc; int cache = par->fifo_cache; if (cache - n < 0) { @@ -373,7 +375,7 @@ static void FFBFifo(struct ffb_par *par, int n) static void FFBWait(struct ffb_par *par) { - struct ffb_fbc __iomem *fbc; + struct ffb_fbc *fbc; int limit = 10000; fbc = par->fbc; @@ -406,8 +408,8 @@ static __inline__ void ffb_rop(struct ffb_par *par, u32 rop) static void ffb_switch_from_graph(struct ffb_par *par) { - struct ffb_fbc __iomem *fbc = par->fbc; - struct ffb_dac __iomem *dac = par->dac; + struct ffb_fbc *fbc = par->fbc; + struct ffb_dac *dac = par->dac; unsigned long flags; spin_lock_irqsave(&par->lock, flags); @@ -460,7 +462,7 @@ static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct ffb_par *par = (struct ffb_par *) info->par; - struct ffb_fbc __iomem *fbc = par->fbc; + struct ffb_fbc *fbc = par->fbc; unsigned long flags; u32 fg; @@ -503,7 +505,7 @@ static void ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { struct ffb_par *par = (struct ffb_par *) info->par; - struct ffb_fbc __iomem *fbc = par->fbc; + struct ffb_fbc *fbc = par->fbc; unsigned long flags; if (area->dx != area->sx || @@ -539,7 +541,7 @@ ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area) static void ffb_imageblit(struct fb_info *info, const struct fb_image *image) { struct ffb_par *par = (struct ffb_par *) info->par; - struct ffb_fbc __iomem *fbc = par->fbc; + struct ffb_fbc *fbc = par->fbc; const u8 *data = image->data; unsigned long flags; u32 fg, bg, xy; @@ -662,7 +664,7 @@ static int ffb_blank(int blank, struct fb_info *info) { struct ffb_par *par = (struct ffb_par *) info->par; - struct ffb_dac __iomem *dac = par->dac; + struct ffb_dac *dac = par->dac; unsigned long flags; u32 tmp; @@ -881,42 +883,78 @@ ffb_init_fix(struct fb_info *info) info->fix.accel = FB_ACCEL_SUN_CREATOR; } +static int ffb_apply_upa_parent_ranges(int parent, + struct linux_prom64_registers *regs) +{ + struct linux_prom64_ranges ranges[PROMREG_MAX]; + char name[128]; + int len, i; + + prom_getproperty(parent, "name", name, sizeof(name)); + if (strcmp(name, "upa") != 0) + return 0; + + len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges)); + if (len <= 0) + return 1; + + len /= sizeof(struct linux_prom64_ranges); + for (i = 0; i < len; i++) { + struct linux_prom64_ranges *rng = &ranges[i]; + u64 phys_addr = regs->phys_addr; + + if (phys_addr >= rng->ot_child_base && + phys_addr < (rng->ot_child_base + rng->or_size)) { + regs->phys_addr -= rng->ot_child_base; + regs->phys_addr += rng->ot_parent_base; + return 0; + } + } + + return 1; +} + struct all_info { struct fb_info info; struct ffb_par par; u32 pseudo_palette[256]; + struct list_head list; }; +static LIST_HEAD(ffb_list); -static int ffb_init_one(struct of_device *op) +static void ffb_init_one(int node, int parent) { - struct device_node *dp = op->node; - struct ffb_fbc __iomem *fbc; - struct ffb_dac __iomem *dac; + struct linux_prom64_registers regs[2*PROMREG_MAX]; + struct ffb_fbc *fbc; + struct ffb_dac *dac; struct all_info *all; - int err; - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + if (prom_getproperty(node, "reg", (void *) regs, sizeof(regs)) <= 0) { + printk("ffb: Cannot get reg device node property.\n"); + return; + } - spin_lock_init(&all->par.lock); - all->par.fbc = of_ioremap(&op->resource[2], 0, - sizeof(struct ffb_fbc), "ffb fbc"); - if (!all->par.fbc) { - kfree(all); - return -ENOMEM; + if (ffb_apply_upa_parent_ranges(parent, ®s[0])) { + printk("ffb: Cannot apply parent ranges to regs.\n"); + return; } - all->par.dac = of_ioremap(&op->resource[1], 0, - sizeof(struct ffb_dac), "ffb dac"); - if (!all->par.dac) { - of_iounmap(all->par.fbc, sizeof(struct ffb_fbc)); - kfree(all); - return -ENOMEM; + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "ffb: Cannot allocate memory.\n"); + return; } + memset(all, 0, sizeof(*all)); + + INIT_LIST_HEAD(&all->list); + spin_lock_init(&all->par.lock); + all->par.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF); + all->par.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF); all->par.rop_cache = FFB_ROP_NEW; - all->par.physbase = op->resource[0].start; + all->par.physbase = regs[0].phys_addr; + all->par.prom_node = node; + all->par.prom_parent_node = parent; /* Don't mention copyarea, so SCROLL_REDRAW is always * used. It is the fastest on this chip. @@ -930,7 +968,7 @@ static int ffb_init_one(struct of_device *op) all->info.par = &all->par; all->info.pseudo_palette = all->pseudo_palette; - sbusfb_fill_var(&all->info.var, dp->node, 32); + sbusfb_fill_var(&all->info.var, all->par.prom_node, 32); all->par.fbsize = PAGE_ALIGN(all->info.var.xres * all->info.var.yres * 4); @@ -938,13 +976,14 @@ static int ffb_init_one(struct of_device *op) all->info.var.accel_flags = FB_ACCELF_TEXT; - if (!strcmp(dp->name, "SUNW,afb")) + prom_getstring(node, "name", all->par.name, sizeof(all->par.name)); + if (!strcmp(all->par.name, "SUNW,afb")) all->par.flags |= FFB_FLAG_AFB; - all->par.board_type = of_getintprop_default(dp, "board_type", 0); + all->par.board_type = prom_getintdefault(node, "board_type", 0); fbc = all->par.fbc; - if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) + if((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr); ffb_switch_from_graph(&all->par); @@ -969,88 +1008,81 @@ static int ffb_init_one(struct of_device *op) if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { printk(KERN_ERR "ffb: Could not allocate color map.\n"); kfree(all); - return -ENOMEM; + return; } ffb_init_fix(&all->info); - err = register_framebuffer(&all->info); - if (err < 0) { + if (register_framebuffer(&all->info) < 0) { printk(KERN_ERR "ffb: Could not register framebuffer.\n"); fb_dealloc_cmap(&all->info.cmap); kfree(all); - return err; + return; } - dev_set_drvdata(&op->dev, all); + list_add(&all->list, &ffb_list); - printk("%s: %s at %016lx, type %d, DAC revision %d\n", - dp->full_name, + printk("ffb: %s at %016lx type %d DAC %d\n", ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), - all->par.physbase, all->par.board_type, all->par.dac_rev); - - return 0; + regs[0].phys_addr, all->par.board_type, all->par.dac_rev); } -static int __devinit ffb_probe(struct of_device *dev, const struct of_device_id *match) +static void ffb_scan_siblings(int root) { - struct of_device *op = to_of_device(&dev->dev); - - return ffb_init_one(op); + int node, child; + + child = prom_getchild(root); + for (node = prom_searchsiblings(child, "SUNW,ffb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) + ffb_init_one(node, root); + for (node = prom_searchsiblings(child, "SUNW,afb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb")) + ffb_init_one(node, root); } -static int __devexit ffb_remove(struct of_device *dev) +int __init ffb_init(void) { - struct all_info *all = dev_get_drvdata(&dev->dev); - - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + int root; - of_iounmap(all->par.fbc, sizeof(struct ffb_fbc)); - of_iounmap(all->par.dac, sizeof(struct ffb_dac)); + if (fb_get_options("ffb", NULL)) + return -ENODEV; - kfree(all); + ffb_scan_siblings(prom_root_node); - dev_set_drvdata(&dev->dev, NULL); + root = prom_getchild(prom_root_node); + for (root = prom_searchsiblings(root, "upa"); root; + root = prom_searchsiblings(prom_getsibling(root), "upa")) + ffb_scan_siblings(root); return 0; } -static struct of_device_id ffb_match[] = { - { - .name = "SUNW,ffb", - }, - { - .name = "SUNW,afb", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, ffb_match); - -static struct of_platform_driver ffb_driver = { - .name = "ffb", - .match_table = ffb_match, - .probe = ffb_probe, - .remove = __devexit_p(ffb_remove), -}; - -int __init ffb_init(void) +void __exit ffb_exit(void) { - if (fb_get_options("ffb", NULL)) - return -ENODEV; + struct list_head *pos, *tmp; + + list_for_each_safe(pos, tmp, &ffb_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); - return of_register_driver(&ffb_driver, &of_bus_type); + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } } -void __exit ffb_exit(void) +int __init +ffb_setup(char *arg) { - of_unregister_driver(&ffb_driver); + /* No cmdline options yet... */ + return 0; } module_init(ffb_init); + +#ifdef MODULE module_exit(ffb_exit); +#endif MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets"); -MODULE_AUTHOR("David S. Miller "); -MODULE_VERSION("2.0"); +MODULE_AUTHOR("David S. Miller "); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/leo.c b/trunk/drivers/video/leo.c index f3a24338d9ac..a23cfdb9d826 100644 --- a/trunk/drivers/video/leo.c +++ b/trunk/drivers/video/leo.c @@ -1,6 +1,6 @@ /* leo.c: LEO frame buffer driver * - * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz) * @@ -18,8 +18,8 @@ #include #include -#include -#include +#include +#include #include #include "sbuslib.h" @@ -80,10 +80,10 @@ static struct fb_ops leo_ops = { struct leo_cursor { u8 xxx0[16]; - u32 cur_type; - u32 cur_misc; - u32 cur_cursxy; - u32 cur_data; + volatile u32 cur_type; + volatile u32 cur_misc; + volatile u32 cur_cursxy; + volatile u32 cur_data; }; #define LEO_KRN_TYPE_CLUT0 0x00001000 @@ -99,27 +99,27 @@ struct leo_cursor { #define LEO_KRN_CSR_UNK2 0x00000001 struct leo_lx_krn { - u32 krn_type; - u32 krn_csr; - u32 krn_value; + volatile u32 krn_type; + volatile u32 krn_csr; + volatile u32 krn_value; }; struct leo_lc_ss0_krn { - u32 misc; + volatile u32 misc; u8 xxx0[0x800-4]; - u32 rev; + volatile u32 rev; }; struct leo_lc_ss0_usr { - u32 csr; - u32 addrspace; - u32 fontmsk; - u32 fontt; - u32 extent; - u32 src; + volatile u32 csr; + volatile u32 addrspace; + volatile u32 fontmsk; + volatile u32 fontt; + volatile u32 extent; + volatile u32 src; u32 dst; - u32 copy; - u32 fill; + volatile u32 copy; + volatile u32 fill; }; struct leo_lc_ss1_krn { @@ -132,47 +132,47 @@ struct leo_lc_ss1_usr { struct leo_ld { u8 xxx0[0xe00]; - u32 csr; - u32 wid; - u32 wmask; - u32 widclip; - u32 vclipmin; - u32 vclipmax; - u32 pickmin; /* SS1 only */ - u32 pickmax; /* SS1 only */ - u32 fg; - u32 bg; - u32 src; /* Copy/Scroll (SS0 only) */ - u32 dst; /* Copy/Scroll/Fill (SS0 only) */ - u32 extent; /* Copy/Scroll/Fill size (SS0 only) */ + volatile u32 csr; + volatile u32 wid; + volatile u32 wmask; + volatile u32 widclip; + volatile u32 vclipmin; + volatile u32 vclipmax; + volatile u32 pickmin; /* SS1 only */ + volatile u32 pickmax; /* SS1 only */ + volatile u32 fg; + volatile u32 bg; + volatile u32 src; /* Copy/Scroll (SS0 only) */ + volatile u32 dst; /* Copy/Scroll/Fill (SS0 only) */ + volatile u32 extent; /* Copy/Scroll/Fill size (SS0 only) */ u32 xxx1[3]; - u32 setsem; /* SS1 only */ - u32 clrsem; /* SS1 only */ - u32 clrpick; /* SS1 only */ - u32 clrdat; /* SS1 only */ - u32 alpha; /* SS1 only */ + volatile u32 setsem; /* SS1 only */ + volatile u32 clrsem; /* SS1 only */ + volatile u32 clrpick; /* SS1 only */ + volatile u32 clrdat; /* SS1 only */ + volatile u32 alpha; /* SS1 only */ u8 xxx2[0x2c]; - u32 winbg; - u32 planemask; - u32 rop; - u32 z; - u32 dczf; /* SS1 only */ - u32 dczb; /* SS1 only */ - u32 dcs; /* SS1 only */ - u32 dczs; /* SS1 only */ - u32 pickfb; /* SS1 only */ - u32 pickbb; /* SS1 only */ - u32 dcfc; /* SS1 only */ - u32 forcecol; /* SS1 only */ - u32 door[8]; /* SS1 only */ - u32 pick[5]; /* SS1 only */ + volatile u32 winbg; + volatile u32 planemask; + volatile u32 rop; + volatile u32 z; + volatile u32 dczf; /* SS1 only */ + volatile u32 dczb; /* SS1 only */ + volatile u32 dcs; /* SS1 only */ + volatile u32 dczs; /* SS1 only */ + volatile u32 pickfb; /* SS1 only */ + volatile u32 pickbb; /* SS1 only */ + volatile u32 dcfc; /* SS1 only */ + volatile u32 forcecol; /* SS1 only */ + volatile u32 door[8]; /* SS1 only */ + volatile u32 pick[5]; /* SS1 only */ }; #define LEO_SS1_MISC_ENABLE 0x00000001 #define LEO_SS1_MISC_STEREO 0x00000002 struct leo_ld_ss1 { - u8 xxx0[0xef4]; - u32 ss1_misc; + u8 xxx0[0xef4]; + volatile u32 ss1_misc; }; struct leo_ld_gbl { @@ -193,8 +193,9 @@ struct leo_par { #define LEO_FLAG_BLANKED 0x00000001 unsigned long physbase; - unsigned long which_io; unsigned long fbsize; + + struct sbus_dev *sdev; }; static void leo_wait(struct leo_lx_krn __iomem *lx_krn) @@ -367,7 +368,8 @@ static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(leo_mmap_map, par->physbase, par->fbsize, - par->which_io, vma); + par->sdev->reg_addrs[0].which_io, + vma); } static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) @@ -383,9 +385,11 @@ static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) */ static void -leo_init_fix(struct fb_info *info, struct device_node *dp) +leo_init_fix(struct fb_info *info) { - strlcpy(info->fix.id, dp->name, sizeof(info->fix.id)); + struct leo_par *par = (struct leo_par *)info->par; + + strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_TRUECOLOR; @@ -528,74 +532,60 @@ static void leo_fixup_var_rgb(struct fb_var_screeninfo *var) struct all_info { struct fb_info info; struct leo_par par; + struct list_head list; }; +static LIST_HEAD(leo_list); -static void leo_unmap_regs(struct all_info *all) -{ - if (all->par.lc_ss0_usr) - of_iounmap(all->par.lc_ss0_usr, 0x1000); - if (all->par.ld_ss0) - of_iounmap(all->par.ld_ss0, 0x1000); - if (all->par.ld_ss1) - of_iounmap(all->par.ld_ss1, 0x1000); - if (all->par.lx_krn) - of_iounmap(all->par.lx_krn, 0x1000); - if (all->par.cursor) - of_iounmap(all->par.cursor, sizeof(struct leo_cursor)); - if (all->info.screen_base) - of_iounmap(all->info.screen_base, 0x800000); -} - -static int __devinit leo_init_one(struct of_device *op) +static void leo_init_one(struct sbus_dev *sdev) { - struct device_node *dp = op->node; struct all_info *all; - int linebytes, err; + int linebytes; + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "leo: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + INIT_LIST_HEAD(&all->list); spin_lock_init(&all->par.lock); + all->par.sdev = sdev; - all->par.physbase = op->resource[0].start; - all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; + all->par.physbase = sdev->reg_addrs[0].phys_addr; - sbusfb_fill_var(&all->info.var, dp->node, 32); + sbusfb_fill_var(&all->info.var, sdev->prom_node, 32); leo_fixup_var_rgb(&all->info.var); - linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); +#ifdef CONFIG_SPARC32 + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = + sbus_ioremap(&sdev->resource[0], LEO_OFF_SS0, + 0x800000, "leo ram"); + all->par.lc_ss0_usr = - of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, - 0x1000, "leolc ss0usr"); + sbus_ioremap(&sdev->resource[0], LEO_OFF_LC_SS0_USR, + 0x1000, "leolc ss0usr"); all->par.ld_ss0 = - of_ioremap(&op->resource[0], LEO_OFF_LD_SS0, - 0x1000, "leold ss0"); + sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS0, + 0x1000, "leold ss0"); all->par.ld_ss1 = - of_ioremap(&op->resource[0], LEO_OFF_LD_SS1, - 0x1000, "leold ss1"); + sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS1, + 0x1000, "leold ss1"); all->par.lx_krn = - of_ioremap(&op->resource[0], LEO_OFF_LX_KRN, - 0x1000, "leolx krn"); + sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_KRN, + 0x1000, "leolx krn"); all->par.cursor = - of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR, - sizeof(struct leo_cursor), "leolx cursor"); - all->info.screen_base = - of_ioremap(&op->resource[0], LEO_OFF_SS0, - 0x800000, "leo ram"); - if (!all->par.lc_ss0_usr || - !all->par.ld_ss0 || - !all->par.ld_ss1 || - !all->par.lx_krn || - !all->par.cursor || - !all->info.screen_base) { - leo_unmap_regs(all); - kfree(all); - return -ENOMEM; - } + sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_CURSOR, + sizeof(struct leo_cursor), "leolx cursor"); all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; all->info.fbops = &leo_ops; @@ -607,85 +597,69 @@ static int __devinit leo_init_one(struct of_device *op) leo_blank(0, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - leo_unmap_regs(all); + printk(KERN_ERR "leo: Could not allocate color map.\n"); kfree(all); - return -ENOMEM;; + return; } - leo_init_fix(&all->info, dp); + leo_init_fix(&all->info); - err = register_framebuffer(&all->info); - if (err < 0) { + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "leo: Could not register framebuffer.\n"); fb_dealloc_cmap(&all->info.cmap); - leo_unmap_regs(all); kfree(all); - return err; + return; } - dev_set_drvdata(&op->dev, all); - - printk("%s: leo at %lx:%lx\n", - dp->full_name, - all->par.which_io, all->par.physbase); + list_add(&all->list, &leo_list); - return 0; + printk("leo: %s at %lx:%lx\n", + sdev->prom_name, + (long) sdev->reg_addrs[0].which_io, + (long) sdev->reg_addrs[0].phys_addr); } -static int __devinit leo_probe(struct of_device *dev, const struct of_device_id *match) +int __init leo_init(void) { - struct of_device *op = to_of_device(&dev->dev); - - return leo_init_one(op); -} - -static int __devexit leo_remove(struct of_device *dev) -{ - struct all_info *all = dev_get_drvdata(&dev->dev); - - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + struct sbus_bus *sbus; + struct sbus_dev *sdev; - leo_unmap_regs(all); - - kfree(all); + if (fb_get_options("leofb", NULL)) + return -ENODEV; - dev_set_drvdata(&dev->dev, NULL); + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "leo")) + leo_init_one(sdev); + } return 0; } -static struct of_device_id leo_match[] = { - { - .name = "leo", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, leo_match); - -static struct of_platform_driver leo_driver = { - .name = "leo", - .match_table = leo_match, - .probe = leo_probe, - .remove = __devexit_p(leo_remove), -}; - -static int __init leo_init(void) +void __exit leo_exit(void) { - if (fb_get_options("leofb", NULL)) - return -ENODEV; + struct list_head *pos, *tmp; - return of_register_driver(&leo_driver, &of_bus_type); + list_for_each_safe(pos, tmp, &leo_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } } -static void __exit leo_exit(void) +int __init +leo_setup(char *arg) { - of_unregister_driver(&leo_driver); + /* No cmdline options yet... */ + return 0; } module_init(leo_init); +#ifdef MODULE module_exit(leo_exit); +#endif MODULE_DESCRIPTION("framebuffer driver for LEO chipsets"); -MODULE_AUTHOR("David S. Miller "); -MODULE_VERSION("2.0"); +MODULE_AUTHOR("David S. Miller "); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/p9100.c b/trunk/drivers/video/p9100.c index 56ac51d6a7f3..0d1957505359 100644 --- a/trunk/drivers/video/p9100.c +++ b/trunk/drivers/video/p9100.c @@ -1,6 +1,6 @@ /* p9100.c: P9100 frame buffer driver * - * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) * Copyright 1999 Derrick J Brashear (shadow@dementia.org) * * Driver layout based loosely on tgafb.c, see that file for credits. @@ -17,8 +17,8 @@ #include #include -#include -#include +#include +#include #include #include "sbuslib.h" @@ -72,60 +72,60 @@ static struct fb_ops p9100_ops = { struct p9100_regs { /* Registers for the system control */ - u32 sys_base; - u32 sys_config; - u32 sys_intr; - u32 sys_int_ena; - u32 sys_alt_rd; - u32 sys_alt_wr; - u32 sys_xxx[58]; + volatile u32 sys_base; + volatile u32 sys_config; + volatile u32 sys_intr; + volatile u32 sys_int_ena; + volatile u32 sys_alt_rd; + volatile u32 sys_alt_wr; + volatile u32 sys_xxx[58]; /* Registers for the video control */ - u32 vid_base; - u32 vid_hcnt; - u32 vid_htotal; - u32 vid_hsync_rise; - u32 vid_hblank_rise; - u32 vid_hblank_fall; - u32 vid_hcnt_preload; - u32 vid_vcnt; - u32 vid_vlen; - u32 vid_vsync_rise; - u32 vid_vblank_rise; - u32 vid_vblank_fall; - u32 vid_vcnt_preload; - u32 vid_screenpaint_addr; - u32 vid_screenpaint_timectl1; - u32 vid_screenpaint_qsfcnt; - u32 vid_screenpaint_timectl2; - u32 vid_xxx[15]; + volatile u32 vid_base; + volatile u32 vid_hcnt; + volatile u32 vid_htotal; + volatile u32 vid_hsync_rise; + volatile u32 vid_hblank_rise; + volatile u32 vid_hblank_fall; + volatile u32 vid_hcnt_preload; + volatile u32 vid_vcnt; + volatile u32 vid_vlen; + volatile u32 vid_vsync_rise; + volatile u32 vid_vblank_rise; + volatile u32 vid_vblank_fall; + volatile u32 vid_vcnt_preload; + volatile u32 vid_screenpaint_addr; + volatile u32 vid_screenpaint_timectl1; + volatile u32 vid_screenpaint_qsfcnt; + volatile u32 vid_screenpaint_timectl2; + volatile u32 vid_xxx[15]; /* Registers for the video control */ - u32 vram_base; - u32 vram_memcfg; - u32 vram_refresh_pd; - u32 vram_refresh_cnt; - u32 vram_raslo_max; - u32 vram_raslo_cur; - u32 pwrup_cfg; - u32 vram_xxx[25]; + volatile u32 vram_base; + volatile u32 vram_memcfg; + volatile u32 vram_refresh_pd; + volatile u32 vram_refresh_cnt; + volatile u32 vram_raslo_max; + volatile u32 vram_raslo_cur; + volatile u32 pwrup_cfg; + volatile u32 vram_xxx[25]; /* Registers for IBM RGB528 Palette */ - u32 ramdac_cmap_wridx; - u32 ramdac_palette_data; - u32 ramdac_pixel_mask; - u32 ramdac_palette_rdaddr; - u32 ramdac_idx_lo; - u32 ramdac_idx_hi; - u32 ramdac_idx_data; - u32 ramdac_idx_ctl; - u32 ramdac_xxx[1784]; + volatile u32 ramdac_cmap_wridx; + volatile u32 ramdac_palette_data; + volatile u32 ramdac_pixel_mask; + volatile u32 ramdac_palette_rdaddr; + volatile u32 ramdac_idx_lo; + volatile u32 ramdac_idx_hi; + volatile u32 ramdac_idx_data; + volatile u32 ramdac_idx_ctl; + volatile u32 ramdac_xxx[1784]; }; struct p9100_cmd_parameng { - u32 parameng_status; - u32 parameng_bltcmd; - u32 parameng_quadcmd; + volatile u32 parameng_status; + volatile u32 parameng_bltcmd; + volatile u32 parameng_quadcmd; }; struct p9100_par { @@ -136,8 +136,9 @@ struct p9100_par { #define P9100_FLAG_BLANKED 0x00000001 unsigned long physbase; - unsigned long which_io; unsigned long fbsize; + + struct sbus_dev *sdev; }; /** @@ -226,7 +227,8 @@ static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(p9100_mmap_map, par->physbase, par->fbsize, - par->which_io, vma); + par->sdev->reg_addrs[0].which_io, + vma); } static int p9100_ioctl(struct fb_info *info, unsigned int cmd, @@ -243,9 +245,12 @@ static int p9100_ioctl(struct fb_info *info, unsigned int cmd, * Initialisation */ -static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_node *dp) +static void +p9100_init_fix(struct fb_info *info, int linebytes) { - strlcpy(info->fix.id, dp->name, sizeof(info->fix.id)); + struct p9100_par *par = (struct p9100_par *)info->par; + + strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_PSEUDOCOLOR; @@ -258,137 +263,121 @@ static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_no struct all_info { struct fb_info info; struct p9100_par par; + struct list_head list; }; +static LIST_HEAD(p9100_list); -static int __devinit p9100_init_one(struct of_device *op) +static void p9100_init_one(struct sbus_dev *sdev) { - struct device_node *dp = op->node; struct all_info *all; - int linebytes, err; + int linebytes; + + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "p9100: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + INIT_LIST_HEAD(&all->list); spin_lock_init(&all->par.lock); + all->par.sdev = sdev; /* This is the framebuffer and the only resource apps can mmap. */ - all->par.physbase = op->resource[2].start; - all->par.which_io = op->resource[2].flags & IORESOURCE_BITS; + all->par.physbase = sdev->reg_addrs[2].phys_addr; - sbusfb_fill_var(&all->info.var, dp->node, 8); + sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); all->info.var.red.length = 8; all->info.var.green.length = 8; all->info.var.blue.length = 8; - linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - all->par.regs = of_ioremap(&op->resource[0], 0, - sizeof(struct p9100_regs), "p9100 regs"); - if (!all->par.regs) { - kfree(all); - return -ENOMEM; - } + all->par.regs = sbus_ioremap(&sdev->resource[0], 0, + sizeof(struct p9100_regs), "p9100 regs"); all->info.flags = FBINFO_DEFAULT; all->info.fbops = &p9100_ops; - all->info.screen_base = of_ioremap(&op->resource[2], 0, - all->par.fbsize, "p9100 ram"); - if (!all->info.screen_base) { - of_iounmap(all->par.regs, sizeof(struct p9100_regs)); - kfree(all); - return -ENOMEM; - } +#ifdef CONFIG_SPARC32 + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = sbus_ioremap(&sdev->resource[2], 0, + all->par.fbsize, "p9100 ram"); all->info.par = &all->par; p9100_blank(0, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - of_iounmap(all->par.regs, sizeof(struct p9100_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); + printk(KERN_ERR "p9100: Could not allocate color map.\n"); kfree(all); - return -ENOMEM; + return; } - p9100_init_fix(&all->info, linebytes, dp); + p9100_init_fix(&all->info, linebytes); - err = register_framebuffer(&all->info); - if (err < 0) { + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "p9100: Could not register framebuffer.\n"); fb_dealloc_cmap(&all->info.cmap); - of_iounmap(all->par.regs, sizeof(struct p9100_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); kfree(all); - return err; + return; } fb_set_cmap(&all->info.cmap, &all->info); - dev_set_drvdata(&op->dev, all); - - printk("%s: p9100 at %lx:%lx\n", - dp->full_name, - all->par.which_io, all->par.physbase); - - return 0; -} - -static int __devinit p9100_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); + list_add(&all->list, &p9100_list); - return p9100_init_one(op); + printk("p9100: %s at %lx:%lx\n", + sdev->prom_name, + (long) sdev->reg_addrs[0].which_io, + (long) sdev->reg_addrs[0].phys_addr); } -static int __devexit p9100_remove(struct of_device *dev) +int __init p9100_init(void) { - struct all_info *all = dev_get_drvdata(&dev->dev); - - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + struct sbus_bus *sbus; + struct sbus_dev *sdev; - of_iounmap(all->par.regs, sizeof(struct p9100_regs)); - of_iounmap(all->info.screen_base, all->par.fbsize); - - kfree(all); + if (fb_get_options("p9100fb", NULL)) + return -ENODEV; - dev_set_drvdata(&dev->dev, NULL); + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "p9100")) + p9100_init_one(sdev); + } return 0; } -static struct of_device_id p9100_match[] = { - { - .name = "p9100", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, p9100_match); - -static struct of_platform_driver p9100_driver = { - .name = "p9100", - .match_table = p9100_match, - .probe = p9100_probe, - .remove = __devexit_p(p9100_remove), -}; - -static int __init p9100_init(void) +void __exit p9100_exit(void) { - if (fb_get_options("p9100fb", NULL)) - return -ENODEV; + struct list_head *pos, *tmp; + + list_for_each_safe(pos, tmp, &p9100_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); - return of_register_driver(&p9100_driver, &of_bus_type); + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } } -static void __exit p9100_exit(void) +int __init +p9100_setup(char *arg) { - of_unregister_driver(&p9100_driver); + /* No cmdline options yet... */ + return 0; } module_init(p9100_init); + +#ifdef MODULE module_exit(p9100_exit); +#endif MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets"); -MODULE_AUTHOR("David S. Miller "); -MODULE_VERSION("2.0"); +MODULE_AUTHOR("David S. Miller "); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/tcx.c b/trunk/drivers/video/tcx.c index 6990ab11cd06..95b918229d9b 100644 --- a/trunk/drivers/video/tcx.c +++ b/trunk/drivers/video/tcx.c @@ -1,6 +1,6 @@ /* tcx.c: TCX frame buffer driver * - * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include #include #include "sbuslib.h" @@ -77,32 +77,32 @@ static struct fb_ops tcx_ops = { /* The contents are unknown */ struct tcx_tec { - u32 tec_matrix; - u32 tec_clip; - u32 tec_vdc; + volatile u32 tec_matrix; + volatile u32 tec_clip; + volatile u32 tec_vdc; }; struct tcx_thc { - u32 thc_rev; + volatile u32 thc_rev; u32 thc_pad0[511]; - u32 thc_hs; /* hsync timing */ - u32 thc_hsdvs; - u32 thc_hd; - u32 thc_vs; /* vsync timing */ - u32 thc_vd; - u32 thc_refresh; - u32 thc_misc; + volatile u32 thc_hs; /* hsync timing */ + volatile u32 thc_hsdvs; + volatile u32 thc_hd; + volatile u32 thc_vs; /* vsync timing */ + volatile u32 thc_vd; + volatile u32 thc_refresh; + volatile u32 thc_misc; u32 thc_pad1[56]; - u32 thc_cursxy; /* cursor x,y position (16 bits each) */ - u32 thc_cursmask[32]; /* cursor mask bits */ - u32 thc_cursbits[32]; /* what to show where mask enabled */ + volatile u32 thc_cursxy; /* cursor x,y position (16 bits each) */ + volatile u32 thc_cursmask[32]; /* cursor mask bits */ + volatile u32 thc_cursbits[32]; /* what to show where mask enabled */ }; struct bt_regs { - u32 addr; - u32 color_map; - u32 control; - u32 cursor; + volatile u32 addr; + volatile u32 color_map; + volatile u32 control; + volatile u32 cursor; }; #define TCX_MMAP_ENTRIES 14 @@ -112,23 +112,24 @@ struct tcx_par { struct bt_regs __iomem *bt; struct tcx_thc __iomem *thc; struct tcx_tec __iomem *tec; - u32 __iomem *cplane; + volatile u32 __iomem *cplane; u32 flags; #define TCX_FLAG_BLANKED 0x00000001 unsigned long physbase; - unsigned long which_io; unsigned long fbsize; struct sbus_mmap_map mmap_map[TCX_MMAP_ENTRIES]; int lowdepth; + + struct sbus_dev *sdev; }; /* Reset control plane so that WID is 8-bit plane. */ static void __tcx_set_control_plane (struct tcx_par *par) { - u32 __iomem *p, *pend; + volatile u32 __iomem *p, *pend; if (par->lowdepth) return; @@ -306,7 +307,8 @@ static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(par->mmap_map, par->physbase, par->fbsize, - par->which_io, vma); + par->sdev->reg_addrs[0].which_io, + vma); } static int tcx_ioctl(struct fb_info *info, unsigned int cmd, @@ -348,71 +350,48 @@ tcx_init_fix(struct fb_info *info, int linebytes) struct all_info { struct fb_info info; struct tcx_par par; + struct list_head list; }; +static LIST_HEAD(tcx_list); -static void tcx_unmap_regs(struct all_info *all) -{ - if (all->par.tec) - of_iounmap(all->par.tec, sizeof(struct tcx_tec)); - if (all->par.thc) - of_iounmap(all->par.thc, sizeof(struct tcx_thc)); - if (all->par.bt) - of_iounmap(all->par.bt, sizeof(struct bt_regs)); - if (all->par.cplane) - of_iounmap(all->par.cplane, all->par.fbsize * sizeof(u32)); - if (all->info.screen_base) - of_iounmap(all->info.screen_base, all->par.fbsize); -} - -static int __devinit tcx_init_one(struct of_device *op) +static void tcx_init_one(struct sbus_dev *sdev) { - struct device_node *dp = op->node; struct all_info *all; - int linebytes, i, err; + int linebytes, i; - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "tcx: Cannot allocate memory.\n"); + return; + } + memset(all, 0, sizeof(*all)); + + INIT_LIST_HEAD(&all->list); spin_lock_init(&all->par.lock); + all->par.sdev = sdev; - all->par.lowdepth = - (of_find_property(dp, "tcx-8-bit", NULL) != NULL); + all->par.lowdepth = prom_getbool(sdev->prom_node, "tcx-8-bit"); - sbusfb_fill_var(&all->info.var, dp->node, 8); + sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); all->info.var.red.length = 8; all->info.var.green.length = 8; all->info.var.blue.length = 8; - linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); + linebytes = prom_getintdefault(sdev->prom_node, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - all->par.tec = of_ioremap(&op->resource[7], 0, - sizeof(struct tcx_tec), "tcx tec"); - all->par.thc = of_ioremap(&op->resource[9], 0, - sizeof(struct tcx_thc), "tcx thc"); - all->par.bt = of_ioremap(&op->resource[8], 0, - sizeof(struct bt_regs), "tcx dac"); - all->info.screen_base = of_ioremap(&op->resource[0], 0, - all->par.fbsize, "tcx ram"); - if (!all->par.tec || !all->par.thc || - !all->par.bt || !all->info.screen_base) { - tcx_unmap_regs(all); - kfree(all); - return -ENOMEM; - } - + all->par.tec = sbus_ioremap(&sdev->resource[7], 0, + sizeof(struct tcx_tec), "tcx tec"); + all->par.thc = sbus_ioremap(&sdev->resource[9], 0, + sizeof(struct tcx_thc), "tcx thc"); + all->par.bt = sbus_ioremap(&sdev->resource[8], 0, + sizeof(struct bt_regs), "tcx dac"); memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map)); if (!all->par.lowdepth) { - all->par.cplane = of_ioremap(&op->resource[4], 0, - all->par.fbsize * sizeof(u32), - "tcx cplane"); - if (!all->par.cplane) { - tcx_unmap_regs(all); - kfree(all); - return -ENOMEM; - } + all->par.cplane = sbus_ioremap(&sdev->resource[4], 0, + all->par.fbsize * sizeof(u32), "tcx cplane"); } else { all->par.mmap_map[1].size = SBUS_MMAP_EMPTY; all->par.mmap_map[4].size = SBUS_MMAP_EMPTY; @@ -421,8 +400,6 @@ static int __devinit tcx_init_one(struct of_device *op) } all->par.physbase = 0; - all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; - for (i = 0; i < TCX_MMAP_ENTRIES; i++) { int j; @@ -439,11 +416,18 @@ static int __devinit tcx_init_one(struct of_device *op) j = i; break; }; - all->par.mmap_map[i].poff = op->resource[j].start; + all->par.mmap_map[i].poff = sdev->reg_addrs[j].phys_addr; } all->info.flags = FBINFO_DEFAULT; all->info.fbops = &tcx_ops; +#ifdef CONFIG_SPARC32 + all->info.screen_base = (char __iomem *) + prom_getintdefault(sdev->prom_node, "address", 0); +#endif + if (!all->info.screen_base) + all->info.screen_base = sbus_ioremap(&sdev->resource[0], 0, + all->par.fbsize, "tcx ram"); all->info.par = &all->par; /* Initialize brooktree DAC. */ @@ -461,88 +445,72 @@ static int __devinit tcx_init_one(struct of_device *op) tcx_blank(FB_BLANK_UNBLANK, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - tcx_unmap_regs(all); + printk(KERN_ERR "tcx: Could not allocate color map.\n"); kfree(all); - return -ENOMEM; + return; } fb_set_cmap(&all->info.cmap, &all->info); tcx_init_fix(&all->info, linebytes); - err = register_framebuffer(&all->info); - if (err < 0) { + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "tcx: Could not register framebuffer.\n"); fb_dealloc_cmap(&all->info.cmap); - tcx_unmap_regs(all); kfree(all); - return err; + return; } - dev_set_drvdata(&op->dev, all); + list_add(&all->list, &tcx_list); - printk("%s: TCX at %lx:%lx, %s\n", - dp->full_name, - all->par.which_io, - op->resource[0].start, + printk("tcx: %s at %lx:%lx, %s\n", + sdev->prom_name, + (long) sdev->reg_addrs[0].which_io, + (long) sdev->reg_addrs[0].phys_addr, all->par.lowdepth ? "8-bit only" : "24-bit depth"); - - return 0; } -static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); - - return tcx_init_one(op); -} - -static int __devexit tcx_remove(struct of_device *dev) +int __init tcx_init(void) { - struct all_info *all = dev_get_drvdata(&dev->dev); - - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + struct sbus_bus *sbus; + struct sbus_dev *sdev; - tcx_unmap_regs(all); - - kfree(all); + if (fb_get_options("tcxfb", NULL)) + return -ENODEV; - dev_set_drvdata(&dev->dev, NULL); + for_all_sbusdev(sdev, sbus) { + if (!strcmp(sdev->prom_name, "SUNW,tcx")) + tcx_init_one(sdev); + } return 0; } -static struct of_device_id tcx_match[] = { - { - .name = "SUNW,tcx", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, tcx_match); - -static struct of_platform_driver tcx_driver = { - .name = "tcx", - .match_table = tcx_match, - .probe = tcx_probe, - .remove = __devexit_p(tcx_remove), -}; - -int __init tcx_init(void) +void __exit tcx_exit(void) { - if (fb_get_options("tcxfb", NULL)) - return -ENODEV; + struct list_head *pos, *tmp; - return of_register_driver(&tcx_driver, &of_bus_type); + list_for_each_safe(pos, tmp, &tcx_list) { + struct all_info *all = list_entry(pos, typeof(*all), list); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + kfree(all); + } } -void __exit tcx_exit(void) +int __init +tcx_setup(char *arg) { - of_unregister_driver(&tcx_driver); + /* No cmdline options yet... */ + return 0; } module_init(tcx_init); + +#ifdef MODULE module_exit(tcx_exit); +#endif MODULE_DESCRIPTION("framebuffer driver for TCX chipsets"); -MODULE_AUTHOR("David S. Miller "); -MODULE_VERSION("2.0"); +MODULE_AUTHOR("David S. Miller "); MODULE_LICENSE("GPL"); diff --git a/trunk/include/asm-sparc/of_device.h b/trunk/include/asm-sparc/of_device.h index 80ea31f6e17f..4816d102f918 100644 --- a/trunk/include/asm-sparc/of_device.h +++ b/trunk/include/asm-sparc/of_device.h @@ -4,12 +4,10 @@ #include #include -#include #include extern struct bus_type ebus_bus_type; extern struct bus_type sbus_bus_type; -extern struct bus_type of_bus_type; /* * The of_device is a kind of "base class" that is a superset of @@ -18,25 +16,11 @@ extern struct bus_type of_bus_type; */ struct of_device { - struct device_node *node; - struct device dev; - struct resource resource[PROMREG_MAX]; - unsigned int irqs[PROMINTR_MAX]; - int num_irqs; - - void *sysdata; - - int slot; - int portid; - int clock_freq; + struct device_node *node; /* OF device node */ + struct device dev; /* Generic device interface */ }; #define to_of_device(d) container_of(d, struct of_device, dev) -extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); -extern void of_iounmap(void __iomem *base, unsigned long size); - -extern struct of_device *of_find_device_by_node(struct device_node *); - extern const struct of_device_id *of_match_device( const struct of_device_id *matches, const struct of_device *dev); diff --git a/trunk/include/asm-sparc/prom.h b/trunk/include/asm-sparc/prom.h index 86c13dccea3d..f9cf44c07164 100644 --- a/trunk/include/asm-sparc/prom.h +++ b/trunk/include/asm-sparc/prom.h @@ -25,6 +25,11 @@ typedef u32 phandle; typedef u32 ihandle; +struct interrupt_info { + int line; + int sense; /* +ve/-ve logic, edge or level, etc. */ +}; + struct property { char *name; int length; @@ -38,6 +43,9 @@ struct device_node { char *name; char *type; phandle node; + phandle linux_phandle; + int n_intrs; + struct interrupt_info *intrs; char *path_component_name; char *full_name; @@ -61,8 +69,6 @@ struct device_node { #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) -#define OF_BAD_ADDR ((u64)-1) - static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) { dn->pde = de; @@ -95,8 +101,6 @@ extern int of_set_property(struct device_node *node, const char *name, void *val extern int of_getintprop_default(struct device_node *np, const char *name, int def); -extern int of_n_addr_cells(struct device_node *np); -extern int of_n_size_cells(struct device_node *np); extern void prom_build_devicetree(void); diff --git a/trunk/include/asm-sparc64/of_device.h b/trunk/include/asm-sparc64/of_device.h index a62c7b997d66..024088ef9d27 100644 --- a/trunk/include/asm-sparc64/of_device.h +++ b/trunk/include/asm-sparc64/of_device.h @@ -4,13 +4,11 @@ #include #include -#include #include extern struct bus_type isa_bus_type; extern struct bus_type ebus_bus_type; extern struct bus_type sbus_bus_type; -extern struct bus_type of_bus_type; /* * The of_device is a kind of "base class" that is a superset of @@ -19,25 +17,11 @@ extern struct bus_type of_bus_type; */ struct of_device { - struct device_node *node; - struct device dev; - struct resource resource[PROMREG_MAX]; - unsigned int irqs[PROMINTR_MAX]; - int num_irqs; - - void *sysdata; - - int slot; - int portid; - int clock_freq; + struct device_node *node; /* OF device node */ + struct device dev; /* Generic device interface */ }; #define to_of_device(d) container_of(d, struct of_device, dev) -extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); -extern void of_iounmap(void __iomem *base, unsigned long size); - -extern struct of_device *of_find_device_by_node(struct device_node *); - extern const struct of_device_id *of_match_device( const struct of_device_id *matches, const struct of_device *dev); diff --git a/trunk/include/asm-sparc64/pbm.h b/trunk/include/asm-sparc64/pbm.h index dcfa7629358c..cebe80b1da6c 100644 --- a/trunk/include/asm-sparc64/pbm.h +++ b/trunk/include/asm-sparc64/pbm.h @@ -16,7 +16,6 @@ #include #include #include -#include #include /* The abstraction used here is that there are PCI controllers, @@ -210,6 +209,7 @@ struct pci_controller_info { /* Operations which are controller specific. */ void (*scan_bus)(struct pci_controller_info *); + unsigned int (*irq_build)(struct pci_pbm_info *, struct pci_dev *, unsigned int); void (*base_address_update)(struct pci_dev *, int); void (*resource_adjust)(struct pci_dev *, struct resource *, struct resource *); @@ -217,6 +217,8 @@ struct pci_controller_info { struct pci_ops *pci_ops; unsigned int pci_first_busno; unsigned int pci_last_busno; + + void *starfire_cookie; }; /* PCI devices which are not bridges have this placed in their pci_dev @@ -226,7 +228,6 @@ struct pci_controller_info { struct pcidev_cookie { struct pci_pbm_info *pbm; struct device_node *prom_node; - struct of_device *op; struct linux_prom_pci_registers prom_regs[PROMREG_MAX]; int num_prom_regs; struct linux_prom_pci_registers prom_assignments[PROMREG_MAX]; diff --git a/trunk/include/asm-sparc64/prom.h b/trunk/include/asm-sparc64/prom.h index 99671ed6625d..265614d497c4 100644 --- a/trunk/include/asm-sparc64/prom.h +++ b/trunk/include/asm-sparc64/prom.h @@ -25,6 +25,11 @@ typedef u32 phandle; typedef u32 ihandle; +struct interrupt_info { + int line; + int sense; /* +ve/-ve logic, edge or level, etc. */ +}; + struct property { char *name; int length; @@ -34,11 +39,13 @@ struct property { unsigned int unique_id; }; -struct of_irq_controller; struct device_node { char *name; char *type; phandle node; + phandle linux_phandle; + int n_intrs; + struct interrupt_info *intrs; char *path_component_name; char *full_name; @@ -54,13 +61,6 @@ struct device_node { unsigned long _flags; void *data; unsigned int unique_id; - - struct of_irq_controller *irq_trans; -}; - -struct of_irq_controller { - unsigned int (*irq_build)(struct device_node *, unsigned int, void *); - void *data; }; /* flag descriptions */ @@ -69,8 +69,6 @@ struct of_irq_controller { #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) -#define OF_BAD_ADDR ((u64)-1) - static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) { dn->pde = de; @@ -103,8 +101,6 @@ extern int of_set_property(struct device_node *node, const char *name, void *val extern int of_getintprop_default(struct device_node *np, const char *name, int def); -extern int of_n_addr_cells(struct device_node *np); -extern int of_n_size_cells(struct device_node *np); extern void prom_build_devicetree(void); diff --git a/trunk/include/asm-sparc64/sbus.h b/trunk/include/asm-sparc64/sbus.h index 7efd49d31bb8..56ee985e4605 100644 --- a/trunk/include/asm-sparc64/sbus.h +++ b/trunk/include/asm-sparc64/sbus.h @@ -80,6 +80,7 @@ struct sbus_bus { int num_sbus_ranges; int portid; + void *starfire_cookie; }; #define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev) diff --git a/trunk/include/asm-sparc64/starfire.h b/trunk/include/asm-sparc64/starfire.h index 48b50b5e35b0..b606cb2b32a8 100644 --- a/trunk/include/asm-sparc64/starfire.h +++ b/trunk/include/asm-sparc64/starfire.h @@ -14,7 +14,7 @@ extern int this_is_starfire; extern void check_if_starfire(void); extern void starfire_cpu_setup(void); extern int starfire_hard_smp_processor_id(void); -extern void starfire_hookup(int); +extern void *starfire_hookup(int); extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid); #endif diff --git a/trunk/net/ipv4/netfilter/arp_tables.c b/trunk/net/ipv4/netfilter/arp_tables.c index d0d19192026d..ad39bf640567 100644 --- a/trunk/net/ipv4/netfilter/arp_tables.c +++ b/trunk/net/ipv4/netfilter/arp_tables.c @@ -1120,7 +1120,8 @@ int arpt_register_table(struct arpt_table *table, return ret; } - if (xt_register_table(table, &bootstrap, newinfo) != 0) { + ret = xt_register_table(table, &bootstrap, newinfo); + if (ret != 0) { xt_free_table_info(newinfo); return ret; } diff --git a/trunk/net/ipv4/netfilter/ip_tables.c b/trunk/net/ipv4/netfilter/ip_tables.c index 706c0025ec5e..7aaaf92efb59 100644 --- a/trunk/net/ipv4/netfilter/ip_tables.c +++ b/trunk/net/ipv4/netfilter/ip_tables.c @@ -2113,7 +2113,8 @@ int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl) return ret; } - if (xt_register_table(table, &bootstrap, newinfo) != 0) { + ret = xt_register_table(table, &bootstrap, newinfo); + if (ret != 0) { xt_free_table_info(newinfo); return ret; } diff --git a/trunk/net/ipv6/netfilter/ip6_tables.c b/trunk/net/ipv6/netfilter/ip6_tables.c index 2e72f89a7019..0b5bd5587a3e 100644 --- a/trunk/net/ipv6/netfilter/ip6_tables.c +++ b/trunk/net/ipv6/netfilter/ip6_tables.c @@ -1281,7 +1281,8 @@ int ip6t_register_table(struct xt_table *table, return ret; } - if (xt_register_table(table, &bootstrap, newinfo) != 0) { + ret = xt_register_table(table, &bootstrap, newinfo); + if (ret != 0) { xt_free_table_info(newinfo); return ret; }