[linux-yocto] [PATCH 007/161] drivers/net/ethernet: add ACP wrapper support for LSI RTE into kernel
Cristian Bercaru
cristian.bercaru at windriver.com
Thu May 21 12:19:49 PDT 2015
From: David Mercado <david.mercado at 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.mercado at 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.7.9.5
More information about the linux-yocto
mailing list