[linux-yocto] [PATCH 15/78] drivers/net: AXM5516 emulation bringup - lsi_acp_mdio.c

Paul Butler butler.paul at gmail.com
Tue Nov 19 20:22:51 PST 2013


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.8.4.3



More information about the linux-yocto mailing list