diff options
| author | Stefano Babic <sbabic@denx.de> | 2012-11-10 08:05:54 +0100 | 
|---|---|---|
| committer | Stefano Babic <sbabic@denx.de> | 2012-11-10 08:05:54 +0100 | 
| commit | 3e4d27b06d7484040355e22eec2cbce7335d6dab (patch) | |
| tree | 9672a2bb2e4ce0edc0ab776ddf0e2ca8e39a5f62 /drivers/net/fm/memac_phy.c | |
| parent | bad05afe083eec0467220de21683443292c5012e (diff) | |
| parent | 59852d03867108217fe88e3bfc3e1e9cedfe63c5 (diff) | |
| download | olio-uboot-2014.01-3e4d27b06d7484040355e22eec2cbce7335d6dab.tar.xz olio-uboot-2014.01-3e4d27b06d7484040355e22eec2cbce7335d6dab.zip | |
Merge git://git.denx.de/u-boot
Diffstat (limited to 'drivers/net/fm/memac_phy.c')
| -rw-r--r-- | drivers/net/fm/memac_phy.c | 150 | 
1 files changed, 150 insertions, 0 deletions
| diff --git a/drivers/net/fm/memac_phy.c b/drivers/net/fm/memac_phy.c new file mode 100644 index 000000000..ea6118b9b --- /dev/null +++ b/drivers/net/fm/memac_phy.c @@ -0,0 +1,150 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + *	Andy Fleming <afleming@freescale.com> + *	Roy Zang <tie-fei.zang@freescale.com> + * + * 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 + * Some part is taken from tsec.c + */ +#include <common.h> +#include <miiphy.h> +#include <phy.h> +#include <asm/io.h> +#include <asm/fsl_memac.h> +#include <fm_eth.h> + +/* + * Write value to the PHY for this device to the register at regnum, waiting + * until the write is done before it returns.  All PHY configuration has to be + * done through the TSEC1 MIIM regs + */ +int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr, +			int regnum, u16 value) +{ +	u32 mdio_ctl; +	struct memac_mdio_controller *regs = bus->priv; +	u32 c45 = 1; /* Default to 10G interface */ + +	if (dev_addr == MDIO_DEVAD_NONE) { +		c45 = 0; /* clause 22 */ +		dev_addr = regnum & 0x1f; +		clrbits_be32(®s->mdio_stat, MDIO_STAT_ENC); +	} else { +		setbits_be32(®s->mdio_stat, MDIO_STAT_ENC); +		setbits_be32(®s->mdio_stat, MDIO_STAT_HOLD_15_CLK); +	} + +	/* Wait till the bus is free */ +	while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY) +		; + +	/* Set the port and dev addr */ +	mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr); +	out_be32(®s->mdio_ctl, mdio_ctl); + +	/* Set the register address */ +	if (c45) +		out_be32(®s->mdio_addr, regnum & 0xffff); + +	/* Wait till the bus is free */ +	while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY) +		; + +	/* Write the value to the register */ +	out_be32(®s->mdio_data, MDIO_DATA(value)); + +	/* Wait till the MDIO write is complete */ +	while ((in_be32(®s->mdio_data)) & MDIO_DATA_BSY) +		; + +	return 0; +} + +/* + * Reads from register regnum in the PHY for device dev, returning the value. + * Clears miimcom first.  All PHY configuration has to be done through the + * TSEC1 MIIM regs + */ +int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr, +			int regnum) +{ +	u32 mdio_ctl; +	struct memac_mdio_controller *regs = bus->priv; +	u32 c45 = 1; + +	if (dev_addr == MDIO_DEVAD_NONE) { +		c45 = 0; /* clause 22 */ +		dev_addr = regnum & 0x1f; +		clrbits_be32(®s->mdio_stat, MDIO_STAT_ENC); +	} else { +		setbits_be32(®s->mdio_stat, MDIO_STAT_ENC); +		setbits_be32(®s->mdio_stat, MDIO_STAT_HOLD_15_CLK); +	} + +	/* Wait till the bus is free */ +	while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY) +		; + +	/* Set the Port and Device Addrs */ +	mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr); +	out_be32(®s->mdio_ctl, mdio_ctl); + +	/* Set the register address */ +	if (c45) +		out_be32(®s->mdio_addr, regnum & 0xffff); + +	/* Wait till the bus is free */ +	while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY) +		; + +	/* Initiate the read */ +	mdio_ctl |= MDIO_CTL_READ; +	out_be32(®s->mdio_ctl, mdio_ctl); + +	/* Wait till the MDIO write is complete */ +	while ((in_be32(®s->mdio_data)) & MDIO_DATA_BSY) +		; + +	/* Return all Fs if nothing was there */ +	if (in_be32(®s->mdio_stat) & MDIO_STAT_RD_ER) +		return 0xffff; + +	return in_be32(®s->mdio_data) & 0xffff; +} + +int memac_mdio_reset(struct mii_dev *bus) +{ +	return 0; +} + +int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info) +{ +	struct mii_dev *bus = mdio_alloc(); + +	if (!bus) { +		printf("Failed to allocate FM TGEC MDIO bus\n"); +		return -1; +	} + +	bus->read = memac_mdio_read; +	bus->write = memac_mdio_write; +	bus->reset = memac_mdio_reset; +	sprintf(bus->name, info->name); + +	bus->priv = info->regs; + +	return mdio_register(bus); +} |