Commit 16cf4222 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-phy-at803x-device-tree-binding'



Michael Walle says:

====================
net: phy: at803x device tree binding

Adds a device tree binding to configure the clock and the RGMII voltage.

Changes since v1:
 - rebased to latest net-next
 - renamed "Atheros" to "Qualcomm Atheros"
 - add a new patch to remove config_init() from AR9331

Changes since the RFC:
 - renamed the Kconfig entry to "Qualcomm Atheros.." and reordered the
   item
 - renamed the prefix from atheros to qca
 - use the correct name AR803x (instead of AT803x) in new files and
   dt-bindings.
 - listed the PHY maintainers in the new schema. Hopefully, thats ok.
 - fixed a typo in the bindings schema
 - run dtb_checks and dt_binding_check and fixed the schema
 - dropped the rgmii-io-1v8 property; instead provide two regulators vddh
   and vddio, add one consumer vddio-supply
 - fix the clock settings for the AR8030/AR8035
 - only the AR8031 supports chaning the LDO and the PLL mode in software.
   Check if we have the correct PHY.
 - new patch to mention the AR8033 which is the same as the AR8031 just
   without PTP support
 - new patch which corrects any displayed PHY names and comments. Be
   consistent.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a5a7daa5 ed7fa2ad
Loading
Loading
Loading
Loading
+111 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0+
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/qca,ar803x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Qualcomm Atheros AR803x PHY

maintainers:
  - Andrew Lunn <andrew@lunn.ch>
  - Florian Fainelli <f.fainelli@gmail.com>
  - Heiner Kallweit <hkallweit1@gmail.com>

description: |
  Bindings for Qualcomm Atheros AR803x PHYs

allOf:
  - $ref: ethernet-phy.yaml#

properties:
  qca,clk-out-frequency:
    description: Clock output frequency in Hertz.
    allOf:
      - $ref: /schemas/types.yaml#/definitions/uint32
      - enum: [ 25000000, 50000000, 62500000, 125000000 ]

  qca,clk-out-strength:
    description: Clock output driver strength.
    allOf:
      - $ref: /schemas/types.yaml#/definitions/uint32
      - enum: [ 0, 1, 2 ]

  qca,keep-pll-enabled:
    description: |
      If set, keep the PLL enabled even if there is no link. Useful if you
      want to use the clock output without an ethernet link.

      Only supported on the AR8031.
    type: boolean

  vddio-supply:
    description: |
      RGMII I/O voltage regulator (see regulator/regulator.yaml).

      The PHY supports RGMII I/O voltages of 1.5V, 1.8V and 2.5V. You can
      either connect this to the vddio-regulator (1.5V / 1.8V) or the
      vddh-regulator (2.5V).

      Only supported on the AR8031.

  vddio-regulator:
    type: object
    description:
      Initial data for the VDDIO regulator. Set this to 1.5V or 1.8V.
    allOf:
      - $ref: /schemas/regulator/regulator.yaml

  vddh-regulator:
    type: object
    description:
      Dummy subnode to model the external connection of the PHY VDDH
      regulator to VDDIO.
    allOf:
      - $ref: /schemas/regulator/regulator.yaml


examples:
  - |
    #include <dt-bindings/net/qca-ar803x.h>

    ethernet {
        #address-cells = <1>;
        #size-cells = <0>;

        phy-mode = "rgmii-id";

        ethernet-phy@0 {
            reg = <0>;

            qca,clk-out-frequency = <125000000>;
            qca,clk-out-strength = <AR803X_STRENGTH_FULL>;

            vddio-supply = <&vddio>;

            vddio: vddio-regulator {
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
            };
        };
    };
  - |
    #include <dt-bindings/net/qca-ar803x.h>

    ethernet {
        #address-cells = <1>;
        #size-cells = <0>;

        phy-mode = "rgmii-id";

        ethernet-phy@0 {
            reg = <0>;

            qca,clk-out-frequency = <50000000>;
            qca,keep-pll-enabled;

            vddio-supply = <&vddh>;

            vddh: vddh-regulator {
            };
        };
    };
+2 −0
Original line number Diff line number Diff line
@@ -6155,10 +6155,12 @@ S: Maintained
F:	Documentation/ABI/testing/sysfs-class-net-phydev
F:	Documentation/devicetree/bindings/net/ethernet-phy.yaml
F:	Documentation/devicetree/bindings/net/mdio*
F:	Documentation/devicetree/bindings/net/qca,ar803x.yaml
F:	Documentation/networking/phy.rst
F:	drivers/net/phy/
F:	drivers/of/of_mdio.c
F:	drivers/of/of_net.c
F:	include/dt-bindings/net/qca-ar803x.h
F:	include/linux/*mdio*.h
F:	include/linux/of_net.h
F:	include/linux/phy.h
+5 −5
Original line number Diff line number Diff line
@@ -282,11 +282,6 @@ config AX88796B_PHY
	  Currently supports the Asix Electronics PHY found in the X-Surf 100
	  AX88796B package.

config AT803X_PHY
	tristate "AT803X PHYs"
	---help---
	  Currently supports the AT8030 and AT8035 model

config BCM63XX_PHY
	tristate "Broadcom 63xx SOCs internal PHY"
	depends on BCM63XX || COMPILE_TEST
@@ -444,6 +439,11 @@ config NXP_TJA11XX_PHY
	---help---
	  Currently supports the NXP TJA1100 and TJA1101 PHY.

config AT803X_PHY
	tristate "Qualcomm Atheros AR803X PHYs"
	help
	  Currently supports the AR8030, AR8031, AR8033 and AR8035 model

config QSEMI_PHY
	tristate "Quality Semiconductor PHYs"
	---help---
+310 −11
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
/*
 * drivers/net/phy/at803x.c
 *
 * Driver for Atheros 803x PHY
 * Driver for Qualcomm Atheros AR803x PHY
 *
 * Author: Matus Ujhelyi <ujhelyi.m@gmail.com>
 */
@@ -13,7 +13,12 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/of_gpio.h>
#include <linux/bitfield.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/consumer.h>
#include <dt-bindings/net/qca-ar803x.h>

#define AT803X_SPECIFIC_STATUS			0x11
#define AT803X_SS_SPEED_MASK			(3 << 14)
@@ -62,16 +67,62 @@
#define AT803X_DEBUG_REG_5			0x05
#define AT803X_DEBUG_TX_CLK_DLY_EN		BIT(8)

#define AT803X_DEBUG_REG_1F			0x1F
#define AT803X_DEBUG_PLL_ON			BIT(2)
#define AT803X_DEBUG_RGMII_1V8			BIT(3)

/* AT803x supports either the XTAL input pad, an internal PLL or the
 * DSP as clock reference for the clock output pad. The XTAL reference
 * is only used for 25 MHz output, all other frequencies need the PLL.
 * The DSP as a clock reference is used in synchronous ethernet
 * applications.
 *
 * By default the PLL is only enabled if there is a link. Otherwise
 * the PHY will go into low power state and disabled the PLL. You can
 * set the PLL_ON bit (see debug register 0x1f) to keep the PLL always
 * enabled.
 */
#define AT803X_MMD7_CLK25M			0x8016
#define AT803X_CLK_OUT_MASK			GENMASK(4, 2)
#define AT803X_CLK_OUT_25MHZ_XTAL		0
#define AT803X_CLK_OUT_25MHZ_DSP		1
#define AT803X_CLK_OUT_50MHZ_PLL		2
#define AT803X_CLK_OUT_50MHZ_DSP		3
#define AT803X_CLK_OUT_62_5MHZ_PLL		4
#define AT803X_CLK_OUT_62_5MHZ_DSP		5
#define AT803X_CLK_OUT_125MHZ_PLL		6
#define AT803X_CLK_OUT_125MHZ_DSP		7

/* The AR8035 has another mask which is compatible with the AR8031/AR8033 mask
 * but doesn't support choosing between XTAL/PLL and DSP.
 */
#define AT8035_CLK_OUT_MASK			GENMASK(4, 3)

#define AT803X_CLK_OUT_STRENGTH_MASK		GENMASK(8, 7)
#define AT803X_CLK_OUT_STRENGTH_FULL		0
#define AT803X_CLK_OUT_STRENGTH_HALF		1
#define AT803X_CLK_OUT_STRENGTH_QUARTER		2

#define ATH9331_PHY_ID 0x004dd041
#define ATH8030_PHY_ID 0x004dd076
#define ATH8031_PHY_ID 0x004dd074
#define ATH8035_PHY_ID 0x004dd072
#define AT803X_PHY_ID_MASK			0xffffffef

MODULE_DESCRIPTION("Atheros 803x PHY driver");
MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver");
MODULE_AUTHOR("Matus Ujhelyi");
MODULE_LICENSE("GPL");

struct at803x_priv {
	int flags;
#define AT803X_KEEP_PLL_ENABLED	BIT(0)	/* don't turn off internal PLL */
	u16 clk_25m_reg;
	u16 clk_25m_mask;
	struct regulator_dev *vddio_rdev;
	struct regulator_dev *vddh_rdev;
	struct regulator *vddio;
};

struct at803x_context {
	u16 bmcr;
	u16 advertise;
@@ -237,6 +288,240 @@ static int at803x_resume(struct phy_device *phydev)
	return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
}

static int at803x_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
					    unsigned int selector)
{
	struct phy_device *phydev = rdev_get_drvdata(rdev);

	if (selector)
		return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
					     0, AT803X_DEBUG_RGMII_1V8);
	else
		return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
					     AT803X_DEBUG_RGMII_1V8, 0);
}

static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
{
	struct phy_device *phydev = rdev_get_drvdata(rdev);
	int val;

	val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
	if (val < 0)
		return val;

	return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
}

static struct regulator_ops vddio_regulator_ops = {
	.list_voltage = regulator_list_voltage_table,
	.set_voltage_sel = at803x_rgmii_reg_set_voltage_sel,
	.get_voltage_sel = at803x_rgmii_reg_get_voltage_sel,
};

static const unsigned int vddio_voltage_table[] = {
	1500000,
	1800000,
};

static const struct regulator_desc vddio_desc = {
	.name = "vddio",
	.of_match = of_match_ptr("vddio-regulator"),
	.n_voltages = ARRAY_SIZE(vddio_voltage_table),
	.volt_table = vddio_voltage_table,
	.ops = &vddio_regulator_ops,
	.type = REGULATOR_VOLTAGE,
	.owner = THIS_MODULE,
};

static struct regulator_ops vddh_regulator_ops = {
};

static const struct regulator_desc vddh_desc = {
	.name = "vddh",
	.of_match = of_match_ptr("vddh-regulator"),
	.n_voltages = 1,
	.fixed_uV = 2500000,
	.ops = &vddh_regulator_ops,
	.type = REGULATOR_VOLTAGE,
	.owner = THIS_MODULE,
};

static int at8031_register_regulators(struct phy_device *phydev)
{
	struct at803x_priv *priv = phydev->priv;
	struct device *dev = &phydev->mdio.dev;
	struct regulator_config config = { };

	config.dev = dev;
	config.driver_data = phydev;

	priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
	if (IS_ERR(priv->vddio_rdev)) {
		phydev_err(phydev, "failed to register VDDIO regulator\n");
		return PTR_ERR(priv->vddio_rdev);
	}

	priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
	if (IS_ERR(priv->vddh_rdev)) {
		phydev_err(phydev, "failed to register VDDH regulator\n");
		return PTR_ERR(priv->vddh_rdev);
	}

	return 0;
}

static bool at803x_match_phy_id(struct phy_device *phydev, u32 phy_id)
{
	return (phydev->phy_id & phydev->drv->phy_id_mask)
		== (phy_id & phydev->drv->phy_id_mask);
}

static int at803x_parse_dt(struct phy_device *phydev)
{
	struct device_node *node = phydev->mdio.dev.of_node;
	struct at803x_priv *priv = phydev->priv;
	unsigned int sel, mask;
	u32 freq, strength;
	int ret;

	if (!IS_ENABLED(CONFIG_OF_MDIO))
		return 0;

	ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq);
	if (!ret) {
		mask = AT803X_CLK_OUT_MASK;
		switch (freq) {
		case 25000000:
			sel = AT803X_CLK_OUT_25MHZ_XTAL;
			break;
		case 50000000:
			sel = AT803X_CLK_OUT_50MHZ_PLL;
			break;
		case 62500000:
			sel = AT803X_CLK_OUT_62_5MHZ_PLL;
			break;
		case 125000000:
			sel = AT803X_CLK_OUT_125MHZ_PLL;
			break;
		default:
			phydev_err(phydev, "invalid qca,clk-out-frequency\n");
			return -EINVAL;
		}

		priv->clk_25m_reg |= FIELD_PREP(mask, sel);
		priv->clk_25m_mask |= mask;

		/* Fixup for the AR8030/AR8035. This chip has another mask and
		 * doesn't support the DSP reference. Eg. the lowest bit of the
		 * mask. The upper two bits select the same frequencies. Mask
		 * the lowest bit here.
		 *
		 * Warning:
		 *   There was no datasheet for the AR8030 available so this is
		 *   just a guess. But the AR8035 is listed as pin compatible
		 *   to the AR8030 so there might be a good chance it works on
		 *   the AR8030 too.
		 */
		if (at803x_match_phy_id(phydev, ATH8030_PHY_ID) ||
		    at803x_match_phy_id(phydev, ATH8035_PHY_ID)) {
			priv->clk_25m_reg &= ~AT8035_CLK_OUT_MASK;
			priv->clk_25m_mask &= ~AT8035_CLK_OUT_MASK;
		}
	}

	ret = of_property_read_u32(node, "qca,clk-out-strength", &strength);
	if (!ret) {
		priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK;
		switch (strength) {
		case AR803X_STRENGTH_FULL:
			priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL;
			break;
		case AR803X_STRENGTH_HALF:
			priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF;
			break;
		case AR803X_STRENGTH_QUARTER:
			priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER;
			break;
		default:
			phydev_err(phydev, "invalid qca,clk-out-strength\n");
			return -EINVAL;
		}
	}

	/* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
	 * options.
	 */
	if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) {
		if (of_property_read_bool(node, "qca,keep-pll-enabled"))
			priv->flags |= AT803X_KEEP_PLL_ENABLED;

		ret = at8031_register_regulators(phydev);
		if (ret < 0)
			return ret;

		priv->vddio = devm_regulator_get_optional(&phydev->mdio.dev,
							  "vddio");
		if (IS_ERR(priv->vddio)) {
			phydev_err(phydev, "failed to get VDDIO regulator\n");
			return PTR_ERR(priv->vddio);
		}

		ret = regulator_enable(priv->vddio);
		if (ret < 0)
			return ret;
	}

	return 0;
}

static int at803x_probe(struct phy_device *phydev)
{
	struct device *dev = &phydev->mdio.dev;
	struct at803x_priv *priv;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	phydev->priv = priv;

	return at803x_parse_dt(phydev);
}

static int at803x_clk_out_config(struct phy_device *phydev)
{
	struct at803x_priv *priv = phydev->priv;
	int val;

	if (!priv->clk_25m_mask)
		return 0;

	val = phy_read_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M);
	if (val < 0)
		return val;

	val &= ~priv->clk_25m_mask;
	val |= priv->clk_25m_reg;

	return phy_write_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M, val);
}

static int at8031_pll_config(struct phy_device *phydev)
{
	struct at803x_priv *priv = phydev->priv;

	/* The default after hardware reset is PLL OFF. After a soft reset, the
	 * values are retained.
	 */
	if (priv->flags & AT803X_KEEP_PLL_ENABLED)
		return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
					     0, AT803X_DEBUG_PLL_ON);
	else
		return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
					     AT803X_DEBUG_PLL_ON, 0);
}

static int at803x_config_init(struct phy_device *phydev)
{
	int ret;
@@ -259,8 +544,20 @@ static int at803x_config_init(struct phy_device *phydev)
		ret = at803x_enable_tx_delay(phydev);
	else
		ret = at803x_disable_tx_delay(phydev);
	if (ret < 0)
		return ret;

	ret = at803x_clk_out_config(phydev);
	if (ret < 0)
		return ret;

	if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) {
		ret = at8031_pll_config(phydev);
		if (ret < 0)
			return ret;
	}

	return 0;
}

static int at803x_ack_interrupt(struct phy_device *phydev)
@@ -409,10 +706,11 @@ static int at803x_read_status(struct phy_device *phydev)

static struct phy_driver at803x_driver[] = {
{
	/* ATHEROS 8035 */
	/* Qualcomm Atheros AR8035 */
	.phy_id			= ATH8035_PHY_ID,
	.name			= "Atheros 8035 ethernet",
	.name			= "Qualcomm Atheros AR8035",
	.phy_id_mask		= AT803X_PHY_ID_MASK,
	.probe			= at803x_probe,
	.config_init		= at803x_config_init,
	.set_wol		= at803x_set_wol,
	.get_wol		= at803x_get_wol,
@@ -423,10 +721,11 @@ static struct phy_driver at803x_driver[] = {
	.ack_interrupt		= at803x_ack_interrupt,
	.config_intr		= at803x_config_intr,
}, {
	/* ATHEROS 8030 */
	/* Qualcomm Atheros AR8030 */
	.phy_id			= ATH8030_PHY_ID,
	.name			= "Atheros 8030 ethernet",
	.name			= "Qualcomm Atheros AR8030",
	.phy_id_mask		= AT803X_PHY_ID_MASK,
	.probe			= at803x_probe,
	.config_init		= at803x_config_init,
	.link_change_notify	= at803x_link_change_notify,
	.set_wol		= at803x_set_wol,
@@ -437,10 +736,11 @@ static struct phy_driver at803x_driver[] = {
	.ack_interrupt		= at803x_ack_interrupt,
	.config_intr		= at803x_config_intr,
}, {
	/* ATHEROS 8031 */
	/* Qualcomm Atheros AR8031/AR8033 */
	.phy_id			= ATH8031_PHY_ID,
	.name			= "Atheros 8031 ethernet",
	.name			= "Qualcomm Atheros AR8031/AR8033",
	.phy_id_mask		= AT803X_PHY_ID_MASK,
	.probe			= at803x_probe,
	.config_init		= at803x_config_init,
	.set_wol		= at803x_set_wol,
	.get_wol		= at803x_get_wol,
@@ -454,8 +754,7 @@ static struct phy_driver at803x_driver[] = {
}, {
	/* ATHEROS AR9331 */
	PHY_ID_MATCH_EXACT(ATH9331_PHY_ID),
	.name			= "Atheros AR9331 built-in PHY",
	.config_init		= at803x_config_init,
	.name			= "Qualcomm Atheros AR9331 built-in PHY",
	.suspend		= at803x_suspend,
	.resume			= at803x_resume,
	/* PHY_BASIC_FEATURES */
+13 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Device Tree constants for the Qualcomm Atheros AR803x PHYs
 */

#ifndef _DT_BINDINGS_QCA_AR803X_H
#define _DT_BINDINGS_QCA_AR803X_H

#define AR803X_STRENGTH_FULL		0
#define AR803X_STRENGTH_HALF		1
#define AR803X_STRENGTH_QUARTER		2

#endif