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