From: David Mercado <david.merc...@windriver.com> adds the LSI ACP wrapper routines into the kernel. These are needed for the LSI RTE application.
Signed-off-by: David Mercado <david.merc...@windriver.com> --- arch/powerpc/include/asm/lsi/acp_ncr.h | 3 + arch/powerpc/sysdev/Makefile | 2 +- arch/powerpc/sysdev/lsi_acp_wrappers.c | 325 +++++++++++++++++++++++++++++++++ drivers/net/ethernet/lsi/lsi_acp_net.c | 117 +----------- drivers/net/ethernet/lsi/lsi_acp_net.h | 2 - 5 files changed, 333 insertions(+), 116 deletions(-) create mode 100644 arch/powerpc/sysdev/lsi_acp_wrappers.c diff --git a/arch/powerpc/include/asm/lsi/acp_ncr.h b/arch/powerpc/include/asm/lsi/acp_ncr.h index a7399e7..1a08f07 100644 --- a/arch/powerpc/include/asm/lsi/acp_ncr.h +++ b/arch/powerpc/include/asm/lsi/acp_ncr.h @@ -39,4 +39,7 @@ int ncr_write(unsigned long, unsigned long, int, void *); int is_asic(void); +extern int acp_mdio_read(unsigned long, unsigned long, unsigned short *); +extern int acp_mdio_write(unsigned long, unsigned long, unsigned short); + #endif /* __DRIVERS_LSI_ACP_NCR_H */ diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 6354d1c..a95b59f 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -73,4 +73,4 @@ obj-$(CONFIG_PPC_XICS) += xics/ obj-$(CONFIG_GE_FPGA) += ge/ -obj-$(CONFIG_ACP) += lsi_acp_ncr.o +obj-$(CONFIG_ACP) += lsi_acp_ncr.o lsi_acp_wrappers.o diff --git a/arch/powerpc/sysdev/lsi_acp_wrappers.c b/arch/powerpc/sysdev/lsi_acp_wrappers.c new file mode 100644 index 0000000..910ed25 --- /dev/null +++ b/arch/powerpc/sysdev/lsi_acp_wrappers.c @@ -0,0 +1,325 @@ +/* + * arch/powerpc/sysdev/lsi_acp_wrappers.c + * + * Copyright (C) 2013 LSI + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/sched.h> +#include <linux/of.h> +#include <linux/io.h> +#include <asm/irq.h> +#include <asm/lsi/acp_ncr.h> + +MODULE_AUTHOR("LSI Corporation"); +MODULE_DESCRIPTION("ACP Wrappers"); +MODULE_LICENSE("GPL"); + +/* + ============================================================================ + ============================================================================ + MDIO Access + ============================================================================ + ============================================================================ +*/ + + +static unsigned long mdio_base; +DEFINE_SPINLOCK(mdio_lock); + +#define MDIO_CONTROL_RD_DATA ((void *)(mdio_base + 0x0)) +#define MDIO_STATUS_RD_DATA ((void *)(mdio_base + 0x4)) +#define MDIO_CLK_OFFSET ((void *)(mdio_base + 0x8)) +#define MDIO_CLK_PERIOD ((void *)(mdio_base + 0xc)) + +/* + * ------------------------------------------------------------------------- + * acp_mdio_read + */ + +int acp_mdio_read(unsigned long address, unsigned long offset, + unsigned short *value) +{ + unsigned long command = 0; + unsigned long status; + unsigned long flags; + + spin_lock_irqsave(&mdio_lock, flags); + + /* Set the mdio_busy (status) bit. */ + status = in_le32(MDIO_STATUS_RD_DATA); + status |= 0x40000000; + out_le32(MDIO_STATUS_RD_DATA, status); + + /* Write the command.*/ + command |= 0x10000000; /* op_code: read */ + command |= (address & 0x1f) << 16; /* port_addr (target device) */ + command |= (offset & 0x1f) << 21; /* device_addr (target register) */ + out_le32(MDIO_CONTROL_RD_DATA, command); + + /* Wait for the mdio_busy (status) bit to clear. */ + do { + status = in_le32(MDIO_STATUS_RD_DATA); + } while (0 != (status & 0x40000000)); + + /* Wait for the mdio_busy (control) bit to clear. */ + do { + command = in_le32(MDIO_CONTROL_RD_DATA); + } while (0 != (command & 0x80000000)); + + *value = (unsigned short)(command & 0xffff); + + spin_unlock_irqrestore(&mdio_lock, flags); + + return 0; +} +EXPORT_SYMBOL(acp_mdio_read); + +/* + * ------------------------------------------------------------------------- + * acp_mdio_write + */ + +int acp_mdio_write(unsigned long address, unsigned long offset, + unsigned short value) +{ + unsigned long command = 0; + unsigned long status; + unsigned long flags; + + spin_lock_irqsave(&mdio_lock, flags); + + /* Wait for mdio_busy (control) to be clear. */ + do { + command = in_le32(MDIO_CONTROL_RD_DATA); + } while (0 != (command & 0x80000000)); + + /* Set the mdio_busy (status) bit. */ + status = in_le32(MDIO_STATUS_RD_DATA); + status |= 0x40000000; + out_le32(MDIO_STATUS_RD_DATA, status); + + /* Write the command. */ + command = 0x08000000; /* op_code: write */ + command |= (address & 0x1f) << 16; /* port_addr (target device) */ + command |= (offset & 0x1f) << 21; /* device_addr (target register) */ + command |= (value & 0xffff); /* value */ + out_le32(MDIO_CONTROL_RD_DATA, command); + + /* Wait for the mdio_busy (status) bit to clear. */ + do { + status = in_le32(MDIO_STATUS_RD_DATA); + } while (0 != (status & 0x40000000)); + + /* Wait for the mdio_busy (control) bit to clear. */ + do { + command = in_le32(MDIO_CONTROL_RD_DATA); + } while (0 != (command & 0x80000000)); + + spin_unlock_irqrestore(&mdio_lock, flags); + + return 0; +} +EXPORT_SYMBOL(acp_mdio_write); + +/* + * ------------------------------------------------------------------------- + * acp_mdio_initialize + */ + +static int acp_mdio_initialize(void) +{ + if (is_asic()) { + out_le32(MDIO_CLK_OFFSET, 0x10); + out_le32(MDIO_CLK_PERIOD, 0x2c); + } else { + out_le32(MDIO_CLK_OFFSET, 0x05); + out_le32(MDIO_CLK_PERIOD, 0x0c); + } + + return 0; +} + + +/* + ============================================================================ + ============================================================================ + Interrupts + ============================================================================ + ============================================================================ +*/ + +/* + * ------------------------------------------------------------------------- + * acp_irq_create_mapping + */ +unsigned int acp_irq_create_mapping(struct irq_domain *host, + irq_hw_number_t hwirq) +{ + unsigned int mapped_irq; + + preempt_disable(); + mapped_irq = irq_create_mapping(host, hwirq); + preempt_enable(); + + return mapped_irq; +} +EXPORT_SYMBOL(acp_irq_create_mapping); + +/* + ============================================================================ + ============================================================================ + Spin Locks + ============================================================================ + ============================================================================ +*/ + +/* + * ------------------------------------------------------------------------- + * acp_spin_lock_init + */ + +void acp_spin_lock_init(spinlock_t *lock) +{ + spin_lock_init(lock); +} +EXPORT_SYMBOL(acp_spin_lock_init); + +/* + * ------------------------------------------------------------------------- + * acp_spin_lock + */ + +void acp_spin_lock(spinlock_t *lock) +{ + spin_lock(lock); +} +EXPORT_SYMBOL(acp_spin_lock); + +/* + * ------------------------------------------------------------------------- + * acp_spin_unlock + */ + +void acp_spin_unlock(spinlock_t *lock) +{ + spin_unlock(lock); +} +EXPORT_SYMBOL(acp_spin_unlock); + +/* + * ------------------------------------------------------------------------- + * acp_spin_lock_bh + */ + +void acp_spin_lock_bh(spinlock_t *lock) +{ + spin_lock_bh(lock); +} +EXPORT_SYMBOL(acp_spin_lock_bh); + +/* + * ------------------------------------------------------------------------- + * acp_spin_unlock_bh + */ + +void acp_spin_unlock_bh(spinlock_t *lock) +{ + spin_unlock_bh(lock); +} +EXPORT_SYMBOL(acp_spin_unlock_bh); + +/* + * ------------------------------------------------------------------------- + * acp_spin_lock_irqsave + */ + +void acp_spin_lock_irqsave(spinlock_t *lock, unsigned long flags) +{ + spin_lock_irqsave(lock, flags); +} +EXPORT_SYMBOL(acp_spin_lock_irqsave); + +/* + * ------------------------------------------------------------------------- + * acp_spin_unlock_irqrestore + */ + +void acp_spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) +{ + spin_unlock_irqrestore(lock, flags); +} +EXPORT_SYMBOL(acp_spin_unlock_irqrestore); + +/* + * ------------------------------------------------------------------------- + * acp_wrappers_init + */ + +int __init acp_wrappers_init(void) +{ + int rc = -1; + struct device_node *np = NULL; + const u32 *field; + u64 mdio_phys_address; + u32 mdio_size; + + pr_info("Initializing ACP Wrappers.\n"); + + np = of_find_node_by_type(np, "network"); + + while (np && !of_device_is_compatible(np, "acp-femac")) + np = of_find_node_by_type(np, "network"); + + if (np) { + field = of_get_property(np, "enabled", NULL); + + if (!field || (field && (0 == *field))) { + pr_warn("Networking is Not Enabled.\n"); + goto acp_wrappers_init_done; + } + + field = of_get_property(np, "mdio-reg", NULL); + + if (!field) { + pr_err("Couldn't get \"mdio-reg\" property.\n"); + } else { + mdio_phys_address = of_translate_address(np, field); + mdio_size = field[1]; + rc = 0; + } + } + + if (0 != rc) { + mdio_phys_address = 0x002000409000ULL; + mdio_size = 0x1000; + pr_warn("** MDIO Address Not Specified in Device Tree.\n"); + } + + mdio_base = (unsigned long)ioremap(mdio_phys_address, mdio_size); + rc = acp_mdio_initialize(); + + if (0 != rc) + pr_err("MDIO Initiailzation Failed!\n"); + +acp_wrappers_init_done: + + return 0; +} + +module_init(acp_wrappers_init); diff --git a/drivers/net/ethernet/lsi/lsi_acp_net.c b/drivers/net/ethernet/lsi/lsi_acp_net.c index 21153bf..605a431 100644 --- a/drivers/net/ethernet/lsi/lsi_acp_net.c +++ b/drivers/net/ethernet/lsi/lsi_acp_net.c @@ -72,7 +72,6 @@ #define LSI_MDIO_NAME "acp-femac-mdio" #define LSI_DRV_VERSION "2013-04-30" - MODULE_AUTHOR("John Jacques"); MODULE_DESCRIPTION("LSI ACP-FEMAC Ethernet driver"); MODULE_LICENSE("GPL"); @@ -83,37 +82,6 @@ static void *tx_base; static void *dma_base; /* - ============================================================================= - MDIO / PHY - ============================================================================= -*/ - -#define MDIO_CONTROL_RD_DATA ((void *)(pdata->mdio_base + 0x0)) -#define MDIO_STATUS_RD_DATA ((void *)(pdata->mdio_base + 0x4)) -#define MDIO_CLK_OFFSET ((void *)(pdata->mdio_base + 0x8)) -#define MDIO_CLK_PERIOD ((void *)(pdata->mdio_base + 0xc)) - -/* - * ---------------------------------------------------------------------- - * appnic_mdio_initialize - */ - -static void appnic_mdio_initialize(struct net_device *dev) -{ - struct appnic_device *pdata = netdev_priv(dev); - - if (is_asic()) { - out_le32(MDIO_CLK_OFFSET, 0x10); - out_le32(MDIO_CLK_PERIOD, 0x2c); - } else { - out_le32(MDIO_CLK_OFFSET, 0x05); - out_le32(MDIO_CLK_PERIOD, 0x0c); - } - - return; -} - -/* * ---------------------------------------------------------------------- * appnic_mii_read * @@ -122,42 +90,14 @@ static void appnic_mdio_initialize(struct net_device *dev) static int appnic_mii_read(struct mii_bus *bus, int phy, int reg) { - struct appnic_device *pdata = (struct appnic_device *)bus->priv; - unsigned long flags; unsigned short value; - unsigned long command = 0; - unsigned long status; - - spin_lock_irqsave(&pdata->mdio_lock, flags); - /* Set the mdio_busy (status) bit. */ - status = in_le32(MDIO_STATUS_RD_DATA); - status |= 0x40000000; - out_le32(MDIO_STATUS_RD_DATA, status); + /* Always returns success, so no need to check return status. */ + acp_mdio_read(phy, reg, &value); - /* Write the command. */ - command |= 0x10000000; /* op_code: read */ - command |= (phy & 0x1f) << 16; /* port_addr (target device) */ - command |= (reg & 0x1f) << 21; /* device_addr (target register) */ - out_le32(MDIO_CONTROL_RD_DATA, command); - - /* Wait for the mdio_busy (status) bit to clear. */ - do { - status = in_le32(MDIO_STATUS_RD_DATA); - } while (0 != (status & 0x40000000)); - - /* Wait for the mdio_busy (control) bit to clear. */ - do { - command = in_le32(MDIO_CONTROL_RD_DATA); - } while (0 != (command & 0x80000000)); - - value = (unsigned short)(command & 0xffff); - spin_unlock_irqrestore(&pdata->mdio_lock, flags); - - return value; + return (int)value; } - /* * ---------------------------------------------------------------------- * appnic_mii_write @@ -165,43 +105,7 @@ static int appnic_mii_read(struct mii_bus *bus, int phy, int reg) static int appnic_mii_write(struct mii_bus *bus, int phy, int reg, u16 val) { - struct appnic_device *pdata = (struct appnic_device *)bus->priv; - unsigned long flags; - unsigned long command = 0; - unsigned long status; - - spin_lock_irqsave(&pdata->mdio_lock, flags); - - /* Wait for mdio_busy (control) to be clear. */ - do { - command = in_le32(MDIO_CONTROL_RD_DATA); - } while (0 != (command & 0x80000000)); - - /* Set the mdio_busy (status) bit. */ - status = in_le32(MDIO_STATUS_RD_DATA); - status |= 0x40000000; - out_le32(MDIO_STATUS_RD_DATA, status); - - /* Write the command. */ - command = 0x08000000; /* op_code: write */ - command |= (phy & 0x1f) << 16; /* port_addr (target device) */ - command |= (reg & 0x1f) << 21; /* device_addr (target register) */ - command |= (val & 0xffff); /* value */ - out_le32(MDIO_CONTROL_RD_DATA, command); - - /* Wait for the mdio_busy (status) bit to clear. */ - do { - status = in_le32(MDIO_STATUS_RD_DATA); - } while (0 != (status & 0x40000000)); - - /* Wait for the mdio_busy (control) bit to clear. */ - do { - command = in_le32(MDIO_CONTROL_RD_DATA); - } while (0 != (command & 0x80000000)); - - spin_unlock_irqrestore(&pdata->mdio_lock, flags); - - return 0; + return acp_mdio_write(phy, reg, val); } /* @@ -1596,7 +1500,6 @@ int appnic_init(struct net_device *dev) * Initialize the spinlocks. */ - spin_lock_init(&pdata->mdio_lock); spin_lock_init(&pdata->dev_lock); spin_lock_init(&pdata->extra_lock); @@ -1807,15 +1710,6 @@ static int __devinit appnic_probe_config_dt(struct net_device *dev, else pdata->mdio_clock = field[0]; - field = of_get_property(np, "mdio-reg", NULL); - if (!field) { - goto device_tree_failed; - } else { - value64 = of_translate_address(np, field); - value32 = field[1]; - pdata->mdio_base = (unsigned long)ioremap(value64, value32); - } - field = of_get_property(np, "phy-address", NULL); if (!field) goto device_tree_failed; @@ -1998,9 +1892,6 @@ static int __devinit appnic_drv_probe(struct platform_device *pdev) goto out; } - /* Initialize the MDIO interface. */ - appnic_mdio_initialize(dev); - /* Initialize the PHY. */ rc = appnic_mii_init(pdev, dev); if (rc) { diff --git a/drivers/net/ethernet/lsi/lsi_acp_net.h b/drivers/net/ethernet/lsi/lsi_acp_net.h index db4bfcf..f7de38d 100644 --- a/drivers/net/ethernet/lsi/lsi_acp_net.h +++ b/drivers/net/ethernet/lsi/lsi_acp_net.h @@ -93,7 +93,6 @@ struct appnic_device { unsigned long dma_base; unsigned long interrupt; unsigned long mdio_clock; - unsigned long mdio_base; unsigned long phy_address; unsigned long ad_value; unsigned char mac_addr[6]; @@ -149,7 +148,6 @@ struct appnic_device { union appnic_queue_pointer tx_head; /* Spin Lock */ - spinlock_t mdio_lock; spinlock_t dev_lock; spinlock_t extra_lock; -- 1.8.4.3 _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto