Signed-off-by: Paul Butler <paul.but...@windriver.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.3.4 _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto