/* * Copyright 2008-2013 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Freescale Semiconductor nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * * ALTERNATIVELY, this software may be distributed under the terms of the * GNU General Public License ("GPL") as published by the Free Software * Foundation, either version 2 of that License or (at your option) any * later version. * * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "fsl_fman_memac_mii_acc.h" static void write_phy_reg_10g(struct memac_mii_access_mem_map *mii_regs, uint8_t phy_addr, uint8_t reg, uint16_t data) { uint32_t tmp_reg; tmp_reg = ioread32be(&mii_regs->mdio_cfg); /* Leave only MDIO_CLK_DIV bits set on */ tmp_reg &= MDIO_CFG_CLK_DIV_MASK; /* Set maximum MDIO_HOLD value to allow phy to see change of data signal */ tmp_reg |= MDIO_CFG_HOLD_MASK; /* Add 10G interface mode */ tmp_reg |= MDIO_CFG_ENC45; iowrite32be(tmp_reg, &mii_regs->mdio_cfg); /* Wait for command completion */ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) udelay(1); /* Specify phy and register to be accessed */ iowrite32be(phy_addr, &mii_regs->mdio_ctrl); iowrite32be(reg, &mii_regs->mdio_addr); wmb(); while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) udelay(1); /* Write data */ iowrite32be(data, &mii_regs->mdio_data); wmb(); /* Wait for write transaction end */ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) udelay(1); } static uint32_t read_phy_reg_10g(struct memac_mii_access_mem_map *mii_regs, uint8_t phy_addr, uint8_t reg, uint16_t *data) { uint32_t tmp_reg; tmp_reg = ioread32be(&mii_regs->mdio_cfg); /* Leave only MDIO_CLK_DIV bits set on */ tmp_reg &= MDIO_CFG_CLK_DIV_MASK; /* Set maximum MDIO_HOLD value to allow phy to see change of data signal */ tmp_reg |= MDIO_CFG_HOLD_MASK; /* Add 10G interface mode */ tmp_reg |= MDIO_CFG_ENC45; iowrite32be(tmp_reg, &mii_regs->mdio_cfg); /* Wait for command completion */ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) udelay(1); /* Specify phy and register to be accessed */ iowrite32be(phy_addr, &mii_regs->mdio_ctrl); iowrite32be(reg, &mii_regs->mdio_addr); wmb(); while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) udelay(1); /* Read cycle */ tmp_reg = phy_addr; tmp_reg |= MDIO_CTL_READ; iowrite32be(tmp_reg, &mii_regs->mdio_ctrl); wmb(); /* Wait for data to be available */ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) udelay(1); *data = (uint16_t)ioread32be(&mii_regs->mdio_data); /* Check if there was an error */ return ioread32be(&mii_regs->mdio_cfg); } static void write_phy_reg_1g(struct memac_mii_access_mem_map *mii_regs, uint8_t phy_addr, uint8_t reg, uint16_t data) { uint32_t tmp_reg; /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */ tmp_reg = ioread32be(&mii_regs->mdio_cfg); tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK); iowrite32be(tmp_reg, &mii_regs->mdio_cfg); /* Wait for command completion */ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) udelay(1); /* Write transaction */ tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT); tmp_reg |= reg; iowrite32be(tmp_reg, &mii_regs->mdio_ctrl); while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) udelay(1); iowrite32be(data, &mii_regs->mdio_data); wmb(); /* Wait for write transaction to end */ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) udelay(1); } static uint32_t read_phy_reg_1g(struct memac_mii_access_mem_map *mii_regs, uint8_t phy_addr, uint8_t reg, uint16_t *data) { uint32_t tmp_reg; /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */ tmp_reg = ioread32be(&mii_regs->mdio_cfg); tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK); iowrite32be(tmp_reg, &mii_regs->mdio_cfg); /* Wait for command completion */ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) udelay(1); /* Read transaction */ tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT); tmp_reg |= reg; tmp_reg |= MDIO_CTL_READ; iowrite32be(tmp_reg, &mii_regs->mdio_ctrl); while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) udelay(1); /* Wait for data to be available */ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) udelay(1); *data = (uint16_t)ioread32be(&mii_regs->mdio_data); /* Check error */ return ioread32be(&mii_regs->mdio_cfg); } /*****************************************************************************/ int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map *mii_regs, uint8_t phy_addr, uint8_t reg, uint16_t data, enum enet_speed enet_speed) { /* Figure out interface type - 10G vs 1G. In 10G interface both phy_addr and devAddr present. */ if (enet_speed == E_ENET_SPEED_10000) write_phy_reg_10g(mii_regs, phy_addr, reg, data); else write_phy_reg_1g(mii_regs, phy_addr, reg, data); return 0; } /*****************************************************************************/ int fman_memac_mii_read_phy_reg(struct memac_mii_access_mem_map *mii_regs, uint8_t phy_addr, uint8_t reg, uint16_t *data, enum enet_speed enet_speed) { uint32_t ans; /* Figure out interface type - 10G vs 1G. In 10G interface both phy_addr and devAddr present. */ if (enet_speed == E_ENET_SPEED_10000) ans = read_phy_reg_10g(mii_regs, phy_addr, reg, data); else ans = read_phy_reg_1g(mii_regs, phy_addr, reg, data); if (ans & MDIO_CFG_READ_ERR) return -EINVAL; return 0; } /* ......................................................................... */