xref: /linux/drivers/net/dsa/sja1105/sja1105_clocking.c (revision 1bd448703895473e500c0ce4c6258aeac1f67c20)
18aa9ebccSVladimir Oltean // SPDX-License-Identifier: BSD-3-Clause
28aa9ebccSVladimir Oltean /* Copyright (c) 2016-2018, NXP Semiconductors
38aa9ebccSVladimir Oltean  * Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
48aa9ebccSVladimir Oltean  */
58aa9ebccSVladimir Oltean #include <linux/packing.h>
68aa9ebccSVladimir Oltean #include "sja1105.h"
78aa9ebccSVladimir Oltean 
88aa9ebccSVladimir Oltean #define SJA1105_SIZE_CGU_CMD	4
98aa9ebccSVladimir Oltean 
108aa9ebccSVladimir Oltean struct sja1105_cfg_pad_mii_tx {
118aa9ebccSVladimir Oltean 	u64 d32_os;
128aa9ebccSVladimir Oltean 	u64 d32_ipud;
138aa9ebccSVladimir Oltean 	u64 d10_os;
148aa9ebccSVladimir Oltean 	u64 d10_ipud;
158aa9ebccSVladimir Oltean 	u64 ctrl_os;
168aa9ebccSVladimir Oltean 	u64 ctrl_ipud;
178aa9ebccSVladimir Oltean 	u64 clk_os;
188aa9ebccSVladimir Oltean 	u64 clk_ih;
198aa9ebccSVladimir Oltean 	u64 clk_ipud;
208aa9ebccSVladimir Oltean };
218aa9ebccSVladimir Oltean 
22c05ec3d4SVladimir Oltean struct sja1105_cfg_pad_mii_id {
23c05ec3d4SVladimir Oltean 	u64 rxc_stable_ovr;
24c05ec3d4SVladimir Oltean 	u64 rxc_delay;
25c05ec3d4SVladimir Oltean 	u64 rxc_bypass;
26c05ec3d4SVladimir Oltean 	u64 rxc_pd;
27c05ec3d4SVladimir Oltean 	u64 txc_stable_ovr;
28c05ec3d4SVladimir Oltean 	u64 txc_delay;
29c05ec3d4SVladimir Oltean 	u64 txc_bypass;
30c05ec3d4SVladimir Oltean 	u64 txc_pd;
31c05ec3d4SVladimir Oltean };
32c05ec3d4SVladimir Oltean 
338aa9ebccSVladimir Oltean /* UM10944 Table 82.
348aa9ebccSVladimir Oltean  * IDIV_0_C to IDIV_4_C control registers
358aa9ebccSVladimir Oltean  * (addr. 10000Bh to 10000Fh)
368aa9ebccSVladimir Oltean  */
378aa9ebccSVladimir Oltean struct sja1105_cgu_idiv {
388aa9ebccSVladimir Oltean 	u64 clksrc;
398aa9ebccSVladimir Oltean 	u64 autoblock;
408aa9ebccSVladimir Oltean 	u64 idiv;
418aa9ebccSVladimir Oltean 	u64 pd;
428aa9ebccSVladimir Oltean };
438aa9ebccSVladimir Oltean 
448aa9ebccSVladimir Oltean /* PLL_1_C control register
458aa9ebccSVladimir Oltean  *
468aa9ebccSVladimir Oltean  * SJA1105 E/T: UM10944 Table 81 (address 10000Ah)
478aa9ebccSVladimir Oltean  * SJA1105 P/Q/R/S: UM11040 Table 116 (address 10000Ah)
488aa9ebccSVladimir Oltean  */
498aa9ebccSVladimir Oltean struct sja1105_cgu_pll_ctrl {
508aa9ebccSVladimir Oltean 	u64 pllclksrc;
518aa9ebccSVladimir Oltean 	u64 msel;
528aa9ebccSVladimir Oltean 	u64 autoblock;
538aa9ebccSVladimir Oltean 	u64 psel;
548aa9ebccSVladimir Oltean 	u64 direct;
558aa9ebccSVladimir Oltean 	u64 fbsel;
568aa9ebccSVladimir Oltean 	u64 bypass;
578aa9ebccSVladimir Oltean 	u64 pd;
588aa9ebccSVladimir Oltean };
598aa9ebccSVladimir Oltean 
608aa9ebccSVladimir Oltean enum {
618aa9ebccSVladimir Oltean 	CLKSRC_MII0_TX_CLK	= 0x00,
628aa9ebccSVladimir Oltean 	CLKSRC_MII0_RX_CLK	= 0x01,
638aa9ebccSVladimir Oltean 	CLKSRC_MII1_TX_CLK	= 0x02,
648aa9ebccSVladimir Oltean 	CLKSRC_MII1_RX_CLK	= 0x03,
658aa9ebccSVladimir Oltean 	CLKSRC_MII2_TX_CLK	= 0x04,
668aa9ebccSVladimir Oltean 	CLKSRC_MII2_RX_CLK	= 0x05,
678aa9ebccSVladimir Oltean 	CLKSRC_MII3_TX_CLK	= 0x06,
688aa9ebccSVladimir Oltean 	CLKSRC_MII3_RX_CLK	= 0x07,
698aa9ebccSVladimir Oltean 	CLKSRC_MII4_TX_CLK	= 0x08,
708aa9ebccSVladimir Oltean 	CLKSRC_MII4_RX_CLK	= 0x09,
718aa9ebccSVladimir Oltean 	CLKSRC_PLL0		= 0x0B,
728aa9ebccSVladimir Oltean 	CLKSRC_PLL1		= 0x0E,
738aa9ebccSVladimir Oltean 	CLKSRC_IDIV0		= 0x11,
748aa9ebccSVladimir Oltean 	CLKSRC_IDIV1		= 0x12,
758aa9ebccSVladimir Oltean 	CLKSRC_IDIV2		= 0x13,
768aa9ebccSVladimir Oltean 	CLKSRC_IDIV3		= 0x14,
778aa9ebccSVladimir Oltean 	CLKSRC_IDIV4		= 0x15,
788aa9ebccSVladimir Oltean };
798aa9ebccSVladimir Oltean 
808aa9ebccSVladimir Oltean /* UM10944 Table 83.
818aa9ebccSVladimir Oltean  * MIIx clock control registers 1 to 30
828aa9ebccSVladimir Oltean  * (addresses 100013h to 100035h)
838aa9ebccSVladimir Oltean  */
848aa9ebccSVladimir Oltean struct sja1105_cgu_mii_ctrl {
858aa9ebccSVladimir Oltean 	u64 clksrc;
868aa9ebccSVladimir Oltean 	u64 autoblock;
878aa9ebccSVladimir Oltean 	u64 pd;
888aa9ebccSVladimir Oltean };
898aa9ebccSVladimir Oltean 
908aa9ebccSVladimir Oltean static void sja1105_cgu_idiv_packing(void *buf, struct sja1105_cgu_idiv *idiv,
918aa9ebccSVladimir Oltean 				     enum packing_op op)
928aa9ebccSVladimir Oltean {
938aa9ebccSVladimir Oltean 	const int size = 4;
948aa9ebccSVladimir Oltean 
958aa9ebccSVladimir Oltean 	sja1105_packing(buf, &idiv->clksrc,    28, 24, size, op);
968aa9ebccSVladimir Oltean 	sja1105_packing(buf, &idiv->autoblock, 11, 11, size, op);
978aa9ebccSVladimir Oltean 	sja1105_packing(buf, &idiv->idiv,       5,  2, size, op);
988aa9ebccSVladimir Oltean 	sja1105_packing(buf, &idiv->pd,         0,  0, size, op);
998aa9ebccSVladimir Oltean }
1008aa9ebccSVladimir Oltean 
1018aa9ebccSVladimir Oltean static int sja1105_cgu_idiv_config(struct sja1105_private *priv, int port,
1028aa9ebccSVladimir Oltean 				   bool enabled, int factor)
1038aa9ebccSVladimir Oltean {
1048aa9ebccSVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
1058aa9ebccSVladimir Oltean 	struct device *dev = priv->ds->dev;
1068aa9ebccSVladimir Oltean 	struct sja1105_cgu_idiv idiv;
1078aa9ebccSVladimir Oltean 	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
1088aa9ebccSVladimir Oltean 
1098aa9ebccSVladimir Oltean 	if (enabled && factor != 1 && factor != 10) {
1108aa9ebccSVladimir Oltean 		dev_err(dev, "idiv factor must be 1 or 10\n");
1118aa9ebccSVladimir Oltean 		return -ERANGE;
1128aa9ebccSVladimir Oltean 	}
1138aa9ebccSVladimir Oltean 
1148aa9ebccSVladimir Oltean 	/* Payload for packed_buf */
1158aa9ebccSVladimir Oltean 	idiv.clksrc    = 0x0A;            /* 25MHz */
1168aa9ebccSVladimir Oltean 	idiv.autoblock = 1;               /* Block clk automatically */
1178aa9ebccSVladimir Oltean 	idiv.idiv      = factor - 1;      /* Divide by 1 or 10 */
1188aa9ebccSVladimir Oltean 	idiv.pd        = enabled ? 0 : 1; /* Power down? */
1198aa9ebccSVladimir Oltean 	sja1105_cgu_idiv_packing(packed_buf, &idiv, PACK);
1208aa9ebccSVladimir Oltean 
121*1bd44870SVladimir Oltean 	return sja1105_xfer_buf(priv, SPI_WRITE, regs->cgu_idiv[port],
122*1bd44870SVladimir Oltean 				packed_buf, SJA1105_SIZE_CGU_CMD);
1238aa9ebccSVladimir Oltean }
1248aa9ebccSVladimir Oltean 
1258aa9ebccSVladimir Oltean static void
1268aa9ebccSVladimir Oltean sja1105_cgu_mii_control_packing(void *buf, struct sja1105_cgu_mii_ctrl *cmd,
1278aa9ebccSVladimir Oltean 				enum packing_op op)
1288aa9ebccSVladimir Oltean {
1298aa9ebccSVladimir Oltean 	const int size = 4;
1308aa9ebccSVladimir Oltean 
1318aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->clksrc,    28, 24, size, op);
1328aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->autoblock, 11, 11, size, op);
1338aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->pd,         0,  0, size, op);
1348aa9ebccSVladimir Oltean }
1358aa9ebccSVladimir Oltean 
1368aa9ebccSVladimir Oltean static int sja1105_cgu_mii_tx_clk_config(struct sja1105_private *priv,
1378aa9ebccSVladimir Oltean 					 int port, sja1105_mii_role_t role)
1388aa9ebccSVladimir Oltean {
1398aa9ebccSVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
1408aa9ebccSVladimir Oltean 	struct sja1105_cgu_mii_ctrl mii_tx_clk;
1418aa9ebccSVladimir Oltean 	const int mac_clk_sources[] = {
1428aa9ebccSVladimir Oltean 		CLKSRC_MII0_TX_CLK,
1438aa9ebccSVladimir Oltean 		CLKSRC_MII1_TX_CLK,
1448aa9ebccSVladimir Oltean 		CLKSRC_MII2_TX_CLK,
1458aa9ebccSVladimir Oltean 		CLKSRC_MII3_TX_CLK,
1468aa9ebccSVladimir Oltean 		CLKSRC_MII4_TX_CLK,
1478aa9ebccSVladimir Oltean 	};
1488aa9ebccSVladimir Oltean 	const int phy_clk_sources[] = {
1498aa9ebccSVladimir Oltean 		CLKSRC_IDIV0,
1508aa9ebccSVladimir Oltean 		CLKSRC_IDIV1,
1518aa9ebccSVladimir Oltean 		CLKSRC_IDIV2,
1528aa9ebccSVladimir Oltean 		CLKSRC_IDIV3,
1538aa9ebccSVladimir Oltean 		CLKSRC_IDIV4,
1548aa9ebccSVladimir Oltean 	};
1558aa9ebccSVladimir Oltean 	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
1568aa9ebccSVladimir Oltean 	int clksrc;
1578aa9ebccSVladimir Oltean 
1588aa9ebccSVladimir Oltean 	if (role == XMII_MAC)
1598aa9ebccSVladimir Oltean 		clksrc = mac_clk_sources[port];
1608aa9ebccSVladimir Oltean 	else
1618aa9ebccSVladimir Oltean 		clksrc = phy_clk_sources[port];
1628aa9ebccSVladimir Oltean 
1638aa9ebccSVladimir Oltean 	/* Payload for packed_buf */
1648aa9ebccSVladimir Oltean 	mii_tx_clk.clksrc    = clksrc;
1658aa9ebccSVladimir Oltean 	mii_tx_clk.autoblock = 1;  /* Autoblock clk while changing clksrc */
1668aa9ebccSVladimir Oltean 	mii_tx_clk.pd        = 0;  /* Power Down off => enabled */
1678aa9ebccSVladimir Oltean 	sja1105_cgu_mii_control_packing(packed_buf, &mii_tx_clk, PACK);
1688aa9ebccSVladimir Oltean 
169*1bd44870SVladimir Oltean 	return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_tx_clk[port],
170*1bd44870SVladimir Oltean 				packed_buf, SJA1105_SIZE_CGU_CMD);
1718aa9ebccSVladimir Oltean }
1728aa9ebccSVladimir Oltean 
1738aa9ebccSVladimir Oltean static int
1748aa9ebccSVladimir Oltean sja1105_cgu_mii_rx_clk_config(struct sja1105_private *priv, int port)
1758aa9ebccSVladimir Oltean {
1768aa9ebccSVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
1778aa9ebccSVladimir Oltean 	struct sja1105_cgu_mii_ctrl mii_rx_clk;
1788aa9ebccSVladimir Oltean 	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
1798aa9ebccSVladimir Oltean 	const int clk_sources[] = {
1808aa9ebccSVladimir Oltean 		CLKSRC_MII0_RX_CLK,
1818aa9ebccSVladimir Oltean 		CLKSRC_MII1_RX_CLK,
1828aa9ebccSVladimir Oltean 		CLKSRC_MII2_RX_CLK,
1838aa9ebccSVladimir Oltean 		CLKSRC_MII3_RX_CLK,
1848aa9ebccSVladimir Oltean 		CLKSRC_MII4_RX_CLK,
1858aa9ebccSVladimir Oltean 	};
1868aa9ebccSVladimir Oltean 
1878aa9ebccSVladimir Oltean 	/* Payload for packed_buf */
1888aa9ebccSVladimir Oltean 	mii_rx_clk.clksrc    = clk_sources[port];
1898aa9ebccSVladimir Oltean 	mii_rx_clk.autoblock = 1;  /* Autoblock clk while changing clksrc */
1908aa9ebccSVladimir Oltean 	mii_rx_clk.pd        = 0;  /* Power Down off => enabled */
1918aa9ebccSVladimir Oltean 	sja1105_cgu_mii_control_packing(packed_buf, &mii_rx_clk, PACK);
1928aa9ebccSVladimir Oltean 
193*1bd44870SVladimir Oltean 	return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_rx_clk[port],
194*1bd44870SVladimir Oltean 				packed_buf, SJA1105_SIZE_CGU_CMD);
1958aa9ebccSVladimir Oltean }
1968aa9ebccSVladimir Oltean 
1978aa9ebccSVladimir Oltean static int
1988aa9ebccSVladimir Oltean sja1105_cgu_mii_ext_tx_clk_config(struct sja1105_private *priv, int port)
1998aa9ebccSVladimir Oltean {
2008aa9ebccSVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
2018aa9ebccSVladimir Oltean 	struct sja1105_cgu_mii_ctrl mii_ext_tx_clk;
2028aa9ebccSVladimir Oltean 	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
2038aa9ebccSVladimir Oltean 	const int clk_sources[] = {
2048aa9ebccSVladimir Oltean 		CLKSRC_IDIV0,
2058aa9ebccSVladimir Oltean 		CLKSRC_IDIV1,
2068aa9ebccSVladimir Oltean 		CLKSRC_IDIV2,
2078aa9ebccSVladimir Oltean 		CLKSRC_IDIV3,
2088aa9ebccSVladimir Oltean 		CLKSRC_IDIV4,
2098aa9ebccSVladimir Oltean 	};
2108aa9ebccSVladimir Oltean 
2118aa9ebccSVladimir Oltean 	/* Payload for packed_buf */
2128aa9ebccSVladimir Oltean 	mii_ext_tx_clk.clksrc    = clk_sources[port];
2138aa9ebccSVladimir Oltean 	mii_ext_tx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
2148aa9ebccSVladimir Oltean 	mii_ext_tx_clk.pd        = 0; /* Power Down off => enabled */
2158aa9ebccSVladimir Oltean 	sja1105_cgu_mii_control_packing(packed_buf, &mii_ext_tx_clk, PACK);
2168aa9ebccSVladimir Oltean 
217*1bd44870SVladimir Oltean 	return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_ext_tx_clk[port],
2188aa9ebccSVladimir Oltean 				packed_buf, SJA1105_SIZE_CGU_CMD);
2198aa9ebccSVladimir Oltean }
2208aa9ebccSVladimir Oltean 
2218aa9ebccSVladimir Oltean static int
2228aa9ebccSVladimir Oltean sja1105_cgu_mii_ext_rx_clk_config(struct sja1105_private *priv, int port)
2238aa9ebccSVladimir Oltean {
2248aa9ebccSVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
2258aa9ebccSVladimir Oltean 	struct sja1105_cgu_mii_ctrl mii_ext_rx_clk;
2268aa9ebccSVladimir Oltean 	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
2278aa9ebccSVladimir Oltean 	const int clk_sources[] = {
2288aa9ebccSVladimir Oltean 		CLKSRC_IDIV0,
2298aa9ebccSVladimir Oltean 		CLKSRC_IDIV1,
2308aa9ebccSVladimir Oltean 		CLKSRC_IDIV2,
2318aa9ebccSVladimir Oltean 		CLKSRC_IDIV3,
2328aa9ebccSVladimir Oltean 		CLKSRC_IDIV4,
2338aa9ebccSVladimir Oltean 	};
2348aa9ebccSVladimir Oltean 
2358aa9ebccSVladimir Oltean 	/* Payload for packed_buf */
2368aa9ebccSVladimir Oltean 	mii_ext_rx_clk.clksrc    = clk_sources[port];
2378aa9ebccSVladimir Oltean 	mii_ext_rx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
2388aa9ebccSVladimir Oltean 	mii_ext_rx_clk.pd        = 0; /* Power Down off => enabled */
2398aa9ebccSVladimir Oltean 	sja1105_cgu_mii_control_packing(packed_buf, &mii_ext_rx_clk, PACK);
2408aa9ebccSVladimir Oltean 
241*1bd44870SVladimir Oltean 	return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_ext_rx_clk[port],
2428aa9ebccSVladimir Oltean 				packed_buf, SJA1105_SIZE_CGU_CMD);
2438aa9ebccSVladimir Oltean }
2448aa9ebccSVladimir Oltean 
2458aa9ebccSVladimir Oltean static int sja1105_mii_clocking_setup(struct sja1105_private *priv, int port,
2468aa9ebccSVladimir Oltean 				      sja1105_mii_role_t role)
2478aa9ebccSVladimir Oltean {
2488aa9ebccSVladimir Oltean 	struct device *dev = priv->ds->dev;
2498aa9ebccSVladimir Oltean 	int rc;
2508aa9ebccSVladimir Oltean 
2518aa9ebccSVladimir Oltean 	dev_dbg(dev, "Configuring MII-%s clocking\n",
2528aa9ebccSVladimir Oltean 		(role == XMII_MAC) ? "MAC" : "PHY");
2538aa9ebccSVladimir Oltean 	/* If role is MAC, disable IDIV
2548aa9ebccSVladimir Oltean 	 * If role is PHY, enable IDIV and configure for 1/1 divider
2558aa9ebccSVladimir Oltean 	 */
2568aa9ebccSVladimir Oltean 	rc = sja1105_cgu_idiv_config(priv, port, (role == XMII_PHY), 1);
2578aa9ebccSVladimir Oltean 	if (rc < 0)
2588aa9ebccSVladimir Oltean 		return rc;
2598aa9ebccSVladimir Oltean 
2608aa9ebccSVladimir Oltean 	/* Configure CLKSRC of MII_TX_CLK_n
2618aa9ebccSVladimir Oltean 	 *   * If role is MAC, select TX_CLK_n
2628aa9ebccSVladimir Oltean 	 *   * If role is PHY, select IDIV_n
2638aa9ebccSVladimir Oltean 	 */
2648aa9ebccSVladimir Oltean 	rc = sja1105_cgu_mii_tx_clk_config(priv, port, role);
2658aa9ebccSVladimir Oltean 	if (rc < 0)
2668aa9ebccSVladimir Oltean 		return rc;
2678aa9ebccSVladimir Oltean 
2688aa9ebccSVladimir Oltean 	/* Configure CLKSRC of MII_RX_CLK_n
2698aa9ebccSVladimir Oltean 	 * Select RX_CLK_n
2708aa9ebccSVladimir Oltean 	 */
2718aa9ebccSVladimir Oltean 	rc = sja1105_cgu_mii_rx_clk_config(priv, port);
2728aa9ebccSVladimir Oltean 	if (rc < 0)
2738aa9ebccSVladimir Oltean 		return rc;
2748aa9ebccSVladimir Oltean 
2758aa9ebccSVladimir Oltean 	if (role == XMII_PHY) {
2768aa9ebccSVladimir Oltean 		/* Per MII spec, the PHY (which is us) drives the TX_CLK pin */
2778aa9ebccSVladimir Oltean 
2788aa9ebccSVladimir Oltean 		/* Configure CLKSRC of EXT_TX_CLK_n
2798aa9ebccSVladimir Oltean 		 * Select IDIV_n
2808aa9ebccSVladimir Oltean 		 */
2818aa9ebccSVladimir Oltean 		rc = sja1105_cgu_mii_ext_tx_clk_config(priv, port);
2828aa9ebccSVladimir Oltean 		if (rc < 0)
2838aa9ebccSVladimir Oltean 			return rc;
2848aa9ebccSVladimir Oltean 
2858aa9ebccSVladimir Oltean 		/* Configure CLKSRC of EXT_RX_CLK_n
2868aa9ebccSVladimir Oltean 		 * Select IDIV_n
2878aa9ebccSVladimir Oltean 		 */
2888aa9ebccSVladimir Oltean 		rc = sja1105_cgu_mii_ext_rx_clk_config(priv, port);
2898aa9ebccSVladimir Oltean 		if (rc < 0)
2908aa9ebccSVladimir Oltean 			return rc;
2918aa9ebccSVladimir Oltean 	}
2928aa9ebccSVladimir Oltean 	return 0;
2938aa9ebccSVladimir Oltean }
2948aa9ebccSVladimir Oltean 
2958aa9ebccSVladimir Oltean static void
2968aa9ebccSVladimir Oltean sja1105_cgu_pll_control_packing(void *buf, struct sja1105_cgu_pll_ctrl *cmd,
2978aa9ebccSVladimir Oltean 				enum packing_op op)
2988aa9ebccSVladimir Oltean {
2998aa9ebccSVladimir Oltean 	const int size = 4;
3008aa9ebccSVladimir Oltean 
3018aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->pllclksrc, 28, 24, size, op);
3028aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->msel,      23, 16, size, op);
3038aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->autoblock, 11, 11, size, op);
3048aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->psel,       9,  8, size, op);
3058aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->direct,     7,  7, size, op);
3068aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->fbsel,      6,  6, size, op);
3078aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->bypass,     1,  1, size, op);
3088aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->pd,         0,  0, size, op);
3098aa9ebccSVladimir Oltean }
3108aa9ebccSVladimir Oltean 
3118aa9ebccSVladimir Oltean static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv,
3128aa9ebccSVladimir Oltean 					   int port, sja1105_speed_t speed)
3138aa9ebccSVladimir Oltean {
3148aa9ebccSVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
3158aa9ebccSVladimir Oltean 	struct sja1105_cgu_mii_ctrl txc;
3168aa9ebccSVladimir Oltean 	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
3178aa9ebccSVladimir Oltean 	int clksrc;
3188aa9ebccSVladimir Oltean 
3198aa9ebccSVladimir Oltean 	if (speed == SJA1105_SPEED_1000MBPS) {
3208aa9ebccSVladimir Oltean 		clksrc = CLKSRC_PLL0;
3218aa9ebccSVladimir Oltean 	} else {
3228aa9ebccSVladimir Oltean 		int clk_sources[] = {CLKSRC_IDIV0, CLKSRC_IDIV1, CLKSRC_IDIV2,
3238aa9ebccSVladimir Oltean 				     CLKSRC_IDIV3, CLKSRC_IDIV4};
3248aa9ebccSVladimir Oltean 		clksrc = clk_sources[port];
3258aa9ebccSVladimir Oltean 	}
3268aa9ebccSVladimir Oltean 
3278aa9ebccSVladimir Oltean 	/* RGMII: 125MHz for 1000, 25MHz for 100, 2.5MHz for 10 */
3288aa9ebccSVladimir Oltean 	txc.clksrc = clksrc;
3298aa9ebccSVladimir Oltean 	/* Autoblock clk while changing clksrc */
3308aa9ebccSVladimir Oltean 	txc.autoblock = 1;
3318aa9ebccSVladimir Oltean 	/* Power Down off => enabled */
3328aa9ebccSVladimir Oltean 	txc.pd = 0;
3338aa9ebccSVladimir Oltean 	sja1105_cgu_mii_control_packing(packed_buf, &txc, PACK);
3348aa9ebccSVladimir Oltean 
335*1bd44870SVladimir Oltean 	return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgmii_tx_clk[port],
3368aa9ebccSVladimir Oltean 				packed_buf, SJA1105_SIZE_CGU_CMD);
3378aa9ebccSVladimir Oltean }
3388aa9ebccSVladimir Oltean 
3398aa9ebccSVladimir Oltean /* AGU */
3408aa9ebccSVladimir Oltean static void
3418aa9ebccSVladimir Oltean sja1105_cfg_pad_mii_tx_packing(void *buf, struct sja1105_cfg_pad_mii_tx *cmd,
3428aa9ebccSVladimir Oltean 			       enum packing_op op)
3438aa9ebccSVladimir Oltean {
3448aa9ebccSVladimir Oltean 	const int size = 4;
3458aa9ebccSVladimir Oltean 
3468aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->d32_os,   28, 27, size, op);
3478aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->d32_ipud, 25, 24, size, op);
3488aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->d10_os,   20, 19, size, op);
3498aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->d10_ipud, 17, 16, size, op);
3508aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->ctrl_os,  12, 11, size, op);
3518aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->ctrl_ipud, 9,  8, size, op);
3528aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->clk_os,    4,  3, size, op);
3538aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->clk_ih,    2,  2, size, op);
3548aa9ebccSVladimir Oltean 	sja1105_packing(buf, &cmd->clk_ipud,  1,  0, size, op);
3558aa9ebccSVladimir Oltean }
3568aa9ebccSVladimir Oltean 
3578aa9ebccSVladimir Oltean static int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv,
3588aa9ebccSVladimir Oltean 					   int port)
3598aa9ebccSVladimir Oltean {
3608aa9ebccSVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
3618aa9ebccSVladimir Oltean 	struct sja1105_cfg_pad_mii_tx pad_mii_tx;
3628aa9ebccSVladimir Oltean 	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
3638aa9ebccSVladimir Oltean 
3648aa9ebccSVladimir Oltean 	/* Payload */
3658aa9ebccSVladimir Oltean 	pad_mii_tx.d32_os    = 3; /* TXD[3:2] output stage: */
3668aa9ebccSVladimir Oltean 				  /*          high noise/high speed */
3678aa9ebccSVladimir Oltean 	pad_mii_tx.d10_os    = 3; /* TXD[1:0] output stage: */
3688aa9ebccSVladimir Oltean 				  /*          high noise/high speed */
3698aa9ebccSVladimir Oltean 	pad_mii_tx.d32_ipud  = 2; /* TXD[3:2] input stage: */
3708aa9ebccSVladimir Oltean 				  /*          plain input (default) */
3718aa9ebccSVladimir Oltean 	pad_mii_tx.d10_ipud  = 2; /* TXD[1:0] input stage: */
3728aa9ebccSVladimir Oltean 				  /*          plain input (default) */
3738aa9ebccSVladimir Oltean 	pad_mii_tx.ctrl_os   = 3; /* TX_CTL / TX_ER output stage */
3748aa9ebccSVladimir Oltean 	pad_mii_tx.ctrl_ipud = 2; /* TX_CTL / TX_ER input stage (default) */
3758aa9ebccSVladimir Oltean 	pad_mii_tx.clk_os    = 3; /* TX_CLK output stage */
3768aa9ebccSVladimir Oltean 	pad_mii_tx.clk_ih    = 0; /* TX_CLK input hysteresis (default) */
3778aa9ebccSVladimir Oltean 	pad_mii_tx.clk_ipud  = 2; /* TX_CLK input stage (default) */
3788aa9ebccSVladimir Oltean 	sja1105_cfg_pad_mii_tx_packing(packed_buf, &pad_mii_tx, PACK);
3798aa9ebccSVladimir Oltean 
380*1bd44870SVladimir Oltean 	return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_tx[port],
3818aa9ebccSVladimir Oltean 				packed_buf, SJA1105_SIZE_CGU_CMD);
3828aa9ebccSVladimir Oltean }
3838aa9ebccSVladimir Oltean 
384c05ec3d4SVladimir Oltean static void
385c05ec3d4SVladimir Oltean sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
386c05ec3d4SVladimir Oltean 			       enum packing_op op)
387c05ec3d4SVladimir Oltean {
388c05ec3d4SVladimir Oltean 	const int size = SJA1105_SIZE_CGU_CMD;
389c05ec3d4SVladimir Oltean 
390c05ec3d4SVladimir Oltean 	sja1105_packing(buf, &cmd->rxc_stable_ovr, 15, 15, size, op);
391c05ec3d4SVladimir Oltean 	sja1105_packing(buf, &cmd->rxc_delay,      14, 10, size, op);
392c05ec3d4SVladimir Oltean 	sja1105_packing(buf, &cmd->rxc_bypass,      9,  9, size, op);
393c05ec3d4SVladimir Oltean 	sja1105_packing(buf, &cmd->rxc_pd,          8,  8, size, op);
394c05ec3d4SVladimir Oltean 	sja1105_packing(buf, &cmd->txc_stable_ovr,  7,  7, size, op);
395c05ec3d4SVladimir Oltean 	sja1105_packing(buf, &cmd->txc_delay,       6,  2, size, op);
396c05ec3d4SVladimir Oltean 	sja1105_packing(buf, &cmd->txc_bypass,      1,  1, size, op);
397c05ec3d4SVladimir Oltean 	sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
398c05ec3d4SVladimir Oltean }
399c05ec3d4SVladimir Oltean 
400c05ec3d4SVladimir Oltean /* Valid range in degrees is an integer between 73.8 and 101.7 */
40109c1b412SVladimir Oltean static u64 sja1105_rgmii_delay(u64 phase)
402c05ec3d4SVladimir Oltean {
403c05ec3d4SVladimir Oltean 	/* UM11040.pdf: The delay in degree phase is 73.8 + delay_tune * 0.9.
404c05ec3d4SVladimir Oltean 	 * To avoid floating point operations we'll multiply by 10
405c05ec3d4SVladimir Oltean 	 * and get 1 decimal point precision.
406c05ec3d4SVladimir Oltean 	 */
407c05ec3d4SVladimir Oltean 	phase *= 10;
408c05ec3d4SVladimir Oltean 	return (phase - 738) / 9;
409c05ec3d4SVladimir Oltean }
410c05ec3d4SVladimir Oltean 
411c05ec3d4SVladimir Oltean /* The RGMII delay setup procedure is 2-step and gets called upon each
412c05ec3d4SVladimir Oltean  * .phylink_mac_config. Both are strategic.
413c05ec3d4SVladimir Oltean  * The reason is that the RX Tunable Delay Line of the SJA1105 MAC has issues
414c05ec3d4SVladimir Oltean  * with recovering from a frequency change of the link partner's RGMII clock.
415c05ec3d4SVladimir Oltean  * The easiest way to recover from this is to temporarily power down the TDL,
416c05ec3d4SVladimir Oltean  * as it will re-lock at the new frequency afterwards.
417c05ec3d4SVladimir Oltean  */
418c05ec3d4SVladimir Oltean int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
419c05ec3d4SVladimir Oltean {
420c05ec3d4SVladimir Oltean 	const struct sja1105_private *priv = ctx;
421c05ec3d4SVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
422c05ec3d4SVladimir Oltean 	struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
423c05ec3d4SVladimir Oltean 	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
424c05ec3d4SVladimir Oltean 	int rc;
425c05ec3d4SVladimir Oltean 
426c05ec3d4SVladimir Oltean 	if (priv->rgmii_rx_delay[port])
427c05ec3d4SVladimir Oltean 		pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
428c05ec3d4SVladimir Oltean 	if (priv->rgmii_tx_delay[port])
429c05ec3d4SVladimir Oltean 		pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
430c05ec3d4SVladimir Oltean 
431c05ec3d4SVladimir Oltean 	/* Stage 1: Turn the RGMII delay lines off. */
432c05ec3d4SVladimir Oltean 	pad_mii_id.rxc_bypass = 1;
433c05ec3d4SVladimir Oltean 	pad_mii_id.rxc_pd = 1;
434c05ec3d4SVladimir Oltean 	pad_mii_id.txc_bypass = 1;
435c05ec3d4SVladimir Oltean 	pad_mii_id.txc_pd = 1;
436c05ec3d4SVladimir Oltean 	sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
437c05ec3d4SVladimir Oltean 
438*1bd44870SVladimir Oltean 	rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
439c05ec3d4SVladimir Oltean 			      packed_buf, SJA1105_SIZE_CGU_CMD);
440c05ec3d4SVladimir Oltean 	if (rc < 0)
441c05ec3d4SVladimir Oltean 		return rc;
442c05ec3d4SVladimir Oltean 
443c05ec3d4SVladimir Oltean 	/* Stage 2: Turn the RGMII delay lines on. */
444c05ec3d4SVladimir Oltean 	if (priv->rgmii_rx_delay[port]) {
445c05ec3d4SVladimir Oltean 		pad_mii_id.rxc_bypass = 0;
446c05ec3d4SVladimir Oltean 		pad_mii_id.rxc_pd = 0;
447c05ec3d4SVladimir Oltean 	}
448c05ec3d4SVladimir Oltean 	if (priv->rgmii_tx_delay[port]) {
449c05ec3d4SVladimir Oltean 		pad_mii_id.txc_bypass = 0;
450c05ec3d4SVladimir Oltean 		pad_mii_id.txc_pd = 0;
451c05ec3d4SVladimir Oltean 	}
452c05ec3d4SVladimir Oltean 	sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
453c05ec3d4SVladimir Oltean 
454*1bd44870SVladimir Oltean 	return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
455c05ec3d4SVladimir Oltean 				packed_buf, SJA1105_SIZE_CGU_CMD);
456c05ec3d4SVladimir Oltean }
457c05ec3d4SVladimir Oltean 
458c05ec3d4SVladimir Oltean static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
459c05ec3d4SVladimir Oltean 					sja1105_mii_role_t role)
4608aa9ebccSVladimir Oltean {
4618aa9ebccSVladimir Oltean 	struct device *dev = priv->ds->dev;
4628aa9ebccSVladimir Oltean 	struct sja1105_mac_config_entry *mac;
4638aa9ebccSVladimir Oltean 	sja1105_speed_t speed;
4648aa9ebccSVladimir Oltean 	int rc;
4658aa9ebccSVladimir Oltean 
4668aa9ebccSVladimir Oltean 	mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
4678aa9ebccSVladimir Oltean 	speed = mac[port].speed;
4688aa9ebccSVladimir Oltean 
4698aa9ebccSVladimir Oltean 	dev_dbg(dev, "Configuring port %d RGMII at speed %dMbps\n",
4708aa9ebccSVladimir Oltean 		port, speed);
4718aa9ebccSVladimir Oltean 
4728aa9ebccSVladimir Oltean 	switch (speed) {
4738aa9ebccSVladimir Oltean 	case SJA1105_SPEED_1000MBPS:
4748aa9ebccSVladimir Oltean 		/* 1000Mbps, IDIV disabled (125 MHz) */
4758aa9ebccSVladimir Oltean 		rc = sja1105_cgu_idiv_config(priv, port, false, 1);
4768aa9ebccSVladimir Oltean 		break;
4778aa9ebccSVladimir Oltean 	case SJA1105_SPEED_100MBPS:
4788aa9ebccSVladimir Oltean 		/* 100Mbps, IDIV enabled, divide by 1 (25 MHz) */
4798aa9ebccSVladimir Oltean 		rc = sja1105_cgu_idiv_config(priv, port, true, 1);
4808aa9ebccSVladimir Oltean 		break;
4818aa9ebccSVladimir Oltean 	case SJA1105_SPEED_10MBPS:
4828aa9ebccSVladimir Oltean 		/* 10Mbps, IDIV enabled, divide by 10 (2.5 MHz) */
4838aa9ebccSVladimir Oltean 		rc = sja1105_cgu_idiv_config(priv, port, true, 10);
4848aa9ebccSVladimir Oltean 		break;
4858aa9ebccSVladimir Oltean 	case SJA1105_SPEED_AUTO:
4868aa9ebccSVladimir Oltean 		/* Skip CGU configuration if there is no speed available
4878aa9ebccSVladimir Oltean 		 * (e.g. link is not established yet)
4888aa9ebccSVladimir Oltean 		 */
4898aa9ebccSVladimir Oltean 		dev_dbg(dev, "Speed not available, skipping CGU config\n");
4908aa9ebccSVladimir Oltean 		return 0;
4918aa9ebccSVladimir Oltean 	default:
4928aa9ebccSVladimir Oltean 		rc = -EINVAL;
4938aa9ebccSVladimir Oltean 	}
4948aa9ebccSVladimir Oltean 
4958aa9ebccSVladimir Oltean 	if (rc < 0) {
4968aa9ebccSVladimir Oltean 		dev_err(dev, "Failed to configure idiv\n");
4978aa9ebccSVladimir Oltean 		return rc;
4988aa9ebccSVladimir Oltean 	}
4998aa9ebccSVladimir Oltean 	rc = sja1105_cgu_rgmii_tx_clk_config(priv, port, speed);
5008aa9ebccSVladimir Oltean 	if (rc < 0) {
5018aa9ebccSVladimir Oltean 		dev_err(dev, "Failed to configure RGMII Tx clock\n");
5028aa9ebccSVladimir Oltean 		return rc;
5038aa9ebccSVladimir Oltean 	}
5048aa9ebccSVladimir Oltean 	rc = sja1105_rgmii_cfg_pad_tx_config(priv, port);
5058aa9ebccSVladimir Oltean 	if (rc < 0) {
5068aa9ebccSVladimir Oltean 		dev_err(dev, "Failed to configure Tx pad registers\n");
5078aa9ebccSVladimir Oltean 		return rc;
5088aa9ebccSVladimir Oltean 	}
509f5b8631cSVladimir Oltean 	if (!priv->info->setup_rgmii_delay)
5108aa9ebccSVladimir Oltean 		return 0;
511c05ec3d4SVladimir Oltean 	/* The role has no hardware effect for RGMII. However we use it as
512c05ec3d4SVladimir Oltean 	 * a proxy for this interface being a MAC-to-MAC connection, with
513c05ec3d4SVladimir Oltean 	 * the RGMII internal delays needing to be applied by us.
514c05ec3d4SVladimir Oltean 	 */
515c05ec3d4SVladimir Oltean 	if (role == XMII_MAC)
516c05ec3d4SVladimir Oltean 		return 0;
517f5b8631cSVladimir Oltean 
518f5b8631cSVladimir Oltean 	return priv->info->setup_rgmii_delay(priv, port);
5198aa9ebccSVladimir Oltean }
5208aa9ebccSVladimir Oltean 
5218aa9ebccSVladimir Oltean static int sja1105_cgu_rmii_ref_clk_config(struct sja1105_private *priv,
5228aa9ebccSVladimir Oltean 					   int port)
5238aa9ebccSVladimir Oltean {
5248aa9ebccSVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
5258aa9ebccSVladimir Oltean 	struct sja1105_cgu_mii_ctrl ref_clk;
5268aa9ebccSVladimir Oltean 	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
5278aa9ebccSVladimir Oltean 	const int clk_sources[] = {
5288aa9ebccSVladimir Oltean 		CLKSRC_MII0_TX_CLK,
5298aa9ebccSVladimir Oltean 		CLKSRC_MII1_TX_CLK,
5308aa9ebccSVladimir Oltean 		CLKSRC_MII2_TX_CLK,
5318aa9ebccSVladimir Oltean 		CLKSRC_MII3_TX_CLK,
5328aa9ebccSVladimir Oltean 		CLKSRC_MII4_TX_CLK,
5338aa9ebccSVladimir Oltean 	};
5348aa9ebccSVladimir Oltean 
5358aa9ebccSVladimir Oltean 	/* Payload for packed_buf */
5368aa9ebccSVladimir Oltean 	ref_clk.clksrc    = clk_sources[port];
5378aa9ebccSVladimir Oltean 	ref_clk.autoblock = 1;      /* Autoblock clk while changing clksrc */
5388aa9ebccSVladimir Oltean 	ref_clk.pd        = 0;      /* Power Down off => enabled */
5398aa9ebccSVladimir Oltean 	sja1105_cgu_mii_control_packing(packed_buf, &ref_clk, PACK);
5408aa9ebccSVladimir Oltean 
541*1bd44870SVladimir Oltean 	return sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_ref_clk[port],
5428aa9ebccSVladimir Oltean 				packed_buf, SJA1105_SIZE_CGU_CMD);
5438aa9ebccSVladimir Oltean }
5448aa9ebccSVladimir Oltean 
5458aa9ebccSVladimir Oltean static int
5468aa9ebccSVladimir Oltean sja1105_cgu_rmii_ext_tx_clk_config(struct sja1105_private *priv, int port)
5478aa9ebccSVladimir Oltean {
5488aa9ebccSVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
5498aa9ebccSVladimir Oltean 	struct sja1105_cgu_mii_ctrl ext_tx_clk;
5508aa9ebccSVladimir Oltean 	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
5518aa9ebccSVladimir Oltean 
5528aa9ebccSVladimir Oltean 	/* Payload for packed_buf */
5538aa9ebccSVladimir Oltean 	ext_tx_clk.clksrc    = CLKSRC_PLL1;
5548aa9ebccSVladimir Oltean 	ext_tx_clk.autoblock = 1;   /* Autoblock clk while changing clksrc */
5558aa9ebccSVladimir Oltean 	ext_tx_clk.pd        = 0;   /* Power Down off => enabled */
5568aa9ebccSVladimir Oltean 	sja1105_cgu_mii_control_packing(packed_buf, &ext_tx_clk, PACK);
5578aa9ebccSVladimir Oltean 
558*1bd44870SVladimir Oltean 	return sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_ext_tx_clk[port],
5598aa9ebccSVladimir Oltean 				packed_buf, SJA1105_SIZE_CGU_CMD);
5608aa9ebccSVladimir Oltean }
5618aa9ebccSVladimir Oltean 
5628aa9ebccSVladimir Oltean static int sja1105_cgu_rmii_pll_config(struct sja1105_private *priv)
5638aa9ebccSVladimir Oltean {
5648aa9ebccSVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
5658aa9ebccSVladimir Oltean 	u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
5668aa9ebccSVladimir Oltean 	struct sja1105_cgu_pll_ctrl pll = {0};
5678aa9ebccSVladimir Oltean 	struct device *dev = priv->ds->dev;
5688aa9ebccSVladimir Oltean 	int rc;
5698aa9ebccSVladimir Oltean 
5708aa9ebccSVladimir Oltean 	/* PLL1 must be enabled and output 50 Mhz.
5718aa9ebccSVladimir Oltean 	 * This is done by writing first 0x0A010941 to
5728aa9ebccSVladimir Oltean 	 * the PLL_1_C register and then deasserting
5738aa9ebccSVladimir Oltean 	 * power down (PD) 0x0A010940.
5748aa9ebccSVladimir Oltean 	 */
5758aa9ebccSVladimir Oltean 
5768aa9ebccSVladimir Oltean 	/* Step 1: PLL1 setup for 50Mhz */
5778aa9ebccSVladimir Oltean 	pll.pllclksrc = 0xA;
5788aa9ebccSVladimir Oltean 	pll.msel      = 0x1;
5798aa9ebccSVladimir Oltean 	pll.autoblock = 0x1;
5808aa9ebccSVladimir Oltean 	pll.psel      = 0x1;
5818aa9ebccSVladimir Oltean 	pll.direct    = 0x0;
5828aa9ebccSVladimir Oltean 	pll.fbsel     = 0x1;
5838aa9ebccSVladimir Oltean 	pll.bypass    = 0x0;
5848aa9ebccSVladimir Oltean 	pll.pd        = 0x1;
5858aa9ebccSVladimir Oltean 
5868aa9ebccSVladimir Oltean 	sja1105_cgu_pll_control_packing(packed_buf, &pll, PACK);
587*1bd44870SVladimir Oltean 	rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_pll1, packed_buf,
588*1bd44870SVladimir Oltean 			      SJA1105_SIZE_CGU_CMD);
5898aa9ebccSVladimir Oltean 	if (rc < 0) {
5908aa9ebccSVladimir Oltean 		dev_err(dev, "failed to configure PLL1 for 50MHz\n");
5918aa9ebccSVladimir Oltean 		return rc;
5928aa9ebccSVladimir Oltean 	}
5938aa9ebccSVladimir Oltean 
5948aa9ebccSVladimir Oltean 	/* Step 2: Enable PLL1 */
5958aa9ebccSVladimir Oltean 	pll.pd = 0x0;
5968aa9ebccSVladimir Oltean 
5978aa9ebccSVladimir Oltean 	sja1105_cgu_pll_control_packing(packed_buf, &pll, PACK);
598*1bd44870SVladimir Oltean 	rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_pll1, packed_buf,
599*1bd44870SVladimir Oltean 			      SJA1105_SIZE_CGU_CMD);
6008aa9ebccSVladimir Oltean 	if (rc < 0) {
6018aa9ebccSVladimir Oltean 		dev_err(dev, "failed to enable PLL1\n");
6028aa9ebccSVladimir Oltean 		return rc;
6038aa9ebccSVladimir Oltean 	}
6048aa9ebccSVladimir Oltean 	return rc;
6058aa9ebccSVladimir Oltean }
6068aa9ebccSVladimir Oltean 
6078aa9ebccSVladimir Oltean static int sja1105_rmii_clocking_setup(struct sja1105_private *priv, int port,
6088aa9ebccSVladimir Oltean 				       sja1105_mii_role_t role)
6098aa9ebccSVladimir Oltean {
6108aa9ebccSVladimir Oltean 	struct device *dev = priv->ds->dev;
6118aa9ebccSVladimir Oltean 	int rc;
6128aa9ebccSVladimir Oltean 
6138aa9ebccSVladimir Oltean 	dev_dbg(dev, "Configuring RMII-%s clocking\n",
6148aa9ebccSVladimir Oltean 		(role == XMII_MAC) ? "MAC" : "PHY");
6158aa9ebccSVladimir Oltean 	/* AH1601.pdf chapter 2.5.1. Sources */
6168aa9ebccSVladimir Oltean 	if (role == XMII_MAC) {
6178aa9ebccSVladimir Oltean 		/* Configure and enable PLL1 for 50Mhz output */
6188aa9ebccSVladimir Oltean 		rc = sja1105_cgu_rmii_pll_config(priv);
6198aa9ebccSVladimir Oltean 		if (rc < 0)
6208aa9ebccSVladimir Oltean 			return rc;
6218aa9ebccSVladimir Oltean 	}
6228aa9ebccSVladimir Oltean 	/* Disable IDIV for this port */
6238aa9ebccSVladimir Oltean 	rc = sja1105_cgu_idiv_config(priv, port, false, 1);
6248aa9ebccSVladimir Oltean 	if (rc < 0)
6258aa9ebccSVladimir Oltean 		return rc;
6268aa9ebccSVladimir Oltean 	/* Source to sink mappings */
6278aa9ebccSVladimir Oltean 	rc = sja1105_cgu_rmii_ref_clk_config(priv, port);
6288aa9ebccSVladimir Oltean 	if (rc < 0)
6298aa9ebccSVladimir Oltean 		return rc;
6308aa9ebccSVladimir Oltean 	if (role == XMII_MAC) {
6318aa9ebccSVladimir Oltean 		rc = sja1105_cgu_rmii_ext_tx_clk_config(priv, port);
6328aa9ebccSVladimir Oltean 		if (rc < 0)
6338aa9ebccSVladimir Oltean 			return rc;
6348aa9ebccSVladimir Oltean 	}
6358aa9ebccSVladimir Oltean 	return 0;
6368aa9ebccSVladimir Oltean }
6378aa9ebccSVladimir Oltean 
6388aa9ebccSVladimir Oltean int sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
6398aa9ebccSVladimir Oltean {
6408aa9ebccSVladimir Oltean 	struct sja1105_xmii_params_entry *mii;
6418aa9ebccSVladimir Oltean 	struct device *dev = priv->ds->dev;
6428aa9ebccSVladimir Oltean 	sja1105_phy_interface_t phy_mode;
6438aa9ebccSVladimir Oltean 	sja1105_mii_role_t role;
6448aa9ebccSVladimir Oltean 	int rc;
6458aa9ebccSVladimir Oltean 
6468aa9ebccSVladimir Oltean 	mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
6478aa9ebccSVladimir Oltean 
6488aa9ebccSVladimir Oltean 	/* RGMII etc */
6498aa9ebccSVladimir Oltean 	phy_mode = mii->xmii_mode[port];
6508aa9ebccSVladimir Oltean 	/* MAC or PHY, for applicable types (not RGMII) */
6518aa9ebccSVladimir Oltean 	role = mii->phy_mac[port];
6528aa9ebccSVladimir Oltean 
6538aa9ebccSVladimir Oltean 	switch (phy_mode) {
6548aa9ebccSVladimir Oltean 	case XMII_MODE_MII:
6558aa9ebccSVladimir Oltean 		rc = sja1105_mii_clocking_setup(priv, port, role);
6568aa9ebccSVladimir Oltean 		break;
6578aa9ebccSVladimir Oltean 	case XMII_MODE_RMII:
6588aa9ebccSVladimir Oltean 		rc = sja1105_rmii_clocking_setup(priv, port, role);
6598aa9ebccSVladimir Oltean 		break;
6608aa9ebccSVladimir Oltean 	case XMII_MODE_RGMII:
661c05ec3d4SVladimir Oltean 		rc = sja1105_rgmii_clocking_setup(priv, port, role);
6628aa9ebccSVladimir Oltean 		break;
6638aa9ebccSVladimir Oltean 	default:
6648aa9ebccSVladimir Oltean 		dev_err(dev, "Invalid interface mode specified: %d\n",
6658aa9ebccSVladimir Oltean 			phy_mode);
6668aa9ebccSVladimir Oltean 		return -EINVAL;
6678aa9ebccSVladimir Oltean 	}
6688aa9ebccSVladimir Oltean 	if (rc)
6698aa9ebccSVladimir Oltean 		dev_err(dev, "Clocking setup for port %d failed: %d\n",
6708aa9ebccSVladimir Oltean 			port, rc);
6718aa9ebccSVladimir Oltean 	return rc;
6728aa9ebccSVladimir Oltean }
6738aa9ebccSVladimir Oltean 
6748aa9ebccSVladimir Oltean int sja1105_clocking_setup(struct sja1105_private *priv)
6758aa9ebccSVladimir Oltean {
6768aa9ebccSVladimir Oltean 	int port, rc;
6778aa9ebccSVladimir Oltean 
6788aa9ebccSVladimir Oltean 	for (port = 0; port < SJA1105_NUM_PORTS; port++) {
6798aa9ebccSVladimir Oltean 		rc = sja1105_clocking_setup_port(priv, port);
6808aa9ebccSVladimir Oltean 		if (rc < 0)
6818aa9ebccSVladimir Oltean 			return rc;
6828aa9ebccSVladimir Oltean 	}
6838aa9ebccSVladimir Oltean 	return 0;
6848aa9ebccSVladimir Oltean }
685