Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*
 * 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;
}

/* ......................................................................... */