162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause
262306a36Sopenharmony_ci/* Copyright 2016-2018 NXP
362306a36Sopenharmony_ci * Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#include <linux/packing.h>
662306a36Sopenharmony_ci#include "sja1105.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define SJA1105_SIZE_CGU_CMD	4
962306a36Sopenharmony_ci#define SJA1110_BASE_MCSS_CLK	SJA1110_CGU_ADDR(0x70)
1062306a36Sopenharmony_ci#define SJA1110_BASE_TIMER_CLK	SJA1110_CGU_ADDR(0x74)
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/* Common structure for CFG_PAD_MIIx_RX and CFG_PAD_MIIx_TX */
1362306a36Sopenharmony_cistruct sja1105_cfg_pad_mii {
1462306a36Sopenharmony_ci	u64 d32_os;
1562306a36Sopenharmony_ci	u64 d32_ih;
1662306a36Sopenharmony_ci	u64 d32_ipud;
1762306a36Sopenharmony_ci	u64 d10_ih;
1862306a36Sopenharmony_ci	u64 d10_os;
1962306a36Sopenharmony_ci	u64 d10_ipud;
2062306a36Sopenharmony_ci	u64 ctrl_os;
2162306a36Sopenharmony_ci	u64 ctrl_ih;
2262306a36Sopenharmony_ci	u64 ctrl_ipud;
2362306a36Sopenharmony_ci	u64 clk_os;
2462306a36Sopenharmony_ci	u64 clk_ih;
2562306a36Sopenharmony_ci	u64 clk_ipud;
2662306a36Sopenharmony_ci};
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct sja1105_cfg_pad_mii_id {
2962306a36Sopenharmony_ci	u64 rxc_stable_ovr;
3062306a36Sopenharmony_ci	u64 rxc_delay;
3162306a36Sopenharmony_ci	u64 rxc_bypass;
3262306a36Sopenharmony_ci	u64 rxc_pd;
3362306a36Sopenharmony_ci	u64 txc_stable_ovr;
3462306a36Sopenharmony_ci	u64 txc_delay;
3562306a36Sopenharmony_ci	u64 txc_bypass;
3662306a36Sopenharmony_ci	u64 txc_pd;
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* UM10944 Table 82.
4062306a36Sopenharmony_ci * IDIV_0_C to IDIV_4_C control registers
4162306a36Sopenharmony_ci * (addr. 10000Bh to 10000Fh)
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_cistruct sja1105_cgu_idiv {
4462306a36Sopenharmony_ci	u64 clksrc;
4562306a36Sopenharmony_ci	u64 autoblock;
4662306a36Sopenharmony_ci	u64 idiv;
4762306a36Sopenharmony_ci	u64 pd;
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/* PLL_1_C control register
5162306a36Sopenharmony_ci *
5262306a36Sopenharmony_ci * SJA1105 E/T: UM10944 Table 81 (address 10000Ah)
5362306a36Sopenharmony_ci * SJA1105 P/Q/R/S: UM11040 Table 116 (address 10000Ah)
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_cistruct sja1105_cgu_pll_ctrl {
5662306a36Sopenharmony_ci	u64 pllclksrc;
5762306a36Sopenharmony_ci	u64 msel;
5862306a36Sopenharmony_ci	u64 autoblock;
5962306a36Sopenharmony_ci	u64 psel;
6062306a36Sopenharmony_ci	u64 direct;
6162306a36Sopenharmony_ci	u64 fbsel;
6262306a36Sopenharmony_ci	u64 bypass;
6362306a36Sopenharmony_ci	u64 pd;
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistruct sja1110_cgu_outclk {
6762306a36Sopenharmony_ci	u64 clksrc;
6862306a36Sopenharmony_ci	u64 autoblock;
6962306a36Sopenharmony_ci	u64 pd;
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cienum {
7362306a36Sopenharmony_ci	CLKSRC_MII0_TX_CLK	= 0x00,
7462306a36Sopenharmony_ci	CLKSRC_MII0_RX_CLK	= 0x01,
7562306a36Sopenharmony_ci	CLKSRC_MII1_TX_CLK	= 0x02,
7662306a36Sopenharmony_ci	CLKSRC_MII1_RX_CLK	= 0x03,
7762306a36Sopenharmony_ci	CLKSRC_MII2_TX_CLK	= 0x04,
7862306a36Sopenharmony_ci	CLKSRC_MII2_RX_CLK	= 0x05,
7962306a36Sopenharmony_ci	CLKSRC_MII3_TX_CLK	= 0x06,
8062306a36Sopenharmony_ci	CLKSRC_MII3_RX_CLK	= 0x07,
8162306a36Sopenharmony_ci	CLKSRC_MII4_TX_CLK	= 0x08,
8262306a36Sopenharmony_ci	CLKSRC_MII4_RX_CLK	= 0x09,
8362306a36Sopenharmony_ci	CLKSRC_PLL0		= 0x0B,
8462306a36Sopenharmony_ci	CLKSRC_PLL1		= 0x0E,
8562306a36Sopenharmony_ci	CLKSRC_IDIV0		= 0x11,
8662306a36Sopenharmony_ci	CLKSRC_IDIV1		= 0x12,
8762306a36Sopenharmony_ci	CLKSRC_IDIV2		= 0x13,
8862306a36Sopenharmony_ci	CLKSRC_IDIV3		= 0x14,
8962306a36Sopenharmony_ci	CLKSRC_IDIV4		= 0x15,
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* UM10944 Table 83.
9362306a36Sopenharmony_ci * MIIx clock control registers 1 to 30
9462306a36Sopenharmony_ci * (addresses 100013h to 100035h)
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_cistruct sja1105_cgu_mii_ctrl {
9762306a36Sopenharmony_ci	u64 clksrc;
9862306a36Sopenharmony_ci	u64 autoblock;
9962306a36Sopenharmony_ci	u64 pd;
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic void sja1105_cgu_idiv_packing(void *buf, struct sja1105_cgu_idiv *idiv,
10362306a36Sopenharmony_ci				     enum packing_op op)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	const int size = 4;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	sja1105_packing(buf, &idiv->clksrc,    28, 24, size, op);
10862306a36Sopenharmony_ci	sja1105_packing(buf, &idiv->autoblock, 11, 11, size, op);
10962306a36Sopenharmony_ci	sja1105_packing(buf, &idiv->idiv,       5,  2, size, op);
11062306a36Sopenharmony_ci	sja1105_packing(buf, &idiv->pd,         0,  0, size, op);
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic int sja1105_cgu_idiv_config(struct sja1105_private *priv, int port,
11462306a36Sopenharmony_ci				   bool enabled, int factor)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
11762306a36Sopenharmony_ci	struct device *dev = priv->ds->dev;
11862306a36Sopenharmony_ci	struct sja1105_cgu_idiv idiv;
11962306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (regs->cgu_idiv[port] == SJA1105_RSV_ADDR)
12262306a36Sopenharmony_ci		return 0;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (enabled && factor != 1 && factor != 10) {
12562306a36Sopenharmony_ci		dev_err(dev, "idiv factor must be 1 or 10\n");
12662306a36Sopenharmony_ci		return -ERANGE;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* Payload for packed_buf */
13062306a36Sopenharmony_ci	idiv.clksrc    = 0x0A;            /* 25MHz */
13162306a36Sopenharmony_ci	idiv.autoblock = 1;               /* Block clk automatically */
13262306a36Sopenharmony_ci	idiv.idiv      = factor - 1;      /* Divide by 1 or 10 */
13362306a36Sopenharmony_ci	idiv.pd        = enabled ? 0 : 1; /* Power down? */
13462306a36Sopenharmony_ci	sja1105_cgu_idiv_packing(packed_buf, &idiv, PACK);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->cgu_idiv[port],
13762306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic void
14162306a36Sopenharmony_cisja1105_cgu_mii_control_packing(void *buf, struct sja1105_cgu_mii_ctrl *cmd,
14262306a36Sopenharmony_ci				enum packing_op op)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	const int size = 4;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->clksrc,    28, 24, size, op);
14762306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->autoblock, 11, 11, size, op);
14862306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->pd,         0,  0, size, op);
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic int sja1105_cgu_mii_tx_clk_config(struct sja1105_private *priv,
15262306a36Sopenharmony_ci					 int port, sja1105_mii_role_t role)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
15562306a36Sopenharmony_ci	struct sja1105_cgu_mii_ctrl mii_tx_clk;
15662306a36Sopenharmony_ci	const int mac_clk_sources[] = {
15762306a36Sopenharmony_ci		CLKSRC_MII0_TX_CLK,
15862306a36Sopenharmony_ci		CLKSRC_MII1_TX_CLK,
15962306a36Sopenharmony_ci		CLKSRC_MII2_TX_CLK,
16062306a36Sopenharmony_ci		CLKSRC_MII3_TX_CLK,
16162306a36Sopenharmony_ci		CLKSRC_MII4_TX_CLK,
16262306a36Sopenharmony_ci	};
16362306a36Sopenharmony_ci	const int phy_clk_sources[] = {
16462306a36Sopenharmony_ci		CLKSRC_IDIV0,
16562306a36Sopenharmony_ci		CLKSRC_IDIV1,
16662306a36Sopenharmony_ci		CLKSRC_IDIV2,
16762306a36Sopenharmony_ci		CLKSRC_IDIV3,
16862306a36Sopenharmony_ci		CLKSRC_IDIV4,
16962306a36Sopenharmony_ci	};
17062306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
17162306a36Sopenharmony_ci	int clksrc;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (regs->mii_tx_clk[port] == SJA1105_RSV_ADDR)
17462306a36Sopenharmony_ci		return 0;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (role == XMII_MAC)
17762306a36Sopenharmony_ci		clksrc = mac_clk_sources[port];
17862306a36Sopenharmony_ci	else
17962306a36Sopenharmony_ci		clksrc = phy_clk_sources[port];
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/* Payload for packed_buf */
18262306a36Sopenharmony_ci	mii_tx_clk.clksrc    = clksrc;
18362306a36Sopenharmony_ci	mii_tx_clk.autoblock = 1;  /* Autoblock clk while changing clksrc */
18462306a36Sopenharmony_ci	mii_tx_clk.pd        = 0;  /* Power Down off => enabled */
18562306a36Sopenharmony_ci	sja1105_cgu_mii_control_packing(packed_buf, &mii_tx_clk, PACK);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_tx_clk[port],
18862306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic int
19262306a36Sopenharmony_cisja1105_cgu_mii_rx_clk_config(struct sja1105_private *priv, int port)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
19562306a36Sopenharmony_ci	struct sja1105_cgu_mii_ctrl mii_rx_clk;
19662306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
19762306a36Sopenharmony_ci	const int clk_sources[] = {
19862306a36Sopenharmony_ci		CLKSRC_MII0_RX_CLK,
19962306a36Sopenharmony_ci		CLKSRC_MII1_RX_CLK,
20062306a36Sopenharmony_ci		CLKSRC_MII2_RX_CLK,
20162306a36Sopenharmony_ci		CLKSRC_MII3_RX_CLK,
20262306a36Sopenharmony_ci		CLKSRC_MII4_RX_CLK,
20362306a36Sopenharmony_ci	};
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	if (regs->mii_rx_clk[port] == SJA1105_RSV_ADDR)
20662306a36Sopenharmony_ci		return 0;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* Payload for packed_buf */
20962306a36Sopenharmony_ci	mii_rx_clk.clksrc    = clk_sources[port];
21062306a36Sopenharmony_ci	mii_rx_clk.autoblock = 1;  /* Autoblock clk while changing clksrc */
21162306a36Sopenharmony_ci	mii_rx_clk.pd        = 0;  /* Power Down off => enabled */
21262306a36Sopenharmony_ci	sja1105_cgu_mii_control_packing(packed_buf, &mii_rx_clk, PACK);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_rx_clk[port],
21562306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic int
21962306a36Sopenharmony_cisja1105_cgu_mii_ext_tx_clk_config(struct sja1105_private *priv, int port)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
22262306a36Sopenharmony_ci	struct sja1105_cgu_mii_ctrl mii_ext_tx_clk;
22362306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
22462306a36Sopenharmony_ci	const int clk_sources[] = {
22562306a36Sopenharmony_ci		CLKSRC_IDIV0,
22662306a36Sopenharmony_ci		CLKSRC_IDIV1,
22762306a36Sopenharmony_ci		CLKSRC_IDIV2,
22862306a36Sopenharmony_ci		CLKSRC_IDIV3,
22962306a36Sopenharmony_ci		CLKSRC_IDIV4,
23062306a36Sopenharmony_ci	};
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (regs->mii_ext_tx_clk[port] == SJA1105_RSV_ADDR)
23362306a36Sopenharmony_ci		return 0;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/* Payload for packed_buf */
23662306a36Sopenharmony_ci	mii_ext_tx_clk.clksrc    = clk_sources[port];
23762306a36Sopenharmony_ci	mii_ext_tx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
23862306a36Sopenharmony_ci	mii_ext_tx_clk.pd        = 0; /* Power Down off => enabled */
23962306a36Sopenharmony_ci	sja1105_cgu_mii_control_packing(packed_buf, &mii_ext_tx_clk, PACK);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_ext_tx_clk[port],
24262306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic int
24662306a36Sopenharmony_cisja1105_cgu_mii_ext_rx_clk_config(struct sja1105_private *priv, int port)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
24962306a36Sopenharmony_ci	struct sja1105_cgu_mii_ctrl mii_ext_rx_clk;
25062306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
25162306a36Sopenharmony_ci	const int clk_sources[] = {
25262306a36Sopenharmony_ci		CLKSRC_IDIV0,
25362306a36Sopenharmony_ci		CLKSRC_IDIV1,
25462306a36Sopenharmony_ci		CLKSRC_IDIV2,
25562306a36Sopenharmony_ci		CLKSRC_IDIV3,
25662306a36Sopenharmony_ci		CLKSRC_IDIV4,
25762306a36Sopenharmony_ci	};
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (regs->mii_ext_rx_clk[port] == SJA1105_RSV_ADDR)
26062306a36Sopenharmony_ci		return 0;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* Payload for packed_buf */
26362306a36Sopenharmony_ci	mii_ext_rx_clk.clksrc    = clk_sources[port];
26462306a36Sopenharmony_ci	mii_ext_rx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
26562306a36Sopenharmony_ci	mii_ext_rx_clk.pd        = 0; /* Power Down off => enabled */
26662306a36Sopenharmony_ci	sja1105_cgu_mii_control_packing(packed_buf, &mii_ext_rx_clk, PACK);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_ext_rx_clk[port],
26962306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic int sja1105_mii_clocking_setup(struct sja1105_private *priv, int port,
27362306a36Sopenharmony_ci				      sja1105_mii_role_t role)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct device *dev = priv->ds->dev;
27662306a36Sopenharmony_ci	int rc;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	dev_dbg(dev, "Configuring MII-%s clocking\n",
27962306a36Sopenharmony_ci		(role == XMII_MAC) ? "MAC" : "PHY");
28062306a36Sopenharmony_ci	/* If role is MAC, disable IDIV
28162306a36Sopenharmony_ci	 * If role is PHY, enable IDIV and configure for 1/1 divider
28262306a36Sopenharmony_ci	 */
28362306a36Sopenharmony_ci	rc = sja1105_cgu_idiv_config(priv, port, (role == XMII_PHY), 1);
28462306a36Sopenharmony_ci	if (rc < 0)
28562306a36Sopenharmony_ci		return rc;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* Configure CLKSRC of MII_TX_CLK_n
28862306a36Sopenharmony_ci	 *   * If role is MAC, select TX_CLK_n
28962306a36Sopenharmony_ci	 *   * If role is PHY, select IDIV_n
29062306a36Sopenharmony_ci	 */
29162306a36Sopenharmony_ci	rc = sja1105_cgu_mii_tx_clk_config(priv, port, role);
29262306a36Sopenharmony_ci	if (rc < 0)
29362306a36Sopenharmony_ci		return rc;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/* Configure CLKSRC of MII_RX_CLK_n
29662306a36Sopenharmony_ci	 * Select RX_CLK_n
29762306a36Sopenharmony_ci	 */
29862306a36Sopenharmony_ci	rc = sja1105_cgu_mii_rx_clk_config(priv, port);
29962306a36Sopenharmony_ci	if (rc < 0)
30062306a36Sopenharmony_ci		return rc;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (role == XMII_PHY) {
30362306a36Sopenharmony_ci		/* Per MII spec, the PHY (which is us) drives the TX_CLK pin */
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		/* Configure CLKSRC of EXT_TX_CLK_n
30662306a36Sopenharmony_ci		 * Select IDIV_n
30762306a36Sopenharmony_ci		 */
30862306a36Sopenharmony_ci		rc = sja1105_cgu_mii_ext_tx_clk_config(priv, port);
30962306a36Sopenharmony_ci		if (rc < 0)
31062306a36Sopenharmony_ci			return rc;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		/* Configure CLKSRC of EXT_RX_CLK_n
31362306a36Sopenharmony_ci		 * Select IDIV_n
31462306a36Sopenharmony_ci		 */
31562306a36Sopenharmony_ci		rc = sja1105_cgu_mii_ext_rx_clk_config(priv, port);
31662306a36Sopenharmony_ci		if (rc < 0)
31762306a36Sopenharmony_ci			return rc;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci	return 0;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic void
32362306a36Sopenharmony_cisja1105_cgu_pll_control_packing(void *buf, struct sja1105_cgu_pll_ctrl *cmd,
32462306a36Sopenharmony_ci				enum packing_op op)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	const int size = 4;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->pllclksrc, 28, 24, size, op);
32962306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->msel,      23, 16, size, op);
33062306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->autoblock, 11, 11, size, op);
33162306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->psel,       9,  8, size, op);
33262306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->direct,     7,  7, size, op);
33362306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->fbsel,      6,  6, size, op);
33462306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->bypass,     1,  1, size, op);
33562306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->pd,         0,  0, size, op);
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv,
33962306a36Sopenharmony_ci					   int port, u64 speed)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
34262306a36Sopenharmony_ci	struct sja1105_cgu_mii_ctrl txc;
34362306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
34462306a36Sopenharmony_ci	int clksrc;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (regs->rgmii_tx_clk[port] == SJA1105_RSV_ADDR)
34762306a36Sopenharmony_ci		return 0;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
35062306a36Sopenharmony_ci		clksrc = CLKSRC_PLL0;
35162306a36Sopenharmony_ci	} else {
35262306a36Sopenharmony_ci		int clk_sources[] = {CLKSRC_IDIV0, CLKSRC_IDIV1, CLKSRC_IDIV2,
35362306a36Sopenharmony_ci				     CLKSRC_IDIV3, CLKSRC_IDIV4};
35462306a36Sopenharmony_ci		clksrc = clk_sources[port];
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/* RGMII: 125MHz for 1000, 25MHz for 100, 2.5MHz for 10 */
35862306a36Sopenharmony_ci	txc.clksrc = clksrc;
35962306a36Sopenharmony_ci	/* Autoblock clk while changing clksrc */
36062306a36Sopenharmony_ci	txc.autoblock = 1;
36162306a36Sopenharmony_ci	/* Power Down off => enabled */
36262306a36Sopenharmony_ci	txc.pd = 0;
36362306a36Sopenharmony_ci	sja1105_cgu_mii_control_packing(packed_buf, &txc, PACK);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgmii_tx_clk[port],
36662306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci/* AGU */
37062306a36Sopenharmony_cistatic void
37162306a36Sopenharmony_cisja1105_cfg_pad_mii_packing(void *buf, struct sja1105_cfg_pad_mii *cmd,
37262306a36Sopenharmony_ci			    enum packing_op op)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	const int size = 4;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->d32_os,   28, 27, size, op);
37762306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->d32_ih,   26, 26, size, op);
37862306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->d32_ipud, 25, 24, size, op);
37962306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->d10_os,   20, 19, size, op);
38062306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->d10_ih,   18, 18, size, op);
38162306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->d10_ipud, 17, 16, size, op);
38262306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->ctrl_os,  12, 11, size, op);
38362306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->ctrl_ih,  10, 10, size, op);
38462306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->ctrl_ipud, 9,  8, size, op);
38562306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->clk_os,    4,  3, size, op);
38662306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->clk_ih,    2,  2, size, op);
38762306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->clk_ipud,  1,  0, size, op);
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv,
39162306a36Sopenharmony_ci					   int port)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
39462306a36Sopenharmony_ci	struct sja1105_cfg_pad_mii pad_mii_tx = {0};
39562306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (regs->pad_mii_tx[port] == SJA1105_RSV_ADDR)
39862306a36Sopenharmony_ci		return 0;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* Payload */
40162306a36Sopenharmony_ci	pad_mii_tx.d32_os    = 3; /* TXD[3:2] output stage: */
40262306a36Sopenharmony_ci				  /*          high noise/high speed */
40362306a36Sopenharmony_ci	pad_mii_tx.d10_os    = 3; /* TXD[1:0] output stage: */
40462306a36Sopenharmony_ci				  /*          high noise/high speed */
40562306a36Sopenharmony_ci	pad_mii_tx.d32_ipud  = 2; /* TXD[3:2] input stage: */
40662306a36Sopenharmony_ci				  /*          plain input (default) */
40762306a36Sopenharmony_ci	pad_mii_tx.d10_ipud  = 2; /* TXD[1:0] input stage: */
40862306a36Sopenharmony_ci				  /*          plain input (default) */
40962306a36Sopenharmony_ci	pad_mii_tx.ctrl_os   = 3; /* TX_CTL / TX_ER output stage */
41062306a36Sopenharmony_ci	pad_mii_tx.ctrl_ipud = 2; /* TX_CTL / TX_ER input stage (default) */
41162306a36Sopenharmony_ci	pad_mii_tx.clk_os    = 3; /* TX_CLK output stage */
41262306a36Sopenharmony_ci	pad_mii_tx.clk_ih    = 0; /* TX_CLK input hysteresis (default) */
41362306a36Sopenharmony_ci	pad_mii_tx.clk_ipud  = 2; /* TX_CLK input stage (default) */
41462306a36Sopenharmony_ci	sja1105_cfg_pad_mii_packing(packed_buf, &pad_mii_tx, PACK);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_tx[port],
41762306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic int sja1105_cfg_pad_rx_config(struct sja1105_private *priv, int port)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
42362306a36Sopenharmony_ci	struct sja1105_cfg_pad_mii pad_mii_rx = {0};
42462306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (regs->pad_mii_rx[port] == SJA1105_RSV_ADDR)
42762306a36Sopenharmony_ci		return 0;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* Payload */
43062306a36Sopenharmony_ci	pad_mii_rx.d32_ih    = 0; /* RXD[3:2] input stage hysteresis: */
43162306a36Sopenharmony_ci				  /*          non-Schmitt (default) */
43262306a36Sopenharmony_ci	pad_mii_rx.d32_ipud  = 2; /* RXD[3:2] input weak pull-up/down */
43362306a36Sopenharmony_ci				  /*          plain input (default) */
43462306a36Sopenharmony_ci	pad_mii_rx.d10_ih    = 0; /* RXD[1:0] input stage hysteresis: */
43562306a36Sopenharmony_ci				  /*          non-Schmitt (default) */
43662306a36Sopenharmony_ci	pad_mii_rx.d10_ipud  = 2; /* RXD[1:0] input weak pull-up/down */
43762306a36Sopenharmony_ci				  /*          plain input (default) */
43862306a36Sopenharmony_ci	pad_mii_rx.ctrl_ih   = 0; /* RX_DV/CRS_DV/RX_CTL and RX_ER */
43962306a36Sopenharmony_ci				  /* input stage hysteresis: */
44062306a36Sopenharmony_ci				  /* non-Schmitt (default) */
44162306a36Sopenharmony_ci	pad_mii_rx.ctrl_ipud = 3; /* RX_DV/CRS_DV/RX_CTL and RX_ER */
44262306a36Sopenharmony_ci				  /* input stage weak pull-up/down: */
44362306a36Sopenharmony_ci				  /* pull-down */
44462306a36Sopenharmony_ci	pad_mii_rx.clk_os    = 2; /* RX_CLK/RXC output stage: */
44562306a36Sopenharmony_ci				  /* medium noise/fast speed (default) */
44662306a36Sopenharmony_ci	pad_mii_rx.clk_ih    = 0; /* RX_CLK/RXC input hysteresis: */
44762306a36Sopenharmony_ci				  /* non-Schmitt (default) */
44862306a36Sopenharmony_ci	pad_mii_rx.clk_ipud  = 2; /* RX_CLK/RXC input pull-up/down: */
44962306a36Sopenharmony_ci				  /* plain input (default) */
45062306a36Sopenharmony_ci	sja1105_cfg_pad_mii_packing(packed_buf, &pad_mii_rx, PACK);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_rx[port],
45362306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic void
45762306a36Sopenharmony_cisja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
45862306a36Sopenharmony_ci			       enum packing_op op)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	const int size = SJA1105_SIZE_CGU_CMD;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->rxc_stable_ovr, 15, 15, size, op);
46362306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->rxc_delay,      14, 10, size, op);
46462306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->rxc_bypass,      9,  9, size, op);
46562306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->rxc_pd,          8,  8, size, op);
46662306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->txc_stable_ovr,  7,  7, size, op);
46762306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->txc_delay,       6,  2, size, op);
46862306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->txc_bypass,      1,  1, size, op);
46962306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic void
47362306a36Sopenharmony_cisja1110_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
47462306a36Sopenharmony_ci			       enum packing_op op)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	const int size = SJA1105_SIZE_CGU_CMD;
47762306a36Sopenharmony_ci	u64 range = 4;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* Fields RXC_RANGE and TXC_RANGE select the input frequency range:
48062306a36Sopenharmony_ci	 * 0 = 2.5MHz
48162306a36Sopenharmony_ci	 * 1 = 25MHz
48262306a36Sopenharmony_ci	 * 2 = 50MHz
48362306a36Sopenharmony_ci	 * 3 = 125MHz
48462306a36Sopenharmony_ci	 * 4 = Automatically determined by port speed.
48562306a36Sopenharmony_ci	 * There's no point in defining a structure different than the one for
48662306a36Sopenharmony_ci	 * SJA1105, so just hardcode the frequency range to automatic, just as
48762306a36Sopenharmony_ci	 * before.
48862306a36Sopenharmony_ci	 */
48962306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->rxc_stable_ovr, 26, 26, size, op);
49062306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->rxc_delay,      25, 21, size, op);
49162306a36Sopenharmony_ci	sja1105_packing(buf, &range,               20, 18, size, op);
49262306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->rxc_bypass,     17, 17, size, op);
49362306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->rxc_pd,         16, 16, size, op);
49462306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->txc_stable_ovr, 10, 10, size, op);
49562306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->txc_delay,       9,  5, size, op);
49662306a36Sopenharmony_ci	sja1105_packing(buf, &range,                4,  2, size, op);
49762306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->txc_bypass,      1,  1, size, op);
49862306a36Sopenharmony_ci	sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci/* The RGMII delay setup procedure is 2-step and gets called upon each
50262306a36Sopenharmony_ci * .phylink_mac_config. Both are strategic.
50362306a36Sopenharmony_ci * The reason is that the RX Tunable Delay Line of the SJA1105 MAC has issues
50462306a36Sopenharmony_ci * with recovering from a frequency change of the link partner's RGMII clock.
50562306a36Sopenharmony_ci * The easiest way to recover from this is to temporarily power down the TDL,
50662306a36Sopenharmony_ci * as it will re-lock at the new frequency afterwards.
50762306a36Sopenharmony_ci */
50862306a36Sopenharmony_ciint sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	const struct sja1105_private *priv = ctx;
51162306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
51262306a36Sopenharmony_ci	struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
51362306a36Sopenharmony_ci	int rx_delay = priv->rgmii_rx_delay_ps[port];
51462306a36Sopenharmony_ci	int tx_delay = priv->rgmii_tx_delay_ps[port];
51562306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
51662306a36Sopenharmony_ci	int rc;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if (rx_delay)
51962306a36Sopenharmony_ci		pad_mii_id.rxc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(rx_delay);
52062306a36Sopenharmony_ci	if (tx_delay)
52162306a36Sopenharmony_ci		pad_mii_id.txc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(tx_delay);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* Stage 1: Turn the RGMII delay lines off. */
52462306a36Sopenharmony_ci	pad_mii_id.rxc_bypass = 1;
52562306a36Sopenharmony_ci	pad_mii_id.rxc_pd = 1;
52662306a36Sopenharmony_ci	pad_mii_id.txc_bypass = 1;
52762306a36Sopenharmony_ci	pad_mii_id.txc_pd = 1;
52862306a36Sopenharmony_ci	sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
53162306a36Sopenharmony_ci			      packed_buf, SJA1105_SIZE_CGU_CMD);
53262306a36Sopenharmony_ci	if (rc < 0)
53362306a36Sopenharmony_ci		return rc;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	/* Stage 2: Turn the RGMII delay lines on. */
53662306a36Sopenharmony_ci	if (rx_delay) {
53762306a36Sopenharmony_ci		pad_mii_id.rxc_bypass = 0;
53862306a36Sopenharmony_ci		pad_mii_id.rxc_pd = 0;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci	if (tx_delay) {
54162306a36Sopenharmony_ci		pad_mii_id.txc_bypass = 0;
54262306a36Sopenharmony_ci		pad_mii_id.txc_pd = 0;
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci	sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
54762306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ciint sja1110_setup_rgmii_delay(const void *ctx, int port)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	const struct sja1105_private *priv = ctx;
55362306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
55462306a36Sopenharmony_ci	struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
55562306a36Sopenharmony_ci	int rx_delay = priv->rgmii_rx_delay_ps[port];
55662306a36Sopenharmony_ci	int tx_delay = priv->rgmii_tx_delay_ps[port];
55762306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	pad_mii_id.rxc_pd = 1;
56062306a36Sopenharmony_ci	pad_mii_id.txc_pd = 1;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	if (rx_delay) {
56362306a36Sopenharmony_ci		pad_mii_id.rxc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(rx_delay);
56462306a36Sopenharmony_ci		/* The "BYPASS" bit in SJA1110 is actually a "don't bypass" */
56562306a36Sopenharmony_ci		pad_mii_id.rxc_bypass = 1;
56662306a36Sopenharmony_ci		pad_mii_id.rxc_pd = 0;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	if (tx_delay) {
57062306a36Sopenharmony_ci		pad_mii_id.txc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(tx_delay);
57162306a36Sopenharmony_ci		pad_mii_id.txc_bypass = 1;
57262306a36Sopenharmony_ci		pad_mii_id.txc_pd = 0;
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	sja1110_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
57862306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
58262306a36Sopenharmony_ci					sja1105_mii_role_t role)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct device *dev = priv->ds->dev;
58562306a36Sopenharmony_ci	struct sja1105_mac_config_entry *mac;
58662306a36Sopenharmony_ci	u64 speed;
58762306a36Sopenharmony_ci	int rc;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
59062306a36Sopenharmony_ci	speed = mac[port].speed;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	dev_dbg(dev, "Configuring port %d RGMII at speed %lldMbps\n",
59362306a36Sopenharmony_ci		port, speed);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
59662306a36Sopenharmony_ci		/* 1000Mbps, IDIV disabled (125 MHz) */
59762306a36Sopenharmony_ci		rc = sja1105_cgu_idiv_config(priv, port, false, 1);
59862306a36Sopenharmony_ci	} else if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS]) {
59962306a36Sopenharmony_ci		/* 100Mbps, IDIV enabled, divide by 1 (25 MHz) */
60062306a36Sopenharmony_ci		rc = sja1105_cgu_idiv_config(priv, port, true, 1);
60162306a36Sopenharmony_ci	} else if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS]) {
60262306a36Sopenharmony_ci		/* 10Mbps, IDIV enabled, divide by 10 (2.5 MHz) */
60362306a36Sopenharmony_ci		rc = sja1105_cgu_idiv_config(priv, port, true, 10);
60462306a36Sopenharmony_ci	} else if (speed == priv->info->port_speed[SJA1105_SPEED_AUTO]) {
60562306a36Sopenharmony_ci		/* Skip CGU configuration if there is no speed available
60662306a36Sopenharmony_ci		 * (e.g. link is not established yet)
60762306a36Sopenharmony_ci		 */
60862306a36Sopenharmony_ci		dev_dbg(dev, "Speed not available, skipping CGU config\n");
60962306a36Sopenharmony_ci		return 0;
61062306a36Sopenharmony_ci	} else {
61162306a36Sopenharmony_ci		rc = -EINVAL;
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (rc < 0) {
61562306a36Sopenharmony_ci		dev_err(dev, "Failed to configure idiv\n");
61662306a36Sopenharmony_ci		return rc;
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci	rc = sja1105_cgu_rgmii_tx_clk_config(priv, port, speed);
61962306a36Sopenharmony_ci	if (rc < 0) {
62062306a36Sopenharmony_ci		dev_err(dev, "Failed to configure RGMII Tx clock\n");
62162306a36Sopenharmony_ci		return rc;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci	rc = sja1105_rgmii_cfg_pad_tx_config(priv, port);
62462306a36Sopenharmony_ci	if (rc < 0) {
62562306a36Sopenharmony_ci		dev_err(dev, "Failed to configure Tx pad registers\n");
62662306a36Sopenharmony_ci		return rc;
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	if (!priv->info->setup_rgmii_delay)
63062306a36Sopenharmony_ci		return 0;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	return priv->info->setup_rgmii_delay(priv, port);
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic int sja1105_cgu_rmii_ref_clk_config(struct sja1105_private *priv,
63662306a36Sopenharmony_ci					   int port)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
63962306a36Sopenharmony_ci	struct sja1105_cgu_mii_ctrl ref_clk;
64062306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
64162306a36Sopenharmony_ci	const int clk_sources[] = {
64262306a36Sopenharmony_ci		CLKSRC_MII0_TX_CLK,
64362306a36Sopenharmony_ci		CLKSRC_MII1_TX_CLK,
64462306a36Sopenharmony_ci		CLKSRC_MII2_TX_CLK,
64562306a36Sopenharmony_ci		CLKSRC_MII3_TX_CLK,
64662306a36Sopenharmony_ci		CLKSRC_MII4_TX_CLK,
64762306a36Sopenharmony_ci	};
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (regs->rmii_ref_clk[port] == SJA1105_RSV_ADDR)
65062306a36Sopenharmony_ci		return 0;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	/* Payload for packed_buf */
65362306a36Sopenharmony_ci	ref_clk.clksrc    = clk_sources[port];
65462306a36Sopenharmony_ci	ref_clk.autoblock = 1;      /* Autoblock clk while changing clksrc */
65562306a36Sopenharmony_ci	ref_clk.pd        = 0;      /* Power Down off => enabled */
65662306a36Sopenharmony_ci	sja1105_cgu_mii_control_packing(packed_buf, &ref_clk, PACK);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_ref_clk[port],
65962306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic int
66362306a36Sopenharmony_cisja1105_cgu_rmii_ext_tx_clk_config(struct sja1105_private *priv, int port)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
66662306a36Sopenharmony_ci	struct sja1105_cgu_mii_ctrl ext_tx_clk;
66762306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	if (regs->rmii_ext_tx_clk[port] == SJA1105_RSV_ADDR)
67062306a36Sopenharmony_ci		return 0;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	/* Payload for packed_buf */
67362306a36Sopenharmony_ci	ext_tx_clk.clksrc    = CLKSRC_PLL1;
67462306a36Sopenharmony_ci	ext_tx_clk.autoblock = 1;   /* Autoblock clk while changing clksrc */
67562306a36Sopenharmony_ci	ext_tx_clk.pd        = 0;   /* Power Down off => enabled */
67662306a36Sopenharmony_ci	sja1105_cgu_mii_control_packing(packed_buf, &ext_tx_clk, PACK);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_ext_tx_clk[port],
67962306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic int sja1105_cgu_rmii_pll_config(struct sja1105_private *priv)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	const struct sja1105_regs *regs = priv->info->regs;
68562306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
68662306a36Sopenharmony_ci	struct sja1105_cgu_pll_ctrl pll = {0};
68762306a36Sopenharmony_ci	struct device *dev = priv->ds->dev;
68862306a36Sopenharmony_ci	int rc;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	if (regs->rmii_pll1 == SJA1105_RSV_ADDR)
69162306a36Sopenharmony_ci		return 0;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	/* PLL1 must be enabled and output 50 Mhz.
69462306a36Sopenharmony_ci	 * This is done by writing first 0x0A010941 to
69562306a36Sopenharmony_ci	 * the PLL_1_C register and then deasserting
69662306a36Sopenharmony_ci	 * power down (PD) 0x0A010940.
69762306a36Sopenharmony_ci	 */
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	/* Step 1: PLL1 setup for 50Mhz */
70062306a36Sopenharmony_ci	pll.pllclksrc = 0xA;
70162306a36Sopenharmony_ci	pll.msel      = 0x1;
70262306a36Sopenharmony_ci	pll.autoblock = 0x1;
70362306a36Sopenharmony_ci	pll.psel      = 0x1;
70462306a36Sopenharmony_ci	pll.direct    = 0x0;
70562306a36Sopenharmony_ci	pll.fbsel     = 0x1;
70662306a36Sopenharmony_ci	pll.bypass    = 0x0;
70762306a36Sopenharmony_ci	pll.pd        = 0x1;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	sja1105_cgu_pll_control_packing(packed_buf, &pll, PACK);
71062306a36Sopenharmony_ci	rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_pll1, packed_buf,
71162306a36Sopenharmony_ci			      SJA1105_SIZE_CGU_CMD);
71262306a36Sopenharmony_ci	if (rc < 0) {
71362306a36Sopenharmony_ci		dev_err(dev, "failed to configure PLL1 for 50MHz\n");
71462306a36Sopenharmony_ci		return rc;
71562306a36Sopenharmony_ci	}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* Step 2: Enable PLL1 */
71862306a36Sopenharmony_ci	pll.pd = 0x0;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	sja1105_cgu_pll_control_packing(packed_buf, &pll, PACK);
72162306a36Sopenharmony_ci	rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_pll1, packed_buf,
72262306a36Sopenharmony_ci			      SJA1105_SIZE_CGU_CMD);
72362306a36Sopenharmony_ci	if (rc < 0) {
72462306a36Sopenharmony_ci		dev_err(dev, "failed to enable PLL1\n");
72562306a36Sopenharmony_ci		return rc;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci	return rc;
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_cistatic int sja1105_rmii_clocking_setup(struct sja1105_private *priv, int port,
73162306a36Sopenharmony_ci				       sja1105_mii_role_t role)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	struct device *dev = priv->ds->dev;
73462306a36Sopenharmony_ci	int rc;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	dev_dbg(dev, "Configuring RMII-%s clocking\n",
73762306a36Sopenharmony_ci		(role == XMII_MAC) ? "MAC" : "PHY");
73862306a36Sopenharmony_ci	/* AH1601.pdf chapter 2.5.1. Sources */
73962306a36Sopenharmony_ci	if (role == XMII_MAC) {
74062306a36Sopenharmony_ci		/* Configure and enable PLL1 for 50Mhz output */
74162306a36Sopenharmony_ci		rc = sja1105_cgu_rmii_pll_config(priv);
74262306a36Sopenharmony_ci		if (rc < 0)
74362306a36Sopenharmony_ci			return rc;
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci	/* Disable IDIV for this port */
74662306a36Sopenharmony_ci	rc = sja1105_cgu_idiv_config(priv, port, false, 1);
74762306a36Sopenharmony_ci	if (rc < 0)
74862306a36Sopenharmony_ci		return rc;
74962306a36Sopenharmony_ci	/* Source to sink mappings */
75062306a36Sopenharmony_ci	rc = sja1105_cgu_rmii_ref_clk_config(priv, port);
75162306a36Sopenharmony_ci	if (rc < 0)
75262306a36Sopenharmony_ci		return rc;
75362306a36Sopenharmony_ci	if (role == XMII_MAC) {
75462306a36Sopenharmony_ci		rc = sja1105_cgu_rmii_ext_tx_clk_config(priv, port);
75562306a36Sopenharmony_ci		if (rc < 0)
75662306a36Sopenharmony_ci			return rc;
75762306a36Sopenharmony_ci	}
75862306a36Sopenharmony_ci	return 0;
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ciint sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	struct sja1105_xmii_params_entry *mii;
76462306a36Sopenharmony_ci	struct device *dev = priv->ds->dev;
76562306a36Sopenharmony_ci	sja1105_phy_interface_t phy_mode;
76662306a36Sopenharmony_ci	sja1105_mii_role_t role;
76762306a36Sopenharmony_ci	int rc;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	/* RGMII etc */
77262306a36Sopenharmony_ci	phy_mode = mii->xmii_mode[port];
77362306a36Sopenharmony_ci	/* MAC or PHY, for applicable types (not RGMII) */
77462306a36Sopenharmony_ci	role = mii->phy_mac[port];
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	switch (phy_mode) {
77762306a36Sopenharmony_ci	case XMII_MODE_MII:
77862306a36Sopenharmony_ci		rc = sja1105_mii_clocking_setup(priv, port, role);
77962306a36Sopenharmony_ci		break;
78062306a36Sopenharmony_ci	case XMII_MODE_RMII:
78162306a36Sopenharmony_ci		rc = sja1105_rmii_clocking_setup(priv, port, role);
78262306a36Sopenharmony_ci		break;
78362306a36Sopenharmony_ci	case XMII_MODE_RGMII:
78462306a36Sopenharmony_ci		rc = sja1105_rgmii_clocking_setup(priv, port, role);
78562306a36Sopenharmony_ci		break;
78662306a36Sopenharmony_ci	case XMII_MODE_SGMII:
78762306a36Sopenharmony_ci		/* Nothing to do in the CGU for SGMII */
78862306a36Sopenharmony_ci		rc = 0;
78962306a36Sopenharmony_ci		break;
79062306a36Sopenharmony_ci	default:
79162306a36Sopenharmony_ci		dev_err(dev, "Invalid interface mode specified: %d\n",
79262306a36Sopenharmony_ci			phy_mode);
79362306a36Sopenharmony_ci		return -EINVAL;
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci	if (rc) {
79662306a36Sopenharmony_ci		dev_err(dev, "Clocking setup for port %d failed: %d\n",
79762306a36Sopenharmony_ci			port, rc);
79862306a36Sopenharmony_ci		return rc;
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	/* Internally pull down the RX_DV/CRS_DV/RX_CTL and RX_ER inputs */
80262306a36Sopenharmony_ci	return sja1105_cfg_pad_rx_config(priv, port);
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ciint sja1105_clocking_setup(struct sja1105_private *priv)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	struct dsa_switch *ds = priv->ds;
80862306a36Sopenharmony_ci	int port, rc;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	for (port = 0; port < ds->num_ports; port++) {
81162306a36Sopenharmony_ci		rc = sja1105_clocking_setup_port(priv, port);
81262306a36Sopenharmony_ci		if (rc < 0)
81362306a36Sopenharmony_ci			return rc;
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci	return 0;
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic void
81962306a36Sopenharmony_cisja1110_cgu_outclk_packing(void *buf, struct sja1110_cgu_outclk *outclk,
82062306a36Sopenharmony_ci			   enum packing_op op)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	const int size = 4;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	sja1105_packing(buf, &outclk->clksrc,    27, 24, size, op);
82562306a36Sopenharmony_ci	sja1105_packing(buf, &outclk->autoblock, 11, 11, size, op);
82662306a36Sopenharmony_ci	sja1105_packing(buf, &outclk->pd,         0,  0, size, op);
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ciint sja1110_disable_microcontroller(struct sja1105_private *priv)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
83262306a36Sopenharmony_ci	struct sja1110_cgu_outclk outclk_6_c = {
83362306a36Sopenharmony_ci		.clksrc = 0x3,
83462306a36Sopenharmony_ci		.pd = true,
83562306a36Sopenharmony_ci	};
83662306a36Sopenharmony_ci	struct sja1110_cgu_outclk outclk_7_c = {
83762306a36Sopenharmony_ci		.clksrc = 0x5,
83862306a36Sopenharmony_ci		.pd = true,
83962306a36Sopenharmony_ci	};
84062306a36Sopenharmony_ci	int rc;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	/* Power down the BASE_TIMER_CLK to disable the watchdog timer */
84362306a36Sopenharmony_ci	sja1110_cgu_outclk_packing(packed_buf, &outclk_7_c, PACK);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	rc = sja1105_xfer_buf(priv, SPI_WRITE, SJA1110_BASE_TIMER_CLK,
84662306a36Sopenharmony_ci			      packed_buf, SJA1105_SIZE_CGU_CMD);
84762306a36Sopenharmony_ci	if (rc)
84862306a36Sopenharmony_ci		return rc;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	/* Power down the BASE_MCSS_CLOCK to gate the microcontroller off */
85162306a36Sopenharmony_ci	sja1110_cgu_outclk_packing(packed_buf, &outclk_6_c, PACK);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	return sja1105_xfer_buf(priv, SPI_WRITE, SJA1110_BASE_MCSS_CLK,
85462306a36Sopenharmony_ci				packed_buf, SJA1105_SIZE_CGU_CMD);
85562306a36Sopenharmony_ci}
856