[linux-yocto] [PATCH 015/161] drivers/net: AXM5516 emulation bringup - lsi_acp_mdio.c
Cristian Bercaru
cristian.bercaru at windriver.com
Thu May 21 12:19:57 PDT 2015
From: John Jacques <john.jacques at lsi.com>
Signed-off-by: John Jacques <john.jacques at lsi.com>
---
drivers/net/ethernet/lsi/lsi_acp_mdio.c | 243 +++++++++++++++++++++++++++++++
1 file changed, 243 insertions(+)
create mode 100644 drivers/net/ethernet/lsi/lsi_acp_mdio.c
diff --git a/drivers/net/ethernet/lsi/lsi_acp_mdio.c b/drivers/net/ethernet/lsi/lsi_acp_mdio.c
new file mode 100644
index 0000000..dc4e353
--- /dev/null
+++ b/drivers/net/ethernet/lsi/lsi_acp_mdio.c
@@ -0,0 +1,243 @@
+/*
+ * drivers/net/ethernet/lsi/lsi_acp_mdio.c
+ *
+ * Copyright (C) 2010 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
+ */
+
+#if defined(CONFIG_ARCH_AXXIA) && defined(CONFIG_ARM)
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <asm/irq.h>
+#include <asm/lsi/acp_ncr.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/irqdomain.h>
+
+/*
+ ==============================================================================
+ ==============================================================================
+ MDIO Access
+ ==============================================================================
+ ==============================================================================
+*/
+
+#ifndef CONFIG_ACPISS
+
+#define BZ33327_WA
+
+static unsigned long mdio_base;
+static 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))
+
+#ifdef CONFIG_ARM
+#define READ(a) readl((a))
+#define WRITE(a, v) writel((v), (a))
+#else
+#define READ(a) in_le32((a))
+#define WRITE(a, v) out_le32((a), (v))
+#endif
+
+/*
+ ------------------------------------------------------------------------------
+ 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);
+#if defined(BZ33327_WA)
+ /* Set the mdio_busy (status) bit. */
+ status = READ(MDIO_STATUS_RD_DATA);
+ status |= 0x40000000;
+ WRITE(MDIO_STATUS_RD_DATA, status);
+#endif /* BZ33327_WA */
+
+ /* Write the command. */
+ command |= 0x10000000; /* op_code: read */
+ command |= (address & 0x1f) << 16; /* port_addr (target device) */
+ command |= (offset & 0x1f) << 21;/* device_addr (target register) */
+ WRITE(MDIO_CONTROL_RD_DATA, command);
+
+#if defined(BZ33327_WA)
+ /* Wait for the mdio_busy (status) bit to clear. */
+ do {
+ status = READ(MDIO_STATUS_RD_DATA);
+ } while (0 != (status & 0x40000000));
+#endif /* BZ33327_WA */
+
+ /* Wait for the mdio_busy (control) bit to clear. */
+ do {
+ command = READ(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 = READ(MDIO_CONTROL_RD_DATA);
+ } while (0 != (command & 0x80000000));
+
+#if defined(BZ33327_WA)
+ /* Set the mdio_busy (status) bit. */
+ status = READ(MDIO_STATUS_RD_DATA);
+ status |= 0x40000000;
+ WRITE(MDIO_STATUS_RD_DATA, status);
+#endif /* BZ33327_WA */
+
+ /* 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 */
+ WRITE(MDIO_CONTROL_RD_DATA, command);
+
+#if defined(BZ33327_WA)
+ /* Wait for the mdio_busy (status) bit to clear. */
+ do {
+ status = READ(MDIO_STATUS_RD_DATA);
+ } while (0 != (status & 0x40000000));
+#endif /* BZ33327_WA */
+
+ /* Wait for the mdio_busy (control) bit to clear. */
+ do {
+ command = READ(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)
+{
+ WRITE(MDIO_CLK_OFFSET, 0x10);
+ WRITE(MDIO_CLK_PERIOD, 0x2c);
+
+ return 0;
+}
+
+#endif /* ! CONFIG_ACPISS */
+
+/*
+ ==============================================================================
+ ==============================================================================
+ Interrupts
+ ==============================================================================
+ ==============================================================================
+*/
+
+/*
+ ------------------------------------------------------------------------------
+ acp_irq_create_mapping
+*/
+
+unsigned int
+acp_irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq)
+{
+ return irq_create_mapping(host, hwirq);
+}
+EXPORT_SYMBOL(acp_irq_create_mapping);
+
+/*
+ ------------------------------------------------------------------------------
+ acp_wrappers_init
+*/
+
+int __init
+acp_wrappers_init(void)
+{
+ int rc = -ENODEV;
+ struct device_node *np = NULL;
+ const u32 *field;
+ u64 mdio_address;
+ u32 mdio_size;
+
+ printk(KERN_INFO "Initializing Axxia Wrappers.\n");
+
+#ifndef CONFIG_ACPISS
+ 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)
+ goto error;
+
+ field = of_get_property(np, "mdio-reg", NULL);
+
+ if (!field)
+ goto error;
+
+ mdio_address = of_translate_address(np, field);
+ mdio_size = field[1];
+ mdio_base = (unsigned long)ioremap(mdio_address, mdio_size);
+ printk(KERN_INFO "%s:%d - mdio_address=0x%llx mdio_size=0x%x mdio_base=0x%x\n",
+ __FILE__, __LINE__, mdio_address, mdio_size, mdio_base);
+ rc = acp_mdio_initialize();
+#else
+ rc = 0;
+#endif
+
+error:
+
+ return rc;
+}
+module_init(acp_wrappers_init);
+
+MODULE_AUTHOR("LSI Corporation");
+MODULE_DESCRIPTION("Timing Test");
+MODULE_LICENSE("GPL");
+
+#endif
--
1.7.9.5
More information about the linux-yocto
mailing list