Hi Andrew, On 2023/1/18 21:40, Andrew Lunn wrote: > On Wed, Jan 11, 2023 at 05:20:18PM +0800, Frank.Sae wrote: >> Hi Andrew, >> >> On 2023/1/6 21:55, Andrew Lunn wrote: >>>>> Why is this needed? When the MAC driver connects to the PHY, it passes >>>>> phy-mode. For RGMII, this is one of: >>>> >>>>> linux/phy.h: PHY_INTERFACE_MODE_RGMII, >>>>> linux/phy.h: PHY_INTERFACE_MODE_RGMII_ID, >>>>> linux/phy.h: PHY_INTERFACE_MODE_RGMII_RXID, >>>>> linux/phy.h: PHY_INTERFACE_MODE_RGMII_TXID, >>>>> >>>>> This tells you if you need to add a delay for the RX clock line, the >>>>> TX clock line, or both. That is all you need to know for basic RGMII >>>>> delays. >>>>> >>>> >>>> This basic delay can be controlled by hardware or the phy-mode which >>>> passes from MAC driver. >>>> Default value depends on power on strapping, according to the voltage >>>> of RXD0 pin (low = 0, turn off; high = 1, turn on). >>>> >>>> Add this for the case that This basic delay is controlled by hardware, >>>> and software don't change this. >>> >>> You should always do what phy-mode contains. Always. We have had >>> problems in the past where a PHY driver ignored the phy-mode, and left >>> the PHY however it was strapped. Which worked. But developers put the >>> wrong phy-mode value in DT. Then somebody had a board which actually >>> required that the DT value really did work, because the strapping was >>> wrong. So the driver was fixed to respect the PHY mode, made that >>> board work, and broke all the other boards which had the wrong >>> phy-mode in DT. >>> >>> If the user want the driver to leave the mode alone, use the >>> strapping, they should use PHY_INTERFACE_MODE_NA. It is not well >>> documented, but it is used in a few places. However, i don't recommend >>> it. >>> >> >> RX delay = rx-delay-basic (0ns or 1.9ns) + x-delay-additional-ps >> (N*150ps, N = 0 ~ 15) >> If rx-delay-basic is removed and controlled by phy-mode. >> when phy-mode is rgmii-id or rgmii-rxid, RX delay is 1.9ns + N*150ps. >> But sometimes 1.9ns is still too big, we just need 0ns + N*150ps. >> >> For this case, can we do like following ? >> rx-internal-delay-ps: >> enum: [ 0, 150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500, >> 1650, 1800, 1900, 1950, 2050, 2100, 2200, 2250, 2350, 2500, 2650, 2800, >> 2950, 3100, 3250, 3400, 3550, 3700, 3850, 4000, 4150 ] >> default: 0 >> rx-internal-delay-ps is 0ns + N*150ps and 1.9ns + N*150ps. >> And check whether need rx-delay-basic (1.9ns) by the val of >> rx-internal-delay-ps? > > Please take a look at phy_get_internal_delay() and the drivers which > use it. > > Andrew Thanks. But it may be not suitable. rx-internal-delay-ps has two part: 0ns + N*150ps = 0,150,300,450,600,750,900,1050,1200,1350,1500,1650,1800,1950,2100,2250 1.9ns + N*150ps = 1900,2050,2200,2350,2500,2650,2800,2950,3100,3250,3400,3550,3700,3850,4000,4150 The problem is "1900,2050,2200" is less than "2250". If I take this two parts in one sorted table, there will be three tables, one for tx-internal-delay-ps, one for rx-internal-delay-ps and one for the rx index to reg(delay value and 1.9ns on or off) value. So we tend to use the following methods. #define YT8521_CCR_RXC_DLY_1_900_NS 1900 #define YT8521_RC1R_RGMII_0_000_NS 0 #define YT8521_RC1R_RGMII_0_150_NS 1 ... #define YT8521_RC1R_RGMII_2_250_NS 15 struct ytphy_cfg_reg_map { u32 cfg; u32 reg; }; static const struct ytphy_cfg_reg_map ytphy_rgmii_delays[] = { /* for tx delay / rx delay with YT8521_CCR_RXC_DLY_EN is not set. */ { 0, YT8521_RC1R_RGMII_0_000_NS }, { 150, YT8521_RC1R_RGMII_0_150_NS }, ... { 2250, YT8521_RC1R_RGMII_2_250_NS }, /* only for rx delay with YT8521_CCR_RXC_DLY_EN is set. */ { 0 + YT8521_CCR_RXC_DLY_1_900_NS,YT8521_RC1R_RGMII_0_000_NS }, { 150 + YT8521_CCR_RXC_DLY_1_900_NS,YT8521_RC1R_RGMII_0_150_NS }, ... { 2250 + YT8521_CCR_RXC_DLY_1_900_NS,YT8521_RC1R_RGMII_2_250_NS } }; static u32 ytphy_get_delay_reg_value(struct phy_device *phydev, const char *prop_name, const struct ytphy_cfg_reg_map *tbl, int tb_size, u16 *rxc_dly_en, u32 dflt) { struct device_node *node = phydev->mdio.dev.of_node; int tb_size_half = tb_size / 2; u32 val; int i; if (of_property_read_u32(node, prop_name, &val)) return dflt; /* when rxc_dly_en is NULL, it is get the delay for tx, only half of * tb_size is valid. */ if (!rxc_dly_en) tb_size = tb_size_half; for (i = 0; i < tb_size; i++) { if (tbl[i].cfg == val) { if (rxc_dly_en && i < tb_size_half) *rxc_dly_en = 0; return tbl[i].reg; } } phydev_warn(phydev, "Unsupported value %d for %s using default (%u)\n", val, prop_name, dflt); return dflt; } static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev) { int tb_size = ARRAY_SIZE(ytphy_rgmii_delays); u16 rxc_dly_en = YT8521_CCR_RXC_DLY_EN; u32 rx_reg, tx_reg; u16 mask, val = 0; int ret; rx_reg = ytphy_get_delay_reg_value(phydev, "rx-internal-delay-ps", ytphy_rgmii_delays, tb_size, &rxc_dly_en, YT8521_RC1R_RGMII_0_000_NS); tx_reg = ytphy_get_delay_reg_value(phydev, "tx-internal-delay-ps", ytphy_rgmii_delays, tb_size, NULL, YT8521_RC1R_RGMII_0_150_NS); switch (phydev->interface) { case PHY_INTERFACE_MODE_RGMII: rxc_dly_en = 0; break; case PHY_INTERFACE_MODE_RGMII_RXID: val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg); break; case PHY_INTERFACE_MODE_RGMII_TXID: rxc_dly_en = 0; val |= FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg); break; case PHY_INTERFACE_MODE_RGMII_ID: val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg) | FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg); break; default: /* do not support other modes */ return -EOPNOTSUPP; } ret = ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG, YT8521_CCR_RXC_DLY_EN, rxc_dly_en); if (ret < 0) return ret; /* Generally, it is not necessary to adjust YT8521_RC1R_FE_TX_DELAY */ mask = YT8521_RC1R_RX_DELAY_MASK | YT8521_RC1R_GE_TX_DELAY_MASK; return ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, mask, val); }