Commit 847be49d authored by Fin Maaß's avatar Fin Maaß Committed by Henrik Brix Andersen
Browse files

drivers: ethernet: phy: add common functions for PHYs



This commit adds common functions for PHYs to the mii driver.

Signed-off-by: default avatarFin Maaß <f.maass@vogl-electronic.com>
parent 62b5785d
Loading
Loading
Loading
Loading
+5 −34
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(LOG_MODULE_NAME);

#include "phy_mii.h"

#define PHY_MC_KSZ8081_OMSO_REG			0x16
#define PHY_MC_KSZ8081_OMSO_FACTORY_MODE_MASK	BIT(15)
#define PHY_MC_KSZ8081_OMSO_NAND_TREE_MASK	BIT(5)
@@ -339,7 +341,6 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev,
	struct mc_ksz8081_data *data = dev->data;
	struct phy_link_state state = {};
	int ret;
	uint32_t anar;

	/* Lock mutex */
	ret = k_mutex_lock(&data->mutex, K_FOREVER);
@@ -357,39 +358,9 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev,
		goto done;
	}

	/* Read ANAR register to write back */
	ret = phy_mc_ksz8081_read(dev, MII_ANAR, &anar);
	if (ret) {
		LOG_ERR("Error reading phy (%d) advertising register", config->addr);
		goto done;
	}

	/* Setup advertising register */
	if (speeds & LINK_FULL_100BASE) {
		anar |= MII_ADVERTISE_100_FULL;
	} else {
		anar &= ~MII_ADVERTISE_100_FULL;
	}
	if (speeds & LINK_HALF_100BASE) {
		anar |= MII_ADVERTISE_100_HALF;
	} else {
		anar &= ~MII_ADVERTISE_100_HALF;
	}
	if (speeds & LINK_FULL_10BASE) {
		anar |= MII_ADVERTISE_10_FULL;
	} else {
		anar &= ~MII_ADVERTISE_10_FULL;
	}
	if (speeds & LINK_HALF_10BASE) {
		anar |= MII_ADVERTISE_10_HALF;
	} else {
		anar &= ~MII_ADVERTISE_10_HALF;
	}

	/* Write capabilities to advertising register */
	ret = phy_mc_ksz8081_write(dev, MII_ANAR, anar);
	if (ret) {
		LOG_ERR("Error writing phy (%d) advertising register", config->addr);
	ret = phy_mii_set_anar_reg(dev, speeds);
	if ((ret < 0) && (ret != -EALREADY)) {
		LOG_ERR("Error setting ANAR register for phy (%d)", config->addr);
		goto done;
	}

+14 −65
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(phy_mii, CONFIG_PHY_LOG_LEVEL);

#include "phy_mii.h"

#define ANY_DYNAMIC_LINK UTIL_NOT(DT_ALL_INST_HAS_PROP_STATUS_OKAY(fixed_link))
#define ANY_FIXED_LINK   DT_ANY_INST_HAS_PROP_STATUS_OKAY(fixed_link)

@@ -350,11 +352,7 @@ static int phy_mii_cfg_link(const struct device *dev,
{
	struct phy_mii_dev_data *const data = dev->data;
	const struct phy_mii_dev_config *const cfg = dev->config;
	uint16_t anar_reg;
	uint16_t anar_reg_old;
	uint16_t bmcr_reg;
	uint16_t c1kt_reg;
	uint16_t c1kt_reg_old;
	int ret = 0;

	/* if there is no mdio (fixed-link) it is not supported to configure link */
@@ -368,79 +366,30 @@ static int phy_mii_cfg_link(const struct device *dev,

	k_sem_take(&data->sem, K_FOREVER);

	if (phy_mii_reg_read(dev, MII_ANAR, &anar_reg) < 0) {
		ret = -EIO;
		goto cfg_link_end;
	}
	anar_reg_old = anar_reg;

	if (phy_mii_reg_read(dev, MII_BMCR, &bmcr_reg) < 0) {
		ret = -EIO;
		goto cfg_link_end;
	}

	if (data->gigabit_supported) {
		if (phy_mii_reg_read(dev, MII_1KTCR, &c1kt_reg) < 0) {
			ret = -EIO;
		ret = phy_mii_set_c1kt_reg(dev, adv_speeds);
		if (ret == -EALREADY) {
			/* If the C1KT register is already set, we don't need to do anything */
			ret = 0;
		} else if (ret < 0) {
			goto cfg_link_end;
		}
	}

	if (adv_speeds & LINK_FULL_10BASE) {
		anar_reg |= MII_ADVERTISE_10_FULL;
	} else {
		anar_reg &= ~MII_ADVERTISE_10_FULL;
	}

	if (adv_speeds & LINK_HALF_10BASE) {
		anar_reg |= MII_ADVERTISE_10_HALF;
	} else {
		anar_reg &= ~MII_ADVERTISE_10_HALF;
	}

	if (adv_speeds & LINK_FULL_100BASE) {
		anar_reg |= MII_ADVERTISE_100_FULL;
	} else {
		anar_reg &= ~MII_ADVERTISE_100_FULL;
	}

	if (adv_speeds & LINK_HALF_100BASE) {
		anar_reg |= MII_ADVERTISE_100_HALF;
	} else {
		anar_reg &= ~MII_ADVERTISE_100_HALF;
	}

	if (data->gigabit_supported) {
		c1kt_reg_old = c1kt_reg;

		if (adv_speeds & LINK_FULL_1000BASE) {
			c1kt_reg |= MII_ADVERTISE_1000_FULL;
		} else {
			c1kt_reg &= ~MII_ADVERTISE_1000_FULL;
		}

		if (adv_speeds & LINK_HALF_1000BASE) {
			c1kt_reg |= MII_ADVERTISE_1000_HALF;
		} else {
			c1kt_reg &= ~MII_ADVERTISE_1000_HALF;
		}

		if (c1kt_reg != c1kt_reg_old) {
			if (phy_mii_reg_write(dev, MII_1KTCR, c1kt_reg) < 0) {
				ret = -EIO;
				goto cfg_link_end;
			}

			data->restart_autoneg = true;
		}
	}

	if (anar_reg != anar_reg_old) {
		if (phy_mii_reg_write(dev, MII_ANAR, anar_reg) < 0) {
			ret = -EIO;
	ret = phy_mii_set_anar_reg(dev, adv_speeds);
	if (ret == -EALREADY) {
		/* If the ANAR register is already set, we don't need to do anything */
		ret = 0;
	} else if (ret < 0) {
		goto cfg_link_end;
		}

	} else {
		data->restart_autoneg = true;
	}

+63 −0
Original line number Diff line number Diff line
/*
 * Copyright The Zephyr Project Contributors
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef ZEPHYR_PHY_MII_H_
#define ZEPHYR_PHY_MII_H_

#include <zephyr/device.h>
#include <zephyr/net/phy.h>
#include <zephyr/net/mii.h>

static inline int phy_mii_set_anar_reg(const struct device *dev, enum phy_link_speed adv_speeds)
{
	uint32_t anar_reg = 0U;
	uint32_t anar_reg_old;

	if (phy_read(dev, MII_ANAR, &anar_reg) < 0) {
		return -EIO;
	}
	anar_reg_old = anar_reg;

	WRITE_BIT(anar_reg, MII_ADVERTISE_10_FULL_BIT, (adv_speeds & LINK_FULL_10BASE) != 0U);
	WRITE_BIT(anar_reg, MII_ADVERTISE_10_HALF_BIT, (adv_speeds & LINK_HALF_10BASE) != 0U);
	WRITE_BIT(anar_reg, MII_ADVERTISE_100_FULL_BIT, (adv_speeds & LINK_FULL_100BASE) != 0U);
	WRITE_BIT(anar_reg, MII_ADVERTISE_100_HALF_BIT, (adv_speeds & LINK_HALF_100BASE) != 0U);

	if (anar_reg == anar_reg_old) {
		return -EALREADY;
	}

	if (phy_write(dev, MII_ANAR, anar_reg) < 0) {
		return -EIO;
	}

	return 0;
}

static inline int phy_mii_set_c1kt_reg(const struct device *dev, enum phy_link_speed adv_speeds)
{
	uint32_t c1kt_reg = 0U;
	uint32_t c1kt_reg_old;

	if (phy_read(dev, MII_1KTCR, &c1kt_reg) < 0) {
		return -EIO;
	}
	c1kt_reg_old = c1kt_reg;

	WRITE_BIT(c1kt_reg, MII_ADVERTISE_1000_FULL_BIT, (adv_speeds & LINK_FULL_1000BASE) != 0U);
	WRITE_BIT(c1kt_reg, MII_ADVERTISE_1000_HALF_BIT, (adv_speeds & LINK_HALF_1000BASE) != 0U);

	if (c1kt_reg == c1kt_reg_old) {
		return -EALREADY;
	}

	if (phy_write(dev, MII_1KTCR, c1kt_reg) < 0) {
		return -EIO;
	}

	return 0;
}
#endif /* ZEPHYR_PHY_MII_H_ */
+6 −48
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(phy_qc_ar8031, CONFIG_PHY_LOG_LEVEL);

#include "phy_mii.h"

#define AR8031_PHY_ID1           0x004DU
#define PHY_READID_TIMEOUT_COUNT 1000U

@@ -255,68 +257,24 @@ static void monitor_work_handler(struct k_work *work)

static int qc_ar8031_cfg_link(const struct device *dev, enum phy_link_speed adv_speeds)
{
	uint32_t anar_reg;
	uint32_t bmcr_reg;
	uint32_t c1kt_reg;

	if (qc_ar8031_read(dev, MII_ANAR, &anar_reg) < 0) {
		return -EIO;
	}

	if (qc_ar8031_read(dev, MII_BMCR, &bmcr_reg) < 0) {
		return -EIO;
	}

	if (qc_ar8031_read(dev, MII_1KTCR, &c1kt_reg) < 0) {
	ret = phy_mii_set_anar_reg(dev, speeds);
	if ((ret < 0) && (ret != -EALREADY)) {
		return -EIO;
	}

	if (adv_speeds & LINK_FULL_10BASE) {
		anar_reg |= MII_ADVERTISE_10_FULL;
	} else {
		anar_reg &= ~MII_ADVERTISE_10_FULL;
	}

	if (adv_speeds & LINK_HALF_10BASE) {
		anar_reg |= MII_ADVERTISE_10_HALF;
	} else {
		anar_reg &= ~MII_ADVERTISE_10_HALF;
	}

	if (adv_speeds & LINK_FULL_100BASE) {
		anar_reg |= MII_ADVERTISE_100_FULL;
	} else {
		anar_reg &= ~MII_ADVERTISE_100_FULL;
	}

	if (adv_speeds & LINK_HALF_100BASE) {
		anar_reg |= MII_ADVERTISE_100_HALF;
	} else {
		anar_reg &= ~MII_ADVERTISE_100_HALF;
	}

	if (adv_speeds & LINK_FULL_1000BASE) {
		c1kt_reg |= MII_ADVERTISE_1000_FULL;
	} else {
		c1kt_reg &= ~MII_ADVERTISE_1000_FULL;
	}

	if (adv_speeds & LINK_HALF_1000BASE) {
		c1kt_reg |= MII_ADVERTISE_1000_HALF;
	} else {
		c1kt_reg &= ~MII_ADVERTISE_1000_HALF;
	}

	if (qc_ar8031_write(dev, MII_1KTCR, c1kt_reg) < 0) {
	ret = phy_mii_set_c1kt_reg(dev, speeds);
	if ((ret < 0) && (ret != -EALREADY)) {
		return -EIO;
	}

	bmcr_reg |= MII_BMCR_AUTONEG_ENABLE | MII_BMCR_AUTONEG_RESTART;

	if (qc_ar8031_write(dev, MII_ANAR, anar_reg) < 0) {
		return -EIO;
	}

	if (qc_ar8031_write(dev, MII_BMCR, bmcr_reg) < 0) {
		return -EIO;
	}
+8 −53
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(LOG_MODULE_NAME);

#include "phy_mii.h"

#define REALTEK_OUI_MSB (0x1CU)

#define PHY_RT_RTL8211F_PHYSR_REG (0x1A)
@@ -283,8 +285,6 @@ static int phy_rt_rtl8211f_cfg_link(const struct device *dev,
{
	const struct rt_rtl8211f_config *config = dev->config;
	struct rt_rtl8211f_data *data = dev->data;
	uint32_t anar;
	uint32_t gbcr;
	int ret;

	/* Lock mutex */
@@ -303,60 +303,15 @@ static int phy_rt_rtl8211f_cfg_link(const struct device *dev,
	k_work_cancel_delayable(&data->phy_monitor_work);
#endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */

	/* Read ANAR register to write back */
	ret = phy_rt_rtl8211f_read(dev, MII_ANAR, &anar);
	if (ret) {
		LOG_ERR("Error reading phy (%d) advertising register", config->addr);
		goto done;
	}

	/* Read GBCR register to write back */
	ret = phy_rt_rtl8211f_read(dev, MII_1KTCR, &gbcr);
	if (ret) {
		LOG_ERR("Error reading phy (%d) 1000Base-T control register", config->addr);
	ret = phy_mii_set_anar_reg(dev, speeds);
	if (ret < 0 && ret != -EALREADY) {
		LOG_ERR("Error setting ANAR register for phy (%d)", config->addr);
		goto done;
	}

	/* Setup advertising register */
	if (speeds & LINK_FULL_100BASE) {
		anar |= MII_ADVERTISE_100_FULL;
	} else {
		anar &= ~MII_ADVERTISE_100_FULL;
	}
	if (speeds & LINK_HALF_100BASE) {
		anar |= MII_ADVERTISE_100_HALF;
	} else {
		anar &= ~MII_ADVERTISE_100_HALF;
	}
	if (speeds & LINK_FULL_10BASE) {
		anar |= MII_ADVERTISE_10_FULL;
	} else {
		anar &= ~MII_ADVERTISE_10_FULL;
	}
	if (speeds & LINK_HALF_10BASE) {
		anar |= MII_ADVERTISE_10_HALF;
	} else {
		anar &= ~MII_ADVERTISE_10_HALF;
	}

	/* Setup 1000Base-T control register */
	if (speeds & LINK_FULL_1000BASE) {
		gbcr |= MII_ADVERTISE_1000_FULL;
	} else {
		gbcr &= ~MII_ADVERTISE_1000_FULL;
	}

	/* Write capabilities to advertising register */
	ret = phy_rt_rtl8211f_write(dev, MII_ANAR, anar);
	if (ret) {
		LOG_ERR("Error writing phy (%d) advertising register", config->addr);
		goto done;
	}

	/* Write capabilities to 1000Base-T control register */
	ret = phy_rt_rtl8211f_write(dev, MII_1KTCR, gbcr);
	if (ret) {
		LOG_ERR("Error writing phy (%d) 1000Base-T control register", config->addr);
	ret = phy_mii_set_c1kt_reg(dev, speeds);
	if (ret < 0 && ret != -EALREADY) {
		LOG_ERR("Error setting C1KT register for phy (%d)", config->addr);
		goto done;
	}

Loading