From 2dd3c0016090543e12aa0c5aee574ded6a88b886 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sun, 4 Nov 2007 15:44:15 -0600 Subject: [PATCH 1/5] [POWERPC] pasemi: clean up mdio_gpio a bit Misc cleanups of mdio_gpio: * Better error handling/unrolling in case of init/alloc failures * Go through child nodes and get their interrupts instead of using hardcoded values * Remap the GPIO registers at module load/driver init instead of during probe * Coding style and other misc cleanups Signed-off-by: Olof Johansson --- arch/powerpc/platforms/pasemi/gpio_mdio.c | 88 +++++++++++++---------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index dae9f658122e..95d0c78cf634 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -218,45 +218,27 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) { struct device *dev = &ofdev->dev; - struct device_node *np = ofdev->node; - struct device_node *gpio_np; + struct device_node *phy_dn, *np = ofdev->node; struct mii_bus *new_bus; - struct resource res; struct gpio_priv *priv; const unsigned int *prop; - int err = 0; + int err; int i; - gpio_np = of_find_compatible_node(NULL, "gpio", "1682m-gpio"); - - if (!gpio_np) - return -ENODEV; - - err = of_address_to_resource(gpio_np, 0, &res); - of_node_put(gpio_np); - - if (err) - return -EINVAL; - - if (!gpio_regs) - gpio_regs = ioremap(res.start, 0x100); - - if (!gpio_regs) - return -EPERM; - + err = -ENOMEM; priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; + if (!priv) + goto out; new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); - if (new_bus == NULL) - return -ENOMEM; + if (!new_bus) + goto out_free_priv; - new_bus->name = "pasemi gpio mdio bus", - new_bus->read = &gpio_mdio_read, - new_bus->write = &gpio_mdio_write, - new_bus->reset = &gpio_mdio_reset, + new_bus->name = "pasemi gpio mdio bus"; + new_bus->read = &gpio_mdio_read; + new_bus->write = &gpio_mdio_write; + new_bus->reset = &gpio_mdio_reset; prop = of_get_property(np, "reg", NULL); new_bus->id = *prop; @@ -265,9 +247,24 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, new_bus->phy_mask = 0; new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); - for(i = 0; i < PHY_MAX_ADDR; ++i) - new_bus->irq[i] = irq_create_mapping(NULL, 10); + if (!new_bus->irq) + goto out_free_bus; + + for (i = 0; i < PHY_MAX_ADDR; i++) + new_bus->irq[i] = NO_IRQ; + + for (phy_dn = of_get_next_child(np, NULL); + phy_dn != NULL; + phy_dn = of_get_next_child(np, phy_dn)) { + const unsigned int *ip, *regp; + + ip = of_get_property(phy_dn, "interrupts", NULL); + regp = of_get_property(phy_dn, "reg", NULL); + if (!ip || !regp || *regp >= PHY_MAX_ADDR) + continue; + new_bus->irq[*regp] = irq_create_mapping(NULL, *ip); + } prop = of_get_property(np, "mdc-pin", NULL); priv->mdc_pin = *prop; @@ -280,17 +277,21 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, err = mdiobus_register(new_bus); - if (0 != err) { + if (err != 0) { printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n", new_bus->name, err); - goto bus_register_fail; + goto out_free_irq; } return 0; -bus_register_fail: +out_free_irq: + kfree(new_bus->irq); +out_free_bus: kfree(new_bus); - +out_free_priv: + kfree(priv); +out: return err; } @@ -330,12 +331,25 @@ static struct of_platform_driver gpio_mdio_driver = int gpio_mdio_init(void) { + struct device_node *np; + + np = of_find_compatible_node(NULL, "gpio", "1682m-gpio"); + if (!np) + return -ENODEV; + gpio_regs = of_iomap(np, 0); + of_node_put(np); + + if (!gpio_regs) + return -ENODEV; + return of_register_platform_driver(&gpio_mdio_driver); } +module_init(gpio_mdio_init); void gpio_mdio_exit(void) { of_unregister_platform_driver(&gpio_mdio_driver); + if (gpio_regs) + iounmap(gpio_regs); } -device_initcall(gpio_mdio_init); - +module_exit(gpio_mdio_exit); From 0d08a84770cb03aea24268e515342d44df8ea588 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sun, 4 Nov 2007 20:57:45 -0600 Subject: [PATCH 2/5] [POWERPC] pasemi: Broaden specific references to 1682M There will be more product numbers in the future than just PA6T-1682M, but they will share much of the features. Remove some of the explicit references and compatibility checks with 1682M, and replace most of them with the more generic term "PWRficient". Signed-off-by: Olof Johansson Acked-by: Michael Buesch Acked-by: Doug Thompson --- arch/powerpc/platforms/pasemi/Kconfig | 2 +- arch/powerpc/platforms/pasemi/cpufreq.c | 13 ++++++++++--- arch/powerpc/platforms/pasemi/gpio_mdio.c | 5 ++++- arch/powerpc/platforms/pasemi/setup.c | 9 +++++++-- drivers/char/hw_random/Kconfig | 2 +- drivers/char/hw_random/pasemi-rng.c | 7 +++---- drivers/edac/pasemi_edac.c | 4 ++-- 7 files changed, 28 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig index 735e1536cbfc..2f4dd6e4aac1 100644 --- a/arch/powerpc/platforms/pasemi/Kconfig +++ b/arch/powerpc/platforms/pasemi/Kconfig @@ -17,7 +17,7 @@ config PPC_PASEMI_IOMMU bool "PA Semi IOMMU support" depends on PPC_PASEMI help - IOMMU support for PA6T-1682M + IOMMU support for PA Semi PWRficient config PPC_PASEMI_IOMMU_DMA_FORCE bool "Force DMA engine to use IOMMU" diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c index 1cfb8b0c8fec..8caa1667cf34 100644 --- a/arch/powerpc/platforms/pasemi/cpufreq.c +++ b/arch/powerpc/platforms/pasemi/cpufreq.c @@ -147,7 +147,10 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) if (!cpu) goto out; - dn = of_find_compatible_node(NULL, "sdc", "1682m-sdc"); + dn = of_find_compatible_node(NULL, NULL, "1682m-sdc"); + if (!dn) + dn = of_find_compatible_node(NULL, NULL, + "pasemi,pwrficient-sdc"); if (!dn) goto out; err = of_address_to_resource(dn, 0, &res); @@ -160,7 +163,10 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) goto out; } - dn = of_find_compatible_node(NULL, "gizmo", "1682m-gizmo"); + dn = of_find_compatible_node(NULL, NULL, "1682m-gizmo"); + if (!dn) + dn = of_find_compatible_node(NULL, NULL, + "pasemi,pwrficient-gizmo"); if (!dn) { err = -ENODEV; goto out_unmap_sdcasr; @@ -292,7 +298,8 @@ static struct cpufreq_driver pas_cpufreq_driver = { static int __init pas_cpufreq_init(void) { - if (!machine_is_compatible("PA6T-1682M")) + if (!machine_is_compatible("PA6T-1682M") && + !machine_is_compatible("pasemi,pwrficient")) return -ENODEV; return cpufreq_register_driver(&pas_cpufreq_driver); diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index 95d0c78cf634..b0298045df7e 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -333,7 +333,10 @@ int gpio_mdio_init(void) { struct device_node *np; - np = of_find_compatible_node(NULL, "gpio", "1682m-gpio"); + np = of_find_compatible_node(NULL, NULL, "1682m-gpio"); + if (!np) + np = of_find_compatible_node(NULL, NULL, + "pasemi,pwrficient-gpio"); if (!np) return -ENODEV; gpio_regs = of_iomap(np, 0); diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index 3d62060498b4..bd85853bc9da 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -362,8 +362,12 @@ static inline void pasemi_pcmcia_init(void) static struct of_device_id pasemi_bus_ids[] = { + /* Unfortunately needed for legacy firmwares */ { .type = "localbus", }, { .type = "sdc", }, + /* These are the proper entries, which newer firmware uses */ + { .compatible = "pasemi,localbus", }, + { .compatible = "pasemi,sdc", }, {}, }; @@ -389,7 +393,8 @@ static int __init pas_probe(void) { unsigned long root = of_get_flat_dt_root(); - if (!of_flat_dt_is_compatible(root, "PA6T-1682M")) + if (!of_flat_dt_is_compatible(root, "PA6T-1682M") && + !of_flat_dt_is_compatible(root, "pasemi,pwrficient")) return 0; hpte_init_native(); @@ -400,7 +405,7 @@ static int __init pas_probe(void) } define_machine(pasemi) { - .name = "PA Semi PA6T-1682M", + .name = "PA Semi PWRficient", .probe = pas_probe, .setup_arch = pas_setup_arch, .init_early = pas_init_early, diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 2d7cd486e025..6bbd4fa50f3b 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -98,7 +98,7 @@ config HW_RANDOM_PASEMI default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number - Generator hardware found on PA6T-1682M processor. + Generator hardware found on PA Semi PWRficient SoCs. To compile this driver as a module, choose M here: the module will be called pasemi-rng. diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index fa6040b6c8f2..24ae3073991f 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -126,10 +126,9 @@ static int __devexit rng_remove(struct of_device *dev) } static struct of_device_id rng_match[] = { - { - .compatible = "1682m-rng", - }, - {}, + { .compatible = "1682m-rng", }, + { .compatible = "pasemi,pwrficient-rng", }, + { }, }; static struct of_platform_driver rng_driver = { diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c index 9007d0677220..90320917be28 100644 --- a/drivers/edac/pasemi_edac.c +++ b/drivers/edac/pasemi_edac.c @@ -225,7 +225,7 @@ static int __devinit pasemi_edac_probe(struct pci_dev *pdev, EDAC_FLAG_NONE; mci->mod_name = MODULE_NAME; mci->dev_name = pci_name(pdev); - mci->ctl_name = "pasemi,1682m-mc"; + mci->ctl_name = "pasemi,pwrficient-mc"; mci->edac_check = pasemi_edac_check; mci->ctl_page_to_phys = NULL; pci_read_config_dword(pdev, MCCFG_SCRUB, &scrub); @@ -297,4 +297,4 @@ module_exit(pasemi_edac_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Egor Martovetsky "); -MODULE_DESCRIPTION("MC support for PA Semi PA6T-1682M memory controller"); +MODULE_DESCRIPTION("MC support for PA Semi PWRficient memory controller"); From 8b32bc03256c82a6a4fcb3c2520b54469b74ec82 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 7 Nov 2007 09:26:06 -0600 Subject: [PATCH 3/5] [POWERPC] pasemi: Don't enter powersaving states from elevated astates When the PWRficient cpus are entered into powersavings states, the astate is automatically dropped down to 0. While we still restore it when we come out of idle, it can still cause some weird effects with respect to performance (especially since it takes a while to ramp up to higher astates). So, to avoid this, don't enter power savings when the cpufreq driver (or user) has set higher astates than 0. The restore is still required, since there's a chance the astate has been raised from the other cpu while the idling one was asleep. Signed-off-by: Olof Johansson --- arch/powerpc/platforms/pasemi/cpufreq.c | 6 ++++++ arch/powerpc/platforms/pasemi/pasemi.h | 6 ++++++ arch/powerpc/platforms/pasemi/powersave.S | 11 ++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c index 8caa1667cf34..58556b028a4c 100644 --- a/arch/powerpc/platforms/pasemi/cpufreq.c +++ b/arch/powerpc/platforms/pasemi/cpufreq.c @@ -32,6 +32,7 @@ #include #include #include +#include #define SDCASR_REG 0x0100 #define SDCASR_REG_STRIDE 0x1000 @@ -124,6 +125,11 @@ static void set_astate(int cpu, unsigned int astate) local_irq_restore(flags); } +int check_astate(void) +{ + return get_cur_astate(hard_smp_processor_id()); +} + void restore_astate(int cpu) { set_astate(cpu, current_astate); diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h index 516acabb4e96..c96127b029b6 100644 --- a/arch/powerpc/platforms/pasemi/pasemi.h +++ b/arch/powerpc/platforms/pasemi/pasemi.h @@ -16,8 +16,14 @@ extern void idle_doze(void); /* Restore astate to last set */ #ifdef CONFIG_PPC_PASEMI_CPUFREQ +extern int check_astate(void); extern void restore_astate(int cpu); #else +static inline int check_astate(void) +{ + /* Always return >0 so we never power save */ + return 1; +} static inline void restore_astate(int cpu) { } diff --git a/arch/powerpc/platforms/pasemi/powersave.S b/arch/powerpc/platforms/pasemi/powersave.S index 6d0fba6aab17..56f45adcd089 100644 --- a/arch/powerpc/platforms/pasemi/powersave.S +++ b/arch/powerpc/platforms/pasemi/powersave.S @@ -62,7 +62,16 @@ sleep_common: mflr r0 std r0, 16(r1) stdu r1,-64(r1) +#ifdef CONFIG_PPC_PASEMI_CPUFREQ + std r3, 48(r1) + /* Only do power savings when in astate 0 */ + bl .check_astate + cmpwi r3,0 + bne 1f + + ld r3, 48(r1) +#endif LOAD_REG_IMMEDIATE(r6,MSR_DR|MSR_IR|MSR_ME|MSR_EE) mfmsr r4 andc r5,r4,r6 @@ -73,7 +82,7 @@ sleep_common: mtmsrd r4,0 - addi r1,r1,64 +1: addi r1,r1,64 ld r0,16(r1) mtlr r0 blr From 32e2b55eec7116a859b384dbcc4b52a54a156869 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 7 Nov 2007 09:31:06 -0600 Subject: [PATCH 4/5] [POWERPC] pasemi: Move cpus to hold loop before restart Use smp_send_stop() to move all cpus besides the one executing reboot into a hold loop, to keep them from being in powersavings mode at the time of reboot. Signed-off-by: Olof Johansson --- arch/powerpc/platforms/pasemi/setup.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index bd85853bc9da..2b638659d1ea 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -43,6 +43,10 @@ #include "pasemi.h" +#if !defined(CONFIG_SMP) +static void smp_send_stop(void) {} +#endif + /* SDC reset register, must be pre-mapped at reset time */ static void __iomem *reset_reg; @@ -60,6 +64,9 @@ static int num_mce_regs; static void pas_restart(char *cmd) { + /* Need to put others cpu in hold loop so they're not sleeping */ + smp_send_stop(); + udelay(10000); printk("Restarting...\n"); while (1) out_le32(reset_reg, 0x6000000); From 5619965fecf5679ea32350905c54d087b27cc8ea Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sun, 2 Dec 2007 22:35:25 -0600 Subject: [PATCH 5/5] [POWERPC] pasemi: Fix module information for gpio-mdio Fix up the module information for gpio-mdio, it wouldn't load because of lacking license, and wouldn't auto-load because of missing MODULE_DEVICE_TABLE. Signed-off-by: Olof Johansson --- arch/powerpc/platforms/pasemi/gpio_mdio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index b0298045df7e..04a8686e6084 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -318,6 +318,7 @@ static struct of_device_id gpio_mdio_match[] = }, {}, }; +MODULE_DEVICE_TABLE(of, gpio_mdio_match); static struct of_platform_driver gpio_mdio_driver = { @@ -356,3 +357,7 @@ void gpio_mdio_exit(void) iounmap(gpio_regs); } module_exit(gpio_mdio_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Olof Johansson "); +MODULE_DESCRIPTION("Driver for MDIO over GPIO on PA Semi PWRficient-based boards");