Commit 638c1152 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'adin-add-support-for-clock-output'

Josua Mayer says:

====================
adin: add support for clock output

This patch series adds support for configuring the two clock outputs of adin
1200 and 1300 PHYs. Certain network controllers require an external reference
clock which can be provided by the PHY.

One of the replies to v1 was asking why the common clock framework isn't used.
Currently no PHY driver has implemented providing a clock to the network
controller. Instead they rely on vendor extensions to make the appropriate
configuration. For example ar8035 uses qca,clk-out-frequency - this patchset
aimed to replicate the same functionality.

Finally the 125MHz free-running clock is enabled in the device-tree for
SolidRun i.MX6 SoMs, to support revisions 1.9 and later, where the original phy
has been replaced with an adin 1300.
To avoid introducing new warning messages during boot for SoMs before rev 1.9,
the status field of the new phy node is disabled by default, and will be
enabled by U-Boot on demand.
====================

Link: https://lore.kernel.org/r/20220517085143.3749-1-josua@solid-run.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents a3641ca4 654cd222
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -36,6 +36,21 @@ properties:
    enum: [ 4, 8, 12, 16, 20, 24 ]
    default: 8

  adi,phy-output-clock:
    description: Select clock output on GP_CLK pin. Two clocks are available:
      A 25MHz reference and a free-running 125MHz.
      The phy can alternatively automatically switch between the reference and
      the 125MHz clocks based on its internal state.
    $ref: /schemas/types.yaml#/definitions/string
    enum:
      - 25mhz-reference
      - 125mhz-free-running
      - adaptive-free-running

  adi,phy-output-reference-clock:
    description: Enable 25MHz reference clock output on CLK25_REF pin.
    type: boolean

unevaluatedProperties: false

examples:
+10 −0
Original line number Diff line number Diff line
@@ -83,6 +83,16 @@
			qca,clk-out-frequency = <125000000>;
			qca,smarteee-tw-us-1g = <24>;
		};

		/*
		 * ADIN1300 (som rev 1.9 or later) is always at address 1. It
		 * will be enabled automatically by U-Boot if detected.
		 */
		ethernet-phy@1 {
			reg = <1>;
			adi,phy-output-clock = "125mhz-free-running";
			status = "disabled";
		};
	};
};

+40 −0
Original line number Diff line number Diff line
@@ -99,6 +99,15 @@
#define ADIN1300_GE_SOFT_RESET_REG		0xff0c
#define   ADIN1300_GE_SOFT_RESET		BIT(0)

#define ADIN1300_GE_CLK_CFG_REG			0xff1f
#define   ADIN1300_GE_CLK_CFG_MASK		GENMASK(5, 0)
#define   ADIN1300_GE_CLK_CFG_RCVR_125		BIT(5)
#define   ADIN1300_GE_CLK_CFG_FREE_125		BIT(4)
#define   ADIN1300_GE_CLK_CFG_REF_EN		BIT(3)
#define   ADIN1300_GE_CLK_CFG_HRT_RCVR		BIT(2)
#define   ADIN1300_GE_CLK_CFG_HRT_FREE		BIT(1)
#define   ADIN1300_GE_CLK_CFG_25		BIT(0)

#define ADIN1300_GE_RGMII_CFG_REG		0xff23
#define   ADIN1300_GE_RGMII_RX_MSK		GENMASK(8, 6)
#define   ADIN1300_GE_RGMII_RX_SEL(x)		\
@@ -433,6 +442,33 @@ static int adin_set_tunable(struct phy_device *phydev,
	}
}

static int adin_config_clk_out(struct phy_device *phydev)
{
	struct device *dev = &phydev->mdio.dev;
	const char *val = NULL;
	u8 sel = 0;

	device_property_read_string(dev, "adi,phy-output-clock", &val);
	if (!val) {
		/* property not present, do not enable GP_CLK pin */
	} else if (strcmp(val, "25mhz-reference") == 0) {
		sel |= ADIN1300_GE_CLK_CFG_25;
	} else if (strcmp(val, "125mhz-free-running") == 0) {
		sel |= ADIN1300_GE_CLK_CFG_FREE_125;
	} else if (strcmp(val, "adaptive-free-running") == 0) {
		sel |= ADIN1300_GE_CLK_CFG_HRT_FREE;
	} else {
		phydev_err(phydev, "invalid adi,phy-output-clock\n");
		return -EINVAL;
	}

	if (device_property_read_bool(dev, "adi,phy-output-reference-clock"))
		sel |= ADIN1300_GE_CLK_CFG_REF_EN;

	return phy_modify_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_GE_CLK_CFG_REG,
			      ADIN1300_GE_CLK_CFG_MASK, sel);
}

static int adin_config_init(struct phy_device *phydev)
{
	int rc;
@@ -455,6 +491,10 @@ static int adin_config_init(struct phy_device *phydev)
	if (rc < 0)
		return rc;

	rc = adin_config_clk_out(phydev);
	if (rc < 0)
		return rc;

	phydev_dbg(phydev, "PHY is using mode '%s'\n",
		   phy_modes(phydev->interface));