diff options
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r-- | arch/powerpc/sysdev/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/sysdev/bestcomm/ata.c | 3 | ||||
-rw-r--r-- | arch/powerpc/sysdev/bestcomm/ata.h | 19 | ||||
-rw-r--r-- | arch/powerpc/sysdev/bestcomm/bestcomm.c | 7 | ||||
-rw-r--r-- | arch/powerpc/sysdev/bestcomm/bestcomm.h | 61 | ||||
-rw-r--r-- | arch/powerpc/sysdev/bestcomm/bestcomm_priv.h | 20 | ||||
-rw-r--r-- | arch/powerpc/sysdev/dcr-low.S | 8 | ||||
-rw-r--r-- | arch/powerpc/sysdev/dcr.c | 5 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.c | 11 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_soc.c | 241 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_soc.h | 5 | ||||
-rw-r--r-- | arch/powerpc/sysdev/grackle.c | 2 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 36 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.h | 2 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.c | 306 | ||||
-rw-r--r-- | arch/powerpc/sysdev/qe_lib/Kconfig | 3 | ||||
-rw-r--r-- | arch/powerpc/sysdev/qe_lib/gpio.c | 195 | ||||
-rw-r--r-- | arch/powerpc/sysdev/qe_lib/qe.c | 3 | ||||
-rw-r--r-- | arch/powerpc/sysdev/qe_lib/ucc.c | 4 | ||||
-rw-r--r-- | arch/powerpc/sysdev/simple_gpio.c | 155 | ||||
-rw-r--r-- | arch/powerpc/sysdev/simple_gpio.h | 12 |
21 files changed, 705 insertions, 394 deletions
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 5afce115ab1..b33b28a6fe1 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y) obj-$(CONFIG_FSL_LBC) += fsl_lbc.o obj-$(CONFIG_FSL_GTM) += fsl_gtm.o obj-$(CONFIG_MPC8xxx_GPIO) += mpc8xxx_gpio.o +obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o obj-$(CONFIG_RAPIDIO) += fsl_rio.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ diff --git a/arch/powerpc/sysdev/bestcomm/ata.c b/arch/powerpc/sysdev/bestcomm/ata.c index 1f5258fb38c..901c9f91e5d 100644 --- a/arch/powerpc/sysdev/bestcomm/ata.c +++ b/arch/powerpc/sysdev/bestcomm/ata.c @@ -61,6 +61,9 @@ bcom_ata_init(int queue_len, int maxbufsize) struct bcom_ata_var *var; struct bcom_ata_inc *inc; + /* Prefetch breaks ATA DMA. Turn it off for ATA DMA */ + bcom_disable_prefetch(); + tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0); if (!tsk) return NULL; diff --git a/arch/powerpc/sysdev/bestcomm/ata.h b/arch/powerpc/sysdev/bestcomm/ata.h index 10982769c46..0b237181133 100644 --- a/arch/powerpc/sysdev/bestcomm/ata.h +++ b/arch/powerpc/sysdev/bestcomm/ata.h @@ -16,22 +16,15 @@ struct bcom_ata_bd { u32 status; - u32 dst_pa; u32 src_pa; + u32 dst_pa; }; -extern struct bcom_task * -bcom_ata_init(int queue_len, int maxbufsize); - -extern void -bcom_ata_rx_prepare(struct bcom_task *tsk); - -extern void -bcom_ata_tx_prepare(struct bcom_task *tsk); - -extern void -bcom_ata_reset_bd(struct bcom_task *tsk); - +extern struct bcom_task * bcom_ata_init(int queue_len, int maxbufsize); +extern void bcom_ata_rx_prepare(struct bcom_task *tsk); +extern void bcom_ata_tx_prepare(struct bcom_task *tsk); +extern void bcom_ata_reset_bd(struct bcom_task *tsk); +extern void bcom_ata_release(struct bcom_task *tsk); #endif /* __BESTCOMM_ATA_H__ */ diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c index 446c9ea85b3..378ebd9aac1 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.c +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c @@ -279,7 +279,6 @@ bcom_engine_init(void) int task; phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa; unsigned int tdt_size, ctx_size, var_size, fdt_size; - u16 regval; /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */ tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt); @@ -331,10 +330,8 @@ bcom_engine_init(void) out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS); /* Disable COMM Bus Prefetch on the original 5200; it's broken */ - if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) { - regval = in_be16(&bcom_eng->regs->PtdCntrl); - out_be16(&bcom_eng->regs->PtdCntrl, regval | 1); - } + if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) + bcom_disable_prefetch(); /* Init lock */ spin_lock_init(&bcom_eng->lock); diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/sysdev/bestcomm/bestcomm.h index c960a8b4965..23a95f80dfd 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.h +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h @@ -16,8 +16,19 @@ #ifndef __BESTCOMM_H__ #define __BESTCOMM_H__ -struct bcom_bd; /* defined later on ... */ - +/** + * struct bcom_bd - Structure describing a generic BestComm buffer descriptor + * @status: The current status of this buffer. Exact meaning depends on the + * task type + * @data: An array of u32 extra data. Size of array is task dependant. + * + * Note: Don't dereference a bcom_bd pointer as an array. The size of the + * bcom_bd is variable. Use bcom_get_bd() instead. + */ +struct bcom_bd { + u32 status; + u32 data[0]; /* variable payload size */ +}; /* ======================================================================== */ /* Generic task management */ @@ -84,17 +95,6 @@ bcom_get_task_irq(struct bcom_task *tsk) { /* BD based tasks helpers */ /* ======================================================================== */ -/** - * struct bcom_bd - Structure describing a generic BestComm buffer descriptor - * @status: The current status of this buffer. Exact meaning depends on the - * task type - * @data: An array of u32 whose meaning depends on the task type. - */ -struct bcom_bd { - u32 status; - u32 data[1]; /* variable, but at least 1 */ -}; - #define BCOM_BD_READY 0x40000000ul /** _bcom_next_index - Get next input index. @@ -140,15 +140,31 @@ bcom_queue_full(struct bcom_task *tsk) } /** + * bcom_get_bd - Get a BD from the queue + * @tsk: The BestComm task structure + * index: Index of the BD to fetch + */ +static inline struct bcom_bd +*bcom_get_bd(struct bcom_task *tsk, unsigned int index) +{ + /* A cast to (void*) so the address can be incremented by the + * real size instead of by sizeof(struct bcom_bd) */ + return ((void *)tsk->bd) + (index * tsk->bd_size); +} + +/** * bcom_buffer_done - Checks if a BestComm * @tsk: The BestComm task structure */ static inline int bcom_buffer_done(struct bcom_task *tsk) { + struct bcom_bd *bd; if (bcom_queue_empty(tsk)) return 0; - return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY); + + bd = bcom_get_bd(tsk, tsk->outdex); + return !(bd->status & BCOM_BD_READY); } /** @@ -160,16 +176,21 @@ bcom_buffer_done(struct bcom_task *tsk) static inline struct bcom_bd * bcom_prepare_next_buffer(struct bcom_task *tsk) { - tsk->bd[tsk->index].status = 0; /* cleanup last status */ - return &tsk->bd[tsk->index]; + struct bcom_bd *bd; + + bd = bcom_get_bd(tsk, tsk->index); + bd->status = 0; /* cleanup last status */ + return bd; } static inline void bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie) { + struct bcom_bd *bd = bcom_get_bd(tsk, tsk->index); + tsk->cookie[tsk->index] = cookie; mb(); /* ensure the bd is really up-to-date */ - tsk->bd[tsk->index].status |= BCOM_BD_READY; + bd->status |= BCOM_BD_READY; tsk->index = _bcom_next_index(tsk); if (tsk->flags & BCOM_FLAGS_ENABLE_TASK) bcom_enable(tsk); @@ -179,10 +200,12 @@ static inline void * bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd) { void *cookie = tsk->cookie[tsk->outdex]; + struct bcom_bd *bd = bcom_get_bd(tsk, tsk->outdex); + if (p_status) - *p_status = tsk->bd[tsk->outdex].status; + *p_status = bd->status; if (p_bd) - *p_bd = &tsk->bd[tsk->outdex]; + *p_bd = bd; tsk->outdex = _bcom_next_outdex(tsk); return cookie; } diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h index 866a2915ef2..eb0d1c883c3 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h +++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h @@ -198,8 +198,8 @@ struct bcom_task_header { #define BCOM_IPR_SCTMR_1 2 #define BCOM_IPR_FEC_RX 6 #define BCOM_IPR_FEC_TX 5 -#define BCOM_IPR_ATA_RX 4 -#define BCOM_IPR_ATA_TX 3 +#define BCOM_IPR_ATA_RX 7 +#define BCOM_IPR_ATA_TX 7 #define BCOM_IPR_SCPCI_RX 2 #define BCOM_IPR_SCPCI_TX 2 #define BCOM_IPR_PSC3_RX 2 @@ -241,6 +241,22 @@ extern void bcom_set_initiator(int task, int initiator); #define TASK_ENABLE 0x8000 +/** + * bcom_disable_prefetch - Hook to disable bus prefetching + * + * ATA DMA and the original MPC5200 need this due to silicon bugs. At the + * moment disabling prefetch is a one-way street. There is no mechanism + * in place to turn prefetch back on after it has been disabled. There is + * no reason it couldn't be done, it would just be more complex to implement. + */ +static inline void bcom_disable_prefetch(void) +{ + u16 regval; + + regval = in_be16(&bcom_eng->regs->PtdCntrl); + out_be16(&bcom_eng->regs->PtdCntrl, regval | 1); +}; + static inline void bcom_enable_task(int task) { diff --git a/arch/powerpc/sysdev/dcr-low.S b/arch/powerpc/sysdev/dcr-low.S index 2078f39e2f1..d3098ef1404 100644 --- a/arch/powerpc/sysdev/dcr-low.S +++ b/arch/powerpc/sysdev/dcr-low.S @@ -11,14 +11,20 @@ #include <asm/ppc_asm.h> #include <asm/processor.h> +#include <asm/bug.h> #define DCR_ACCESS_PROLOG(table) \ + cmpli cr0,r3,1024; \ rlwinm r3,r3,4,18,27; \ lis r5,table@h; \ ori r5,r5,table@l; \ add r3,r3,r5; \ + bge- 1f; \ mtctr r3; \ - bctr + bctr; \ +1: trap; \ + EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0; \ + blr _GLOBAL(__mfdcr) DCR_ACCESS_PROLOG(__mfdcr_table) diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c index a8ba9983dd5..bb44aa9fd47 100644 --- a/arch/powerpc/sysdev/dcr.c +++ b/arch/powerpc/sysdev/dcr.c @@ -124,7 +124,8 @@ EXPORT_SYMBOL_GPL(dcr_write_generic); #endif /* defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO) */ -unsigned int dcr_resource_start(struct device_node *np, unsigned int index) +unsigned int dcr_resource_start(const struct device_node *np, + unsigned int index) { unsigned int ds; const u32 *dr = of_get_property(np, "dcr-reg", &ds); @@ -136,7 +137,7 @@ unsigned int dcr_resource_start(struct device_node *np, unsigned int index) } EXPORT_SYMBOL_GPL(dcr_resource_start); -unsigned int dcr_resource_len(struct device_node *np, unsigned int index) +unsigned int dcr_resource_len(const struct device_node *np, unsigned int index) { unsigned int ds; const u32 *dr = of_get_property(np, "dcr-reg", &ds); diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 5b264eb4b1f..f611d0369cc 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -29,7 +29,8 @@ #if defined(CONFIG_PPC_85xx) || defined(CONFIG_PPC_86xx) /* atmu setup for fsl pci/pcie controller */ -void __init setup_pci_atmu(struct pci_controller *hose, struct resource *rsrc) +static void __init setup_pci_atmu(struct pci_controller *hose, + struct resource *rsrc) { struct ccsr_pci __iomem *pci; int i; @@ -86,7 +87,7 @@ void __init setup_pci_atmu(struct pci_controller *hose, struct resource *rsrc) out_be32(&pci->piw[2].piwar, PIWAR_2G); } -void __init setup_pci_cmd(struct pci_controller *hose) +static void __init setup_pci_cmd(struct pci_controller *hose) { u16 cmd; int cap_x; @@ -130,7 +131,7 @@ static void __init quirk_fsl_pcie_header(struct pci_dev *dev) return ; } -int __init fsl_pcie_check_link(struct pci_controller *hose) +static int __init fsl_pcie_check_link(struct pci_controller *hose) { u32 val; early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val); @@ -187,7 +188,7 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; @@ -300,7 +301,7 @@ int __init mpc83xx_add_bridge(struct device_node *dev) " bus 0\n", dev->full_name); } - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 26ecb96f973..115cb16351f 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -207,236 +207,51 @@ static int __init of_add_fixed_phys(void) arch_initcall(of_add_fixed_phys); #endif /* CONFIG_FIXED_PHY */ -static int gfar_mdio_of_init_one(struct device_node *np) -{ - int k; - struct device_node *child = NULL; - struct gianfar_mdio_data mdio_data; - struct platform_device *mdio_dev; - struct resource res; - int ret; - - memset(&res, 0, sizeof(res)); - memset(&mdio_data, 0, sizeof(mdio_data)); - - ret = of_address_to_resource(np, 0, &res); - if (ret) - return ret; - - /* The gianfar device will try to use the same ID created below to find - * this bus, to coordinate register access (since they share). */ - mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", - res.start&0xfffff, &res, 1); - if (IS_ERR(mdio_dev)) - return PTR_ERR(mdio_dev); - - for (k = 0; k < 32; k++) - mdio_data.irq[k] = PHY_POLL; - - while ((child = of_get_next_child(np, child)) != NULL) { - int irq = irq_of_parse_and_map(child, 0); - if (irq != NO_IRQ) { - const u32 *id = of_get_property(child, "reg", NULL); - mdio_data.irq[*id] = irq; - } - } - - ret = platform_device_add_data(mdio_dev, &mdio_data, - sizeof(struct gianfar_mdio_data)); - if (ret) - platform_device_unregister(mdio_dev); - - return ret; -} - -static int __init gfar_mdio_of_init(void) -{ - struct device_node *np = NULL; - - for_each_compatible_node(np, NULL, "fsl,gianfar-mdio") - gfar_mdio_of_init_one(np); - - /* try the deprecated version */ - for_each_compatible_node(np, "mdio", "gianfar"); - gfar_mdio_of_init_one(np); - - return 0; -} - -arch_initcall(gfar_mdio_of_init); - -static const char *gfar_tx_intr = "tx"; -static const char *gfar_rx_intr = "rx"; -static const char *gfar_err_intr = "error"; - -static int __init gfar_of_init(void) +#ifdef CONFIG_PPC_83xx +static int __init mpc83xx_wdt_init(void) { + struct resource r; struct device_node *np; - unsigned int i; - struct platform_device *gfar_dev; - struct resource res; + struct platform_device *dev; + u32 freq = fsl_get_sys_freq(); int ret; - for (np = NULL, i = 0; - (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; - i++) { - struct resource r[4]; - struct device_node *phy, *mdio; - struct gianfar_platform_data gfar_data; - const unsigned int *id; - const char *model; - const char *ctype; - const void *mac_addr; - const phandle *ph; - int n_res = 2; - - if (!of_device_is_available(np)) - continue; - - memset(r, 0, sizeof(r)); - memset(&gfar_data, 0, sizeof(gfar_data)); - - ret = of_address_to_resource(np, 0, &r[0]); - if (ret) - goto err; - - of_irq_to_resource(np, 0, &r[1]); - - model = of_get_property(np, "model", NULL); - - /* If we aren't the FEC we have multiple interrupts */ - if (model && strcasecmp(model, "FEC")) { - r[1].name = gfar_tx_intr; - - r[2].name = gfar_rx_intr; - of_irq_to_resource(np, 1, &r[2]); + np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt"); - r[3].name = gfar_err_intr; - of_irq_to_resource(np, 2, &r[3]); - - n_res += 2; - } - - gfar_dev = - platform_device_register_simple("fsl-gianfar", i, &r[0], - n_res); - - if (IS_ERR(gfar_dev)) { - ret = PTR_ERR(gfar_dev); - goto err; - } - - mac_addr = of_get_mac_address(np); - if (mac_addr) - memcpy(gfar_data.mac_addr, mac_addr, 6); - - if (model && !strcasecmp(model, "TSEC")) - gfar_data.device_flags = - FSL_GIANFAR_DEV_HAS_GIGABIT | - FSL_GIANFAR_DEV_HAS_COALESCE | - FSL_GIANFAR_DEV_HAS_RMON | - FSL_GIANFAR_DEV_HAS_MULTI_INTR; - if (model && !strcasecmp(model, "eTSEC")) - gfar_data.device_flags = - FSL_GIANFAR_DEV_HAS_GIGABIT | - FSL_GIANFAR_DEV_HAS_COALESCE | - FSL_GIANFAR_DEV_HAS_RMON | - FSL_GIANFAR_DEV_HAS_MULTI_INTR | - FSL_GIANFAR_DEV_HAS_CSUM | - FSL_GIANFAR_DEV_HAS_VLAN | - FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; - - ctype = of_get_property(np, "phy-connection-type", NULL); - - /* We only care about rgmii-id. The rest are autodetected */ - if (ctype && !strcmp(ctype, "rgmii-id")) - gfar_data.interface = PHY_INTERFACE_MODE_RGMII_ID; - else - gfar_data.interface = PHY_INTERFACE_MODE_MII; - - if (of_get_property(np, "fsl,magic-packet", NULL)) - gfar_data.device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET; - - ph = of_get_property(np, "phy-handle", NULL); - if (ph == NULL) { - u32 *fixed_link; - - fixed_link = (u32 *)of_get_property(np, "fixed-link", - NULL); - if (!fixed_link) { - ret = -ENODEV; - goto unreg; - } - - snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "0"); - gfar_data.phy_id = fixed_link[0]; - } else { - phy = of_find_node_by_phandle(*ph); - - if (phy == NULL) { - ret = -ENODEV; - goto unreg; - } - - mdio = of_get_parent(phy); - - id = of_get_property(phy, "reg", NULL); - ret = of_address_to_resource(mdio, 0, &res); - if (ret) { - of_node_put(phy); - of_node_put(mdio); - goto unreg; - } - - gfar_data.phy_id = *id; - snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "%llx", - (unsigned long long)res.start&0xfffff); + if (!np) { + ret = -ENODEV; + goto nodev; + } - of_node_put(phy); - of_node_put(mdio); - } + memset(&r, 0, sizeof(r)); - /* Get MDIO bus controlled by this eTSEC, if any. Normally only - * eTSEC 1 will control an MDIO bus, not necessarily the same - * bus that its PHY is on ('mdio' above), so we can't just use - * that. What we do is look for a gianfar mdio device that has - * overlapping registers with this device. That's really the - * whole point, to find the device sharing our registers to - * coordinate access with it. - */ - for_each_compatible_node(mdio, NULL, "fsl,gianfar-mdio") { - if (of_address_to_resource(mdio, 0, &res)) - continue; - - if (res.start >= r[0].start && res.end <= r[0].end) { - /* Get the ID the mdio bus platform device was - * registered with. gfar_data.bus_id is - * different because it's for finding a PHY, - * while this is for finding a MII bus. - */ - gfar_data.mdio_bus = res.start&0xfffff; - of_node_put(mdio); - break; - } - } + ret = of_address_to_resource(np, 0, &r); + if (ret) + goto err; - ret = - platform_device_add_data(gfar_dev, &gfar_data, - sizeof(struct - gianfar_platform_data)); - if (ret) - goto unreg; + dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1); + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + goto err; } + ret = platform_device_add_data(dev, &freq, sizeof(freq)); + if (ret) + goto unreg; + + of_node_put(np); return 0; unreg: - platform_device_unregister(gfar_dev); + platform_device_unregister(dev); err: + of_node_put(np); +nodev: return ret; } -arch_initcall(gfar_of_init); +arch_initcall(mpc83xx_wdt_init); +#endif static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) { diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 60f7f227327..9c744e4285a 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h @@ -5,8 +5,13 @@ #include <asm/mmu.h> extern phys_addr_t get_immrbase(void); +#if defined(CONFIG_CPM2) || defined(CONFIG_QUICC_ENGINE) || defined(CONFIG_8xx) extern u32 get_brgfreq(void); extern u32 get_baudrate(void); +#else +static inline u32 get_brgfreq(void) { return -1; } +static inline u32 get_baudrate(void) { return -1; } +#endif extern u32 fsl_get_sys_freq(void); struct spi_board_info; diff --git a/arch/powerpc/sysdev/grackle.c b/arch/powerpc/sysdev/grackle.c index d502927644c..5da37c2f22e 100644 --- a/arch/powerpc/sysdev/grackle.c +++ b/arch/powerpc/sysdev/grackle.c @@ -57,7 +57,7 @@ void __init setup_grackle(struct pci_controller *hose) { setup_indirect_pci(hose, 0xfec00000, 0xfee00000, 0); if (machine_is_compatible("PowerMac1,1")) - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(hose, 1); #if 0 /* Disabled for now, HW problems ??? */ diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 1890fb085cd..3e0d89dcdba 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -661,17 +661,6 @@ static inline void mpic_eoi(struct mpic *mpic) (void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI)); } -#ifdef CONFIG_SMP -static irqreturn_t mpic_ipi_action(int irq, void *data) -{ - long ipi = (long)data; - - smp_message_recv(ipi); - - return IRQ_HANDLED; -} -#endif /* CONFIG_SMP */ - /* * Linux descriptor level callbacks */ @@ -817,7 +806,7 @@ static void mpic_end_ipi(unsigned int irq) #endif /* CONFIG_SMP */ -void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) +void mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask) { struct mpic *mpic = mpic_from_irq(irq); unsigned int src = mpic_irq_to_hw(irq); @@ -829,7 +818,7 @@ void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) } else { cpumask_t tmp; - cpus_and(tmp, cpumask, cpu_online_map); + cpumask_and(&tmp, cpumask, cpu_online_mask); mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), mpic_physmask(cpus_addr(tmp)[0])); @@ -1548,13 +1537,7 @@ unsigned int mpic_get_mcirq(void) void mpic_request_ipis(void) { struct mpic *mpic = mpic_primary; - long i, err; - static char *ipi_names[] = { - "IPI0 (call function)", - "IPI1 (reschedule)", - "IPI2 (call function single)", - "IPI3 (debugger break)", - }; + int i; BUG_ON(mpic == NULL); printk(KERN_INFO "mpic: requesting IPIs ... \n"); @@ -1563,17 +1546,10 @@ void mpic_request_ipis(void) unsigned int vipi = irq_create_mapping(mpic->irqhost, mpic->ipi_vecs[0] + i); if (vipi == NO_IRQ) { - printk(KERN_ERR "Failed to map IPI %ld\n", i); - break; - } - err = request_irq(vipi, mpic_ipi_action, - IRQF_DISABLED|IRQF_PERCPU, - ipi_names[i], (void *)i); - if (err) { - printk(KERN_ERR "Request of irq %d for IPI %ld failed\n", - vipi, i); - break; + printk(KERN_ERR "Failed to map %s\n", smp_ipi_name[i]); + continue; } + smp_request_message_ipi(vipi, i); } } diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h index 6209c62a426..3cef2af10f4 100644 --- a/arch/powerpc/sysdev/mpic.h +++ b/arch/powerpc/sysdev/mpic.h @@ -36,6 +36,6 @@ static inline int mpic_pasemi_msi_init(struct mpic *mpic) extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type); extern void mpic_set_vector(unsigned int virq, unsigned int vector); -extern void mpic_set_affinity(unsigned int irq, cpumask_t cpumask); +extern void mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask); #endif /* _POWERPC_SYSDEV_MPIC_H */ diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index d3e4d61030b..77fae5f64f2 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -194,11 +194,41 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, * 4xx PCI 2.x part */ +static int __init ppc4xx_setup_one_pci_PMM(struct pci_controller *hose, + void __iomem *reg, + u64 plb_addr, + u64 pci_addr, + u64 size, + unsigned int flags, + int index) +{ + u32 ma, pcila, pciha; + + if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) || + size < 0x1000 || (plb_addr & (size - 1)) != 0) { + printk(KERN_WARNING "%s: Resource out of range\n", + hose->dn->full_name); + return -1; + } + ma = (0xffffffffu << ilog2(size)) | 1; + if (flags & IORESOURCE_PREFETCH) + ma |= 2; + + pciha = RES_TO_U32_HIGH(pci_addr); + pcila = RES_TO_U32_LOW(pci_addr); + + writel(plb_addr, reg + PCIL0_PMM0LA + (0x10 * index)); + writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * index)); + writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * index)); + writel(ma, reg + PCIL0_PMM0MA + (0x10 * index)); + + return 0; +} + static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, void __iomem *reg) { - u32 la, ma, pcila, pciha; - int i, j; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -213,28 +243,29 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, break; } - /* Calculate register values */ - la = res->start; - pciha = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); - pcila = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); - - ma = res->end + 1 - res->start; - if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) { - printk(KERN_WARNING "%s: Resource out of range\n", - hose->dn->full_name); - continue; + /* Configure the resource */ + if (ppc4xx_setup_one_pci_PMM(hose, reg, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - ma = (0xffffffffu << ilog2(ma)) | 0x1; - if (res->flags & IORESOURCE_PREFETCH) - ma |= 0x2; - - /* Program register values */ - writel(la, reg + PCIL0_PMM0LA + (0x10 * j)); - writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * j)); - writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * j)); - writel(ma, reg + PCIL0_PMM0MA + (0x10 * j)); - j++; } + + /* Handle ISA memory hole if not already covered */ + if (j <= 2 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pci_PMM(hose, reg, hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); } static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose, @@ -352,11 +383,52 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np) * 4xx PCI-X part */ +static int __init ppc4xx_setup_one_pcix_POM(struct pci_controller *hose, + void __iomem *reg, + u64 plb_addr, + u64 pci_addr, + u64 size, + unsigned int flags, + int index) +{ + u32 lah, lal, pciah, pcial, sa; + + if (!is_power_of_2(size) || size < 0x1000 || + (plb_addr & (size - 1)) != 0) { + printk(KERN_WARNING "%s: Resource out of range\n", + hose->dn->full_name); + return -1; + } + + /* Calculate register values */ + lah = RES_TO_U32_HIGH(plb_addr); + lal = RES_TO_U32_LOW(plb_addr); + pciah = RES_TO_U32_HIGH(pci_addr); + pcial = RES_TO_U32_LOW(pci_addr); + sa = (0xffffffffu << ilog2(size)) | 0x1; + + /* Program register values */ + if (index == 0) { + writel(lah, reg + PCIX0_POM0LAH); + writel(lal, reg + PCIX0_POM0LAL); + writel(pciah, reg + PCIX0_POM0PCIAH); + writel(pcial, reg + PCIX0_POM0PCIAL); + writel(sa, reg + PCIX0_POM0SA); + } else { + writel(lah, reg + PCIX0_POM1LAH); + writel(lal, reg + PCIX0_POM1LAL); + writel(pciah, reg + PCIX0_POM1PCIAH); + writel(pcial, reg + PCIX0_POM1PCIAL); + writel(sa, reg + PCIX0_POM1SA); + } + + return 0; +} + static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, void __iomem *reg) { - u32 lah, lal, pciah, pcial, sa; - int i, j; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -371,36 +443,29 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, break; } - /* Calculate register values */ - lah = RES_TO_U32_HIGH(res->start); - lal = RES_TO_U32_LOW(res->start); - pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); - pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); - sa = res->end + 1 - res->start; - if (!is_power_of_2(sa) || sa < 0x100000 || - sa > 0xffffffffu) { - printk(KERN_WARNING "%s: Resource out of range\n", - hose->dn->full_name); - continue; + /* Configure the resource */ + if (ppc4xx_setup_one_pcix_POM(hose, reg, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - sa = (0xffffffffu << ilog2(sa)) | 0x1; - - /* Program register values */ - if (j == 0) { - writel(lah, reg + PCIX0_POM0LAH); - writel(lal, reg + PCIX0_POM0LAL); - writel(pciah, reg + PCIX0_POM0PCIAH); - writel(pcial, reg + PCIX0_POM0PCIAL); - writel(sa, reg + PCIX0_POM0SA); - } else { - writel(lah, reg + PCIX0_POM1LAH); - writel(lal, reg + PCIX0_POM1LAL); - writel(pciah, reg + PCIX0_POM1PCIAH); - writel(pcial, reg + PCIX0_POM1PCIAL); - writel(sa, reg + PCIX0_POM1SA); - } - j++; } + + /* Handle ISA memory hole if not already covered */ + if (j <= 1 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pcix_POM(hose, reg, hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); } static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose, @@ -1317,12 +1382,72 @@ static struct pci_ops ppc4xx_pciex_pci_ops = .write = ppc4xx_pciex_write_config, }; +static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, + struct pci_controller *hose, + void __iomem *mbase, + u64 plb_addr, + u64 pci_addr, + u64 size, + unsigned int flags, + int index) +{ + u32 lah, lal, pciah, pcial, sa; + + if (!is_power_of_2(size) || + (index < 2 && size < 0x100000) || + (index == 2 && size < 0x100) || + (plb_addr & (size - 1)) != 0) { + printk(KERN_WARNING "%s: Resource out of range\n", + hose->dn->full_name); + return -1; + } + + /* Calculate register values */ + lah = RES_TO_U32_HIGH(plb_addr); + lal = RES_TO_U32_LOW(plb_addr); + pciah = RES_TO_U32_HIGH(pci_addr); + pcial = RES_TO_U32_LOW(pci_addr); + sa = (0xffffffffu << ilog2(size)) | 0x1; + + /* Program register values */ + switch (index) { + case 0: + out_le32(mbase + PECFG_POM0LAH, pciah); + out_le32(mbase + PECFG_POM0LAL, pcial); + dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); + dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); + /* Note that 3 here means enabled | single region */ + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); + break; + case 1: + out_le32(mbase + PECFG_POM1LAH, pciah); + out_le32(mbase + PECFG_POM1LAL, pcial); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); + /* Note that 3 here means enabled | single region */ + dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); + break; + case 2: + out_le32(mbase + PECFG_POM2LAH, pciah); + out_le32(mbase + PECFG_POM2LAL, pcial); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); + /* Note that 3 here means enabled | IO space !!! */ + dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, sa | 3); + break; + } + + return 0; +} + static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, struct pci_controller *hose, void __iomem *mbase) { - u32 lah, lal, pciah, pcial, sa; - int i, j; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -1337,53 +1462,38 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, break; } - /* Calculate register values */ - lah = RES_TO_U32_HIGH(res->start); - lal = RES_TO_U32_LOW(res->start); - pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); - pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); - sa = res->end + 1 - res->start; - if (!is_power_of_2(sa) || sa < 0x100000 || - sa > 0xffffffffu) { - printk(KERN_WARNING "%s: Resource out of range\n", - port->node->full_name); - continue; - } - sa = (0xffffffffu << ilog2(sa)) | 0x1; - - /* Program register values */ - switch (j) { - case 0: - out_le32(mbase + PECFG_POM0LAH, pciah); - out_le32(mbase + PECFG_POM0LAL, pcial); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); - break; - case 1: - out_le32(mbase + PECFG_POM1LAH, pciah); - out_le32(mbase + PECFG_POM1LAL, pcial); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); - break; + /* Configure the resource */ + if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - j++; } - /* Configure IO, always 64K starting at 0 */ - if (hose->io_resource.flags & IORESOURCE_IO) { - lah = RES_TO_U32_HIGH(hose->io_base_phys); - lal = RES_TO_U32_LOW(hose->io_base_phys); - out_le32(mbase + PECFG_POM2LAH, 0); - out_le32(mbase + PECFG_POM2LAL, 0); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0xffff0000 | 3); - } + /* Handle ISA memory hole if not already covered */ + if (j <= 1 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, + hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); + + /* Configure IO, always 64K starting at 0. We hard wire it to 64K ! + * Note also that it -has- to be region index 2 on this HW + */ + if (hose->io_resource.flags & IORESOURCE_IO) + ppc4xx_setup_one_pciex_POM(port, hose, mbase, + hose->io_base_phys, 0, + 0x10000, IORESOURCE_IO, 2); } static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig index 76ffbc48d4b..41ac3dfac98 100644 --- a/arch/powerpc/sysdev/qe_lib/Kconfig +++ b/arch/powerpc/sysdev/qe_lib/Kconfig @@ -22,5 +22,6 @@ config UCC config QE_USB bool + default y if USB_GADGET_FSL_QE help - QE USB Host Controller support + QE USB Controller support diff --git a/arch/powerpc/sysdev/qe_lib/gpio.c b/arch/powerpc/sysdev/qe_lib/gpio.c index 8e5a0bc36d0..3485288dce3 100644 --- a/arch/powerpc/sysdev/qe_lib/gpio.c +++ b/arch/powerpc/sysdev/qe_lib/gpio.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/spinlock.h> +#include <linux/err.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_gpio.h> @@ -24,8 +25,14 @@ struct qe_gpio_chip { struct of_mm_gpio_chip mm_gc; spinlock_t lock; + unsigned long pin_flags[QE_PIO_PINS]; +#define QE_PIN_REQUESTED 0 + /* shadowed data register to clear/set bits safely */ u32 cpdata; + + /* saved_regs used to restore dedicated functions */ + struct qe_pio_regs saved_regs; }; static inline struct qe_gpio_chip * @@ -40,6 +47,12 @@ static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) struct qe_pio_regs __iomem *regs = mm_gc->regs; qe_gc->cpdata = in_be32(®s->cpdata); + qe_gc->saved_regs.cpdata = qe_gc->cpdata; + qe_gc->saved_regs.cpdir1 = in_be32(®s->cpdir1); + qe_gc->saved_regs.cpdir2 = in_be32(®s->cpdir2); + qe_gc->saved_regs.cppar1 = in_be32(®s->cppar1); + qe_gc->saved_regs.cppar2 = in_be32(®s->cppar2); + qe_gc->saved_regs.cpodr = in_be32(®s->cpodr); } static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio) @@ -103,6 +116,188 @@ static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } +struct qe_pin { + /* + * The qe_gpio_chip name is unfortunate, we should change that to + * something like qe_pio_controller. Someday. + */ + struct qe_gpio_chip *controller; + int num; +}; + +/** + * qe_pin_request - Request a QE pin + * @np: device node to get a pin from + * @index: index of a pin in the device tree + * Context: non-atomic + * + * This function return qe_pin so that you could use it with the rest of + * the QE Pin Multiplexing API. + */ +struct qe_pin *qe_pin_request(struct device_node *np, int index) +{ + struct qe_pin *qe_pin; + struct device_node *gc; + struct of_gpio_chip *of_gc = NULL; + struct of_mm_gpio_chip *mm_gc; + struct qe_gpio_chip *qe_gc; + int err; + int size; + const void *gpio_spec; + const u32 *gpio_cells; + unsigned long flags; + + qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL); + if (!qe_pin) { + pr_debug("%s: can't allocate memory\n", __func__); + return ERR_PTR(-ENOMEM); + } + + err = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, + &gc, &gpio_spec); + if (err) { + pr_debug("%s: can't parse gpios property\n", __func__); + goto err0; + } + + if (!of_device_is_compatible(gc, "fsl,mpc8323-qe-pario-bank")) { + pr_debug("%s: tried to get a non-qe pin\n", __func__); + err = -EINVAL; + goto err1; + } + + of_gc = gc->data; + if (!of_gc) { + pr_debug("%s: gpio controller %s isn't registered\n", + np->full_name, gc->full_name); + err = -ENODEV; + goto err1; + } + + gpio_cells = of_get_property(gc, "#gpio-cells", &size); + if (!gpio_cells || size != sizeof(*gpio_cells) || + *gpio_cells != of_gc->gpio_cells) { + pr_debug("%s: wrong #gpio-cells for %s\n", + np->full_name, gc->full_name); + err = -EINVAL; + goto err1; + } + + err = of_gc->xlate(of_gc, np, gpio_spec, NULL); + if (err < 0) + goto err1; + + mm_gc = to_of_mm_gpio_chip(&of_gc->gc); + qe_gc = to_qe_gpio_chip(mm_gc); + + spin_lock_irqsave(&qe_gc->lock, flags); + + if (test_and_set_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[err]) == 0) { + qe_pin->controller = qe_gc; + qe_pin->num = err; + err = 0; + } else { + err = -EBUSY; + } + + spin_unlock_irqrestore(&qe_gc->lock, flags); + + if (!err) + return qe_pin; +err1: + of_node_put(gc); +err0: + kfree(qe_pin); + pr_debug("%s failed with status %d\n", __func__, err); + return ERR_PTR(err); +} +EXPORT_SYMBOL(qe_pin_request); + +/** + * qe_pin_free - Free a pin + * @qe_pin: pointer to the qe_pin structure + * Context: any + * + * This function frees the qe_pin structure and makes a pin available + * for further qe_pin_request() calls. + */ +void qe_pin_free(struct qe_pin *qe_pin) +{ + struct qe_gpio_chip *qe_gc = qe_pin->controller; + unsigned long flags; + const int pin = qe_pin->num; + + spin_lock_irqsave(&qe_gc->lock, flags); + test_and_clear_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[pin]); + spin_unlock_irqrestore(&qe_gc->lock, flags); + + kfree(qe_pin); +} +EXPORT_SYMBOL(qe_pin_free); + +/** + * qe_pin_set_dedicated - Revert a pin to a dedicated peripheral function mode + * @qe_pin: pointer to the qe_pin structure + * Context: any + * + * This function resets a pin to a dedicated peripheral function that + * has been set up by the firmware. + */ +void qe_pin_set_dedicated(struct qe_pin *qe_pin) +{ + struct qe_gpio_chip *qe_gc = qe_pin->controller; + struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs; + struct qe_pio_regs *sregs = &qe_gc->saved_regs; + int pin = qe_pin->num; + u32 mask1 = 1 << (QE_PIO_PINS - (pin + 1)); + u32 mask2 = 0x3 << (QE_PIO_PINS - (pin % (QE_PIO_PINS / 2) + 1) * 2); + bool second_reg = pin > (QE_PIO_PINS / 2) - 1; + unsigned long flags; + + spin_lock_irqsave(&qe_gc->lock, flags); + + if (second_reg) { + clrsetbits_be32(®s->cpdir2, mask2, sregs->cpdir2 & mask2); + clrsetbits_be32(®s->cppar2, mask2, sregs->cppar2 & mask2); + } else { + clrsetbits_be32(®s->cpdir1, mask2, sregs->cpdir1 & mask2); + clrsetbits_be32(®s->cppar1, mask2, sregs->cppar1 & mask2); + } + + if (sregs->cpdata & mask1) + qe_gc->cpdata |= mask1; + else + qe_gc->cpdata &= ~mask1; + + out_be32(®s->cpdata, qe_gc->cpdata); + clrsetbits_be32(®s->cpodr, mask1, sregs->cpodr & mask1); + + spin_unlock_irqrestore(&qe_gc->lock, flags); +} +EXPORT_SYMBOL(qe_pin_set_dedicated); + +/** + * qe_pin_set_gpio - Set a pin to the GPIO mode + * @qe_pin: pointer to the qe_pin structure + * Context: any + * + * This function sets a pin to the GPIO mode. + */ +void qe_pin_set_gpio(struct qe_pin *qe_pin) +{ + struct qe_gpio_chip *qe_gc = qe_pin->controller; + struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs; + unsigned long flags; + + spin_lock_irqsave(&qe_gc->lock, flags); + + /* Let's make it input by default, GPIO API is able to change that. */ + __par_io_config_pin(regs, qe_pin->num, QE_PIO_DIR_IN, 0, 0, 0); + + spin_unlock_irqrestore(&qe_gc->lock, flags); +} +EXPORT_SYMBOL(qe_pin_set_gpio); + static int __init qe_add_gpiochips(void) { struct device_node *np; diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index b3b73ae57d6..01bce3784b0 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/param.h> #include <linux/string.h> +#include <linux/spinlock.h> #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/bootmem.h> @@ -38,6 +39,8 @@ static void qe_snums_init(void); static int qe_sdma_init(void); static DEFINE_SPINLOCK(qe_lock); +DEFINE_SPINLOCK(cmxgcr_lock); +EXPORT_SYMBOL(cmxgcr_lock); /* QE snum state */ enum qe_snum_state { diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c index 1d78071aad7..ebb442ea191 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc.c +++ b/arch/powerpc/sysdev/qe_lib/ucc.c @@ -18,6 +18,7 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/stddef.h> +#include <linux/spinlock.h> #include <linux/module.h> #include <asm/irq.h> @@ -26,9 +27,6 @@ #include <asm/qe.h> #include <asm/ucc.h> -DEFINE_SPINLOCK(cmxgcr_lock); -EXPORT_SYMBOL(cmxgcr_lock); - int ucc_set_qe_mux_mii_mng(unsigned int ucc_num) { unsigned long flags; diff --git a/arch/powerpc/sysdev/simple_gpio.c b/arch/powerpc/sysdev/simple_gpio.c new file mode 100644 index 00000000000..43c4569e24b --- /dev/null +++ b/arch/powerpc/sysdev/simple_gpio.c @@ -0,0 +1,155 @@ +/* + * Simple Memory-Mapped GPIOs + * + * Copyright (c) MontaVista Software, Inc. 2008. + * + * Author: Anton Vorontsov <avorontsov@ru.mvista.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> +#include <asm/prom.h> +#include "simple_gpio.h" + +struct u8_gpio_chip { + struct of_mm_gpio_chip mm_gc; + spinlock_t lock; + + /* shadowed data register to clear/set bits safely */ + u8 data; +}; + +static struct u8_gpio_chip *to_u8_gpio_chip(struct of_mm_gpio_chip *mm_gc) +{ + return container_of(mm_gc, struct u8_gpio_chip, mm_gc); +} + +static u8 u8_pin2mask(unsigned int pin) +{ + return 1 << (8 - 1 - pin); +} + +static int u8_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + + return in_8(mm_gc->regs) & u8_pin2mask(gpio); +} + +static void u8_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc); + unsigned long flags; + + spin_lock_irqsave(&u8_gc->lock, flags); + + if (val) + u8_gc->data |= u8_pin2mask(gpio); + else + u8_gc->data &= ~u8_pin2mask(gpio); + + out_8(mm_gc->regs, u8_gc->data); + + spin_unlock_irqrestore(&u8_gc->lock, flags); +} + +static int u8_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) +{ + return 0; +} + +static int u8_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + u8_gpio_set(gc, gpio, val); + return 0; +} + +static void u8_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) +{ + struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc); + + u8_gc->data = in_8(mm_gc->regs); +} + +static int __init u8_simple_gpiochip_add(struct device_node *np) +{ + int ret; + struct u8_gpio_chip *u8_gc; + struct of_mm_gpio_chip *mm_gc; + struct of_gpio_chip *of_gc; + struct gpio_chip *gc; + + u8_gc = kzalloc(sizeof(*u8_gc), GFP_KERNEL); + if (!u8_gc) + return -ENOMEM; + + spin_lock_init(&u8_gc->lock); + + mm_gc = &u8_gc->mm_gc; + of_gc = &mm_gc->of_gc; + gc = &of_gc->gc; + + mm_gc->save_regs = u8_gpio_save_regs; + of_gc->gpio_cells = 2; + gc->ngpio = 8; + gc->direction_input = u8_gpio_dir_in; + gc->direction_output = u8_gpio_dir_out; + gc->get = u8_gpio_get; + gc->set = u8_gpio_set; + + ret = of_mm_gpiochip_add(np, mm_gc); + if (ret) + goto err; + return 0; +err: + kfree(u8_gc); + return ret; +} + +void __init simple_gpiochip_init(const char *compatible) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, compatible) { + int ret; + struct resource r; + + ret = of_address_to_resource(np, 0, &r); + if (ret) + goto err; + + switch (resource_size(&r)) { + case 1: + ret = u8_simple_gpiochip_add(np); + if (ret) + goto err; + break; + default: + /* + * Whenever you need support for GPIO bank width > 1, + * please just turn u8_ code into huge macros, and + * construct needed uX_ code with it. + */ + ret = -ENOSYS; + goto err; + } + continue; +err: + pr_err("%s: registration failed, status %d\n", + np->full_name, ret); + } +} diff --git a/arch/powerpc/sysdev/simple_gpio.h b/arch/powerpc/sysdev/simple_gpio.h new file mode 100644 index 00000000000..3a7b0c513c7 --- /dev/null +++ b/arch/powerpc/sysdev/simple_gpio.h @@ -0,0 +1,12 @@ +#ifndef __SYSDEV_SIMPLE_GPIO_H +#define __SYSDEV_SIMPLE_GPIO_H + +#include <linux/errno.h> + +#ifdef CONFIG_SIMPLE_GPIO +extern void simple_gpiochip_init(const char *compatible); +#else +static inline void simple_gpiochip_init(const char *compatible) {} +#endif /* CONFIG_SIMPLE_GPIO */ + +#endif /* __SYSDEV_SIMPLE_GPIO_H */ |