// SPDX-License-Identifier: GPL-2.0+ /* * Motorcomm 8531 PHY driver. * * Copyright (C) 2023 StarFive Technology Co., Ltd. */ #include #include #include #include #include #define PHY_ID_YT8531 0x4f51e91b #define PHY_ID_MASK GENMASK(31, 0) /* Extended Register's Address Offset Register */ #define YTPHY_PAGE_SELECT 0x1E /* Extended Register's Data Register */ #define YTPHY_PAGE_DATA 0x1F #define YTPHY_SYNCE_CFG_REG 0xA012 #define YTPHY_DTS_OUTPUT_CLK_DIS 0 #define YTPHY_DTS_OUTPUT_CLK_25M 25000000 #define YTPHY_DTS_OUTPUT_CLK_125M 125000000 #define YT8531_SCR_SYNCE_ENABLE BIT(6) /* 1b0 output 25m clock *default* * 1b1 output 125m clock */ #define YT8531_SCR_CLK_FRE_SEL_125M BIT(4) #define YT8531_SCR_CLK_SRC_MASK GENMASK(3, 1) #define YT8531_SCR_CLK_SRC_PLL_125M 0 #define YT8531_SCR_CLK_SRC_UTP_RX 1 #define YT8531_SCR_CLK_SRC_SDS_RX 2 #define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL 3 #define YT8531_SCR_CLK_SRC_REF_25M 4 #define YT8531_SCR_CLK_SRC_SSC_25M 5 /* 1b0 use original tx_clk_rgmii *default* * 1b1 use inverted tx_clk_rgmii. */ #define YT8531_RC1R_TX_CLK_SEL_INVERTED BIT(14) #define YT8531_RC1R_RX_DELAY_MASK GENMASK(13, 10) #define YT8531_RC1R_FE_TX_DELAY_MASK GENMASK(7, 4) #define YT8531_RC1R_GE_TX_DELAY_MASK GENMASK(3, 0) #define YT8531_RC1R_RGMII_0_000_NS 0 #define YT8531_RC1R_RGMII_0_150_NS 1 #define YT8531_RC1R_RGMII_0_300_NS 2 #define YT8531_RC1R_RGMII_0_450_NS 3 #define YT8531_RC1R_RGMII_0_600_NS 4 #define YT8531_RC1R_RGMII_0_750_NS 5 #define YT8531_RC1R_RGMII_0_900_NS 6 #define YT8531_RC1R_RGMII_1_050_NS 7 #define YT8531_RC1R_RGMII_1_200_NS 8 #define YT8531_RC1R_RGMII_1_350_NS 9 #define YT8531_RC1R_RGMII_1_500_NS 10 #define YT8531_RC1R_RGMII_1_650_NS 11 #define YT8531_RC1R_RGMII_1_800_NS 12 #define YT8531_RC1R_RGMII_1_950_NS 13 #define YT8531_RC1R_RGMII_2_100_NS 14 #define YT8531_RC1R_RGMII_2_250_NS 15 /* Phy gmii clock gating Register */ #define YT8531_CLOCK_GATING_REG 0xC #define YT8531_CGR_RX_CLK_EN BIT(12) /* Specific Status Register */ #define YTPHY_SPECIFIC_STATUS_REG 0x11 #define YTPHY_DUPLEX_MASK BIT(13) #define YTPHY_DUPLEX_SHIFT 13 #define YTPHY_SPEED_MODE_MASK GENMASK(15, 14) #define YTPHY_SPEED_MODE_SHIFT 14 #define YT8531_EXTREG_SLEEP_CONTROL1_REG 0x27 #define YT8531_ESC1R_SLEEP_SW BIT(15) #define YT8531_ESC1R_PLLON_SLP BIT(14) #define YT8531_RGMII_CONFIG1_REG 0xA003 #define YT8531_CHIP_CONFIG_REG 0xA001 #define YT8531_CCR_SW_RST BIT(15) /* 1b0 disable 1.9ns rxc clock delay *default* * 1b1 enable 1.9ns rxc clock delay */ #define YT8531_CCR_RXC_DLY_EN BIT(8) #define YT8531_CCR_RXC_DLY_1_900_NS 1900 /* bits in struct ytphy_plat_priv->flag */ #define TX_CLK_ADJ_ENABLED BIT(0) #define AUTO_SLEEP_DISABLED BIT(1) #define KEEP_PLL_ENABLED BIT(2) #define TX_CLK_10_INVERTED BIT(3) #define TX_CLK_100_INVERTED BIT(4) #define TX_CLK_1000_INVERTED BIT(5) struct ytphy_plat_priv { u32 rx_delay_ps; u32 tx_delay_ps; u32 clk_out_frequency; u32 flag; }; /** * struct ytphy_cfg_reg_map - map a config value to a register value * @cfg: value in device configuration * @reg: value in the register */ 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 YT8531_CCR_RXC_DLY_EN is not set. */ { 0, YT8531_RC1R_RGMII_0_000_NS }, { 150, YT8531_RC1R_RGMII_0_150_NS }, { 300, YT8531_RC1R_RGMII_0_300_NS }, { 450, YT8531_RC1R_RGMII_0_450_NS }, { 600, YT8531_RC1R_RGMII_0_600_NS }, { 750, YT8531_RC1R_RGMII_0_750_NS }, { 900, YT8531_RC1R_RGMII_0_900_NS }, { 1050, YT8531_RC1R_RGMII_1_050_NS }, { 1200, YT8531_RC1R_RGMII_1_200_NS }, { 1350, YT8531_RC1R_RGMII_1_350_NS }, { 1500, YT8531_RC1R_RGMII_1_500_NS }, { 1650, YT8531_RC1R_RGMII_1_650_NS }, { 1800, YT8531_RC1R_RGMII_1_800_NS }, { 1950, YT8531_RC1R_RGMII_1_950_NS }, /* default tx/rx delay */ { 2100, YT8531_RC1R_RGMII_2_100_NS }, { 2250, YT8531_RC1R_RGMII_2_250_NS }, /* only for rx delay with YT8531_CCR_RXC_DLY_EN is set. */ { 0 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_000_NS }, { 150 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_150_NS }, { 300 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_300_NS }, { 450 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_450_NS }, { 600 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_600_NS }, { 750 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_750_NS }, { 900 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_0_900_NS }, { 1050 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_050_NS }, { 1200 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_200_NS }, { 1350 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_350_NS }, { 1500 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_500_NS }, { 1650 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_650_NS }, { 1800 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_800_NS }, { 1950 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_1_950_NS }, { 2100 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_2_100_NS }, { 2250 + YT8531_CCR_RXC_DLY_1_900_NS, YT8531_RC1R_RGMII_2_250_NS } }; static u32 ytphy_get_delay_reg_value(struct phy_device *phydev, u32 val, u16 *rxc_dly_en) { int tb_size = ARRAY_SIZE(ytphy_rgmii_delays); int tb_size_half = tb_size / 2; int i; /* 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 (ytphy_rgmii_delays[i].cfg == val) { if (rxc_dly_en && i < tb_size_half) *rxc_dly_en = 0; return ytphy_rgmii_delays[i].reg; } } pr_warn("Unsupported value %d, using default (%u)\n", val, YT8531_RC1R_RGMII_1_950_NS); /* when rxc_dly_en is not NULL, it is get the delay for rx. * The rx default in dts and ytphy_rgmii_clk_delay_config is 1950 ps, * so YT8531_CCR_RXC_DLY_EN should not be set. */ if (rxc_dly_en) *rxc_dly_en = 0; return YT8531_RC1R_RGMII_1_950_NS; } static int ytphy_modify_ext(struct phy_device *phydev, u16 regnum, u16 mask, u16 set) { int ret; ret = phy_write(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_SELECT, regnum); if (ret < 0) return ret; return phy_modify(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_DATA, mask, set); } static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev) { struct ytphy_plat_priv *priv = phydev->priv; u16 rxc_dly_en = YT8531_CCR_RXC_DLY_EN; u32 rx_reg, tx_reg; u16 mask, val = 0; int ret; rx_reg = ytphy_get_delay_reg_value(phydev, priv->rx_delay_ps, &rxc_dly_en); tx_reg = ytphy_get_delay_reg_value(phydev, priv->tx_delay_ps, NULL); switch (phydev->interface) { case PHY_INTERFACE_MODE_RGMII: rxc_dly_en = 0; break; case PHY_INTERFACE_MODE_RGMII_RXID: val |= FIELD_PREP(YT8531_RC1R_RX_DELAY_MASK, rx_reg); break; case PHY_INTERFACE_MODE_RGMII_TXID: rxc_dly_en = 0; val |= FIELD_PREP(YT8531_RC1R_GE_TX_DELAY_MASK, tx_reg); break; case PHY_INTERFACE_MODE_RGMII_ID: val |= FIELD_PREP(YT8531_RC1R_RX_DELAY_MASK, rx_reg) | FIELD_PREP(YT8531_RC1R_GE_TX_DELAY_MASK, tx_reg); break; default: /* do not support other modes */ return -EOPNOTSUPP; } ret = ytphy_modify_ext(phydev, YT8531_CHIP_CONFIG_REG, YT8531_CCR_RXC_DLY_EN, rxc_dly_en); if (ret < 0) return ret; /* Generally, it is not necessary to adjust YT8531_RC1R_FE_TX_DELAY */ mask = YT8531_RC1R_RX_DELAY_MASK | YT8531_RC1R_GE_TX_DELAY_MASK; return ytphy_modify_ext(phydev, YT8531_RGMII_CONFIG1_REG, mask, val); } static int yt8531_parse_status(struct phy_device *phydev) { int val; int speed, speed_mode; val = phy_read(phydev, MDIO_DEVAD_NONE, YTPHY_SPECIFIC_STATUS_REG); if (val < 0) return val; speed_mode = (val & YTPHY_SPEED_MODE_MASK) >> YTPHY_SPEED_MODE_SHIFT; switch (speed_mode) { case 2: speed = SPEED_1000; break; case 1: speed = SPEED_100; break; default: speed = SPEED_10; break; } phydev->speed = speed; phydev->duplex = (val & YTPHY_DUPLEX_MASK) >> YTPHY_DUPLEX_SHIFT; return 0; } static int yt8531_startup(struct phy_device *phydev) { struct ytphy_plat_priv *priv = phydev->priv; u16 val = 0; int ret; ret = genphy_update_link(phydev); if (ret) return ret; ret = yt8531_parse_status(phydev); if (ret) return ret; if (phydev->speed < 0) return -EINVAL; if (!(priv->flag & TX_CLK_ADJ_ENABLED)) return 0; switch (phydev->speed) { case SPEED_1000: if (priv->flag & TX_CLK_1000_INVERTED) val = YT8531_RC1R_TX_CLK_SEL_INVERTED; break; case SPEED_100: if (priv->flag & TX_CLK_100_INVERTED) val = YT8531_RC1R_TX_CLK_SEL_INVERTED; break; case SPEED_10: if (priv->flag & TX_CLK_10_INVERTED) val = YT8531_RC1R_TX_CLK_SEL_INVERTED; break; default: printf("UNKNOWN SPEED\n"); return -EINVAL; } ret = ytphy_modify_ext(phydev, YT8531_RGMII_CONFIG1_REG, YT8531_RC1R_TX_CLK_SEL_INVERTED, val); if (ret < 0) pr_warn("Modify TX_CLK_SEL err:%d\n", ret); return 0; } static void ytphy_dt_parse(struct phy_device *phydev) { struct ytphy_plat_priv *priv = phydev->priv; priv->clk_out_frequency = ofnode_read_u32_default(phydev->node, "motorcomm,clk-out-frequency-hz", YTPHY_DTS_OUTPUT_CLK_DIS); priv->rx_delay_ps = ofnode_read_u32_default(phydev->node, "rx-internal-delay-ps", YT8531_RC1R_RGMII_1_950_NS); priv->tx_delay_ps = ofnode_read_u32_default(phydev->node, "tx-internal-delay-ps", YT8531_RC1R_RGMII_1_950_NS); if (ofnode_read_bool(phydev->node, "motorcomm,auto-sleep-disabled")) priv->flag |= AUTO_SLEEP_DISABLED; if (ofnode_read_bool(phydev->node, "motorcomm,keep-pll-enabled")) priv->flag |= KEEP_PLL_ENABLED; if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-adj-enabled")) priv->flag |= TX_CLK_ADJ_ENABLED; if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-10-inverted")) priv->flag |= TX_CLK_10_INVERTED; if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-100-inverted")) priv->flag |= TX_CLK_100_INVERTED; if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-1000-inverted")) priv->flag |= TX_CLK_1000_INVERTED; } static int yt8531_config(struct phy_device *phydev) { struct ytphy_plat_priv *priv = phydev->priv; u16 mask, val; int ret; ret = genphy_config_aneg(phydev); if (ret < 0) return ret; ytphy_dt_parse(phydev); switch (priv->clk_out_frequency) { case YTPHY_DTS_OUTPUT_CLK_DIS: mask = YT8531_SCR_SYNCE_ENABLE; val = 0; break; case YTPHY_DTS_OUTPUT_CLK_25M: mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK | YT8531_SCR_CLK_FRE_SEL_125M; val = YT8531_SCR_SYNCE_ENABLE | FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, YT8531_SCR_CLK_SRC_REF_25M); break; case YTPHY_DTS_OUTPUT_CLK_125M: mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK | YT8531_SCR_CLK_FRE_SEL_125M; val = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_FRE_SEL_125M | FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, YT8531_SCR_CLK_SRC_PLL_125M); break; default: pr_warn("Freq err:%u\n", priv->clk_out_frequency); return -EINVAL; } ret = ytphy_modify_ext(phydev, YTPHY_SYNCE_CFG_REG, mask, val); if (ret < 0) return ret; ret = ytphy_rgmii_clk_delay_config(phydev); if (ret < 0) return ret; if (priv->flag & AUTO_SLEEP_DISABLED) { /* disable auto sleep */ ret = ytphy_modify_ext(phydev, YT8531_EXTREG_SLEEP_CONTROL1_REG, YT8531_ESC1R_SLEEP_SW, 0); if (ret < 0) return ret; } if (priv->flag & KEEP_PLL_ENABLED) { /* enable RXC clock when no wire plug */ ret = ytphy_modify_ext(phydev, YT8531_CLOCK_GATING_REG, YT8531_CGR_RX_CLK_EN, 0); if (ret < 0) return ret; } return 0; } static int yt8531_probe(struct phy_device *phydev) { struct ytphy_plat_priv *priv; priv = calloc(1, sizeof(struct ytphy_plat_priv)); if (!priv) return -ENOMEM; phydev->priv = priv; return 0; } U_BOOT_PHY_DRIVER(motorcomm8531) = { .name = "YT8531 Gigabit Ethernet", .uid = PHY_ID_YT8531, .mask = PHY_ID_MASK, .features = PHY_GBIT_FEATURES, .probe = &yt8531_probe, .config = &yt8531_config, .startup = &yt8531_startup, .shutdown = &genphy_shutdown, };