/*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2003-2012 Broadcom Corporation * All Rights Reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY BROADCOM ``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 BROADCOM OR CONTRIBUTORS 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 #include #include #include #include #include #include #include #include #include /* Internal MDIO READ/WRITE Routines */ int nlm_int_gmac_mdio_read(uint64_t nae_base, int bus, int block, int intf_type, int phyaddr, int regidx) { uint32_t mdio_ld_cmd; uint32_t ctrlval; ctrlval = INT_MDIO_CTRL_SMP | (phyaddr << INT_MDIO_CTRL_PHYADDR_POS) | (regidx << INT_MDIO_CTRL_DEVTYPE_POS) | (2 << INT_MDIO_CTRL_OP_POS) | (1 << INT_MDIO_CTRL_ST_POS) | (7 << INT_MDIO_CTRL_XDIV_POS) | (2 << INT_MDIO_CTRL_TA_POS) | (2 << INT_MDIO_CTRL_MIIM_POS) | (1 << INT_MDIO_CTRL_MCDIV_POS); mdio_ld_cmd = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4))); if (mdio_ld_cmd & INT_MDIO_CTRL_CMD_LOAD) { nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus*4)), (mdio_ld_cmd & ~INT_MDIO_CTRL_CMD_LOAD)); } nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval); /* Toggle Load Cmd Bit */ nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval | (1 << INT_MDIO_CTRL_LOAD_POS)); /* poll master busy bit until it is not busy */ while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_RD_STAT + bus * 4))) & INT_MDIO_STAT_MBSY) { } nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval); /* Read the data back */ return nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_RD_STAT + bus * 4))); } /* Internal MDIO WRITE Routines */ int nlm_int_gmac_mdio_write(uint64_t nae_base, int bus, int block, int intf_type, int phyaddr, int regidx, uint16_t val) { uint32_t mdio_ld_cmd; uint32_t ctrlval; ctrlval = INT_MDIO_CTRL_SMP | (phyaddr << INT_MDIO_CTRL_PHYADDR_POS) | (regidx << INT_MDIO_CTRL_DEVTYPE_POS) | (1 << INT_MDIO_CTRL_OP_POS) | (1 << INT_MDIO_CTRL_ST_POS) | (7 << INT_MDIO_CTRL_XDIV_POS) | (2 << INT_MDIO_CTRL_TA_POS) | (1 << INT_MDIO_CTRL_MIIM_POS) | (1 << INT_MDIO_CTRL_MCDIV_POS); mdio_ld_cmd = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4))); if (mdio_ld_cmd & INT_MDIO_CTRL_CMD_LOAD) { nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus*4)), (mdio_ld_cmd & ~INT_MDIO_CTRL_CMD_LOAD)); } /* load data into ctrl data reg */ nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL_DATA + bus * 4)), val); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval | (1 << INT_MDIO_CTRL_LOAD_POS)); /* poll master busy bit until it is not busy */ while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_RD_STAT + bus * 4))) & INT_MDIO_STAT_MBSY) { } nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval); return (0); } int nlm_int_gmac_mdio_reset(uint64_t nae_base, int bus, int block, int intf_type) { uint32_t val; val = (7 << INT_MDIO_CTRL_XDIV_POS) | (1 << INT_MDIO_CTRL_MCDIV_POS) | (INT_MDIO_CTRL_SMP); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), val | INT_MDIO_CTRL_RST); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), val); return (0); } /* * nae_gmac_mdio_read - Read sgmii phy register * * Input parameters: * bus - bus number, nae has two external gmac bus: 0 and 1 * phyaddr - PHY's address * regidx - index of register to read * * Return value: * value read (16 bits), or 0xffffffff if an error occurred. */ int nlm_gmac_mdio_read(uint64_t nae_base, int bus, int block, int intf_type, int phyaddr, int regidx) { uint32_t mdio_ld_cmd; uint32_t ctrlval; mdio_ld_cmd = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL + bus * 4))); if (mdio_ld_cmd & EXT_G_MDIO_CMD_LCD) { nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), (mdio_ld_cmd & ~EXT_G_MDIO_CMD_LCD)); while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4))) & EXT_G_MDIO_STAT_MBSY); } ctrlval = EXT_G_MDIO_CMD_SP | (phyaddr << EXT_G_MDIO_PHYADDR_POS) | (regidx << EXT_G_MDIO_REGADDR_POS); if (nlm_is_xlp8xx_ax() || nlm_is_xlp8xx_b0() || nlm_is_xlp3xx_ax()) ctrlval |= EXT_G_MDIO_DIV; else ctrlval |= EXT_G_MDIO_DIV_WITH_HW_DIV64; nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval | (1<<18)); DELAY(1000); /* poll master busy bit until it is not busy */ while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4))) & EXT_G_MDIO_STAT_MBSY); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval); /* Read the data back */ return nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4))); } /* * nae_gmac_mdio_write -Write sgmac mii PHY register. * * Input parameters: * bus - bus number, nae has two external gmac bus: 0 and 1 * phyaddr - PHY to use * regidx - register within the PHY * val - data to write to register * * Return value: * 0 - success */ int nlm_gmac_mdio_write(uint64_t nae_base, int bus, int block, int intf_type, int phyaddr, int regidx, uint16_t val) { uint32_t mdio_ld_cmd; uint32_t ctrlval; mdio_ld_cmd = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL + bus * 4))); if (mdio_ld_cmd & EXT_G_MDIO_CMD_LCD) { nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), (mdio_ld_cmd & ~EXT_G_MDIO_CMD_LCD)); while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4))) & EXT_G_MDIO_STAT_MBSY); } /* load data into ctrl data reg */ nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL_DATA+bus*4)), val); ctrlval = EXT_G_MDIO_CMD_SP | (phyaddr << EXT_G_MDIO_PHYADDR_POS) | (regidx << EXT_G_MDIO_REGADDR_POS); if (nlm_is_xlp8xx_ax() || nlm_is_xlp8xx_b0() || nlm_is_xlp3xx_ax()) ctrlval |= EXT_G_MDIO_DIV; else ctrlval |= EXT_G_MDIO_DIV_WITH_HW_DIV64; nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval | EXT_G_MDIO_CMD_LCD); DELAY(1000); /* poll master busy bit until it is not busy */ while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4))) & EXT_G_MDIO_STAT_MBSY); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval); return (0); } /* * nae_gmac_mdio_reset -Reset sgmii mdio module. * * Input parameters: * bus - bus number, nae has two external gmac bus: 0 and 1 * * Return value: * 0 - success */ int nlm_gmac_mdio_reset(uint64_t nae_base, int bus, int block, int intf_type) { uint32_t ctrlval; ctrlval = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4))); if (nlm_is_xlp8xx_ax() || nlm_is_xlp8xx_b0() || nlm_is_xlp3xx_ax()) ctrlval |= EXT_G_MDIO_DIV; else ctrlval |= EXT_G_MDIO_DIV_WITH_HW_DIV64; nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL + bus * 4)), EXT_G_MDIO_MMRST | ctrlval); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL + bus * 4)), ctrlval); return (0); } /* * nlm_mdio_reset_all : reset all internal and external MDIO */ void nlm_mdio_reset_all(uint64_t nae_base) { /* reset internal MDIO */ nlm_int_gmac_mdio_reset(nae_base, 0, BLOCK_7, LANE_CFG); /* reset external MDIO */ nlm_gmac_mdio_reset(nae_base, 0, BLOCK_7, LANE_CFG); nlm_gmac_mdio_reset(nae_base, 1, BLOCK_7, LANE_CFG); }