// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2026 Aspeed Technology Inc. */ #include #include #include #include #include #include #include #include #include #define PHY3S00 0x00 #define PHY3S00_INIT_DONE BIT(15) #define PHY3S00_SRAM_BYPASS BIT(7) #define PHY3S00_SRAM_EXT_LOAD BIT(6) #define PHY3S04 0x04 #define PHY3C00 0x08 #define PHY3C04 0x0c #define PHY3P00 0x10 #define PHY3P00_RX_ADAPT_AFE_EN_G1 BIT(0) #define PHY3P00_RX_ADAPT_AFE_EN_G2 BIT(1) #define PHY3P00_RX_ADAPT_DFE_EN_G1 BIT(2) #define PHY3P00_RX_ADAPT_DFE_EN_G2 BIT(3) #define PHY3P00_RX_CDR_VCO_LOWFREQ_G1 BIT(4) #define PHY3P00_RX_CDR_VCO_LOWFREQ_G2 BIT(5) #define PHY3P00_RX_EQ_AFE_GAIN_G1 GENMASK(9, 6) #define PHY3P00_RX_EQ_AFE_GAIN_G2 GENMASK(13, 10) #define PHY3P00_RX_EQ_ATT_LVL_G1 GENMASK(16, 14) #define PHY3P00_RX_EQ_ATT_LVL_G2 GENMASK(19, 17) #define PHY3P00_RX_EQ_CTLE_BOOST_G1 GENMASK(24, 20) #define PHY3P00_RX_EQ_CTLE_BOOST_G2 GENMASK(29, 25) #define PHY3P00_RX_EQ_DELTA_IQ_G1_LO GENMASK(31, 30) #define PHY3P04 0x14 #define PHY3P04_RX_EQ_DELTA_IQ_G1_HI GENMASK(1, 0) #define PHY3P04_RX_EQ_DELTA_IQ_G2 GENMASK(5, 2) #define PHY3P04_RX_EQ_DFE_TAP1_G1 GENMASK(13, 6) #define PHY3P04_RX_EQ_DFE_TAP1_G2 GENMASK(21, 14) #define PHY3P04_RX_LOS_LFPS_EN BIT(22) #define PHY3P04_RX_LOS_THRESHOLD GENMASK(25, 23) #define PHY3P04_RX_TERM_CTRL GENMASK(28, 26) #define PHY3P04_TX_EQ_MAIN_G1_LO GENMASK(31, 29) #define PHY3P08 0x18 #define PHY3P08_TX_EQ_MAIN_G1_HI GENMASK(1, 0) #define PHY3P08_TX_EQ_MAIN_G2 GENMASK(6, 2) #define PHY3P08_TX_EQ_OVRD BIT(7) #define PHY3P08_TX_EQ_POST_G1 GENMASK(12, 9) #define PHY3P08_TX_EQ_POST_G2 GENMASK(16, 13) #define PHY3P08_TX_EQ_PRE_G1 GENMASK(20, 17) #define PHY3P08_TX_EQ_PRE_G2 GENMASK(24, 21) #define PHY3P08_TX_IBOOST_LVL GENMASK(28, 25) #define PHY3P08_TX_TERM_CTRL GENMASK(31, 29) #define PHY3P0C 0x1c #define PHY3P0C_TX_VBOOST_EN BIT(0) #define PHY3CMD 0x40 #define PHY3P_RX_EQ_CTLE_BOOST_G1_DEFAULT 0x7 #define PHY3P_RX_EQ_CTLE_BOOST_G2_DEFAULT 0x7 #define PHY3P_RX_EQ_DELTA_IQ_G1_DEFAULT 0x3 #define PHY3P_RX_EQ_DELTA_IQ_G2_DEFAULT 0x5 #define PHY3P_RX_LOS_THRESHOLD_DEFAULT 0x3 #define PHY3P_RX_TERM_CTRL_DEFAULT 0x2 #define PHY3P_TX_EQ_MAIN_G1_DEFAULT 0xa #define PHY3P_TX_EQ_MAIN_G2_DEFAULT 0x9 #define PHY3P_TX_EQ_POST_G1_DEFAULT 0x4 #define PHY3P_TX_EQ_POST_G2_DEFAULT 0x3 #define PHY3P_TX_EQ_PRE_G2_DEFAULT 0x2 #define PHY3P_TX_IBOOST_LVL_DEFAULT 0xf #define PHY3P_TX_TERM_CTRL_DEFAULT 0x2 #define PHY3P00_DEFAULT ( \ PHY3P00_RX_ADAPT_AFE_EN_G1 | \ PHY3P00_RX_ADAPT_AFE_EN_G2 | \ PHY3P00_RX_ADAPT_DFE_EN_G1 | \ PHY3P00_RX_ADAPT_DFE_EN_G2 | \ FIELD_PREP(PHY3P00_RX_EQ_CTLE_BOOST_G1, PHY3P_RX_EQ_CTLE_BOOST_G1_DEFAULT) | \ FIELD_PREP(PHY3P00_RX_EQ_CTLE_BOOST_G2, PHY3P_RX_EQ_CTLE_BOOST_G2_DEFAULT) | \ FIELD_PREP(PHY3P00_RX_EQ_DELTA_IQ_G1_LO, \ PHY3P_RX_EQ_DELTA_IQ_G1_DEFAULT & 0x3) \ ) #define PHY3P04_DEFAULT ( \ FIELD_PREP(PHY3P04_RX_EQ_DELTA_IQ_G1_HI, \ PHY3P_RX_EQ_DELTA_IQ_G1_DEFAULT >> 2) | \ FIELD_PREP(PHY3P04_RX_EQ_DELTA_IQ_G2, PHY3P_RX_EQ_DELTA_IQ_G2_DEFAULT) | \ PHY3P04_RX_LOS_LFPS_EN | \ FIELD_PREP(PHY3P04_RX_LOS_THRESHOLD, PHY3P_RX_LOS_THRESHOLD_DEFAULT) | \ FIELD_PREP(PHY3P04_RX_TERM_CTRL, PHY3P_RX_TERM_CTRL_DEFAULT) | \ FIELD_PREP(PHY3P04_TX_EQ_MAIN_G1_LO, \ PHY3P_TX_EQ_MAIN_G1_DEFAULT & 0x7) \ ) #define PHY3P08_DEFAULT ( \ FIELD_PREP(PHY3P08_TX_EQ_MAIN_G1_HI, PHY3P_TX_EQ_MAIN_G1_DEFAULT >> 3) | \ FIELD_PREP(PHY3P08_TX_EQ_MAIN_G2, PHY3P_TX_EQ_MAIN_G2_DEFAULT) | \ FIELD_PREP(PHY3P08_TX_EQ_POST_G1, PHY3P_TX_EQ_POST_G1_DEFAULT) | \ FIELD_PREP(PHY3P08_TX_EQ_POST_G2, PHY3P_TX_EQ_POST_G2_DEFAULT) | \ FIELD_PREP(PHY3P08_TX_EQ_PRE_G2, PHY3P_TX_EQ_PRE_G2_DEFAULT) | \ FIELD_PREP(PHY3P08_TX_IBOOST_LVL, PHY3P_TX_IBOOST_LVL_DEFAULT) | \ FIELD_PREP(PHY3P08_TX_TERM_CTRL, PHY3P_TX_TERM_CTRL_DEFAULT) \ ) #define PHY3P0C_DEFAULT \ PHY3P0C_TX_VBOOST_EN struct aspeed_usb3_phy { void __iomem *regs; struct reset_control *rst; struct device *dev; struct clk *clk; }; static int aspeed_usb3_phy_init(struct phy *phy) { struct aspeed_usb3_phy *aspeed_phy = phy_get_drvdata(phy); u32 val; int ret; ret = clk_prepare_enable(aspeed_phy->clk); if (ret) { dev_err(aspeed_phy->dev, "Failed to enable clock %d\n", ret); return ret; } ret = reset_control_deassert(aspeed_phy->rst); if (ret) goto err_disable_clk; /* Wait for USB3 PHY internal SRAM initialization done */ ret = readl_poll_timeout(aspeed_phy->regs + PHY3S00, val, val & PHY3S00_INIT_DONE, USEC_PER_MSEC, 10 * USEC_PER_MSEC); if (ret) { dev_err(aspeed_phy->dev, "SRAM init timeout\n"); goto err_assert_reset; } val = readl(aspeed_phy->regs + PHY3S00); val |= PHY3S00_SRAM_EXT_LOAD; writel(val, aspeed_phy->regs + PHY3S00); /* Set protocol1_ext signals as default PHY3 settings based on SNPS documents. * Including PCFGI[54]: protocol1_ext_rx_los_lfps_en for better compatibility */ writel(PHY3P00_DEFAULT, aspeed_phy->regs + PHY3P00); writel(PHY3P04_DEFAULT, aspeed_phy->regs + PHY3P04); writel(PHY3P08_DEFAULT, aspeed_phy->regs + PHY3P08); writel(PHY3P0C_DEFAULT, aspeed_phy->regs + PHY3P0C); return 0; err_assert_reset: reset_control_assert(aspeed_phy->rst); err_disable_clk: clk_disable_unprepare(aspeed_phy->clk); return ret; } static int aspeed_usb3_phy_exit(struct phy *phy) { struct aspeed_usb3_phy *aspeed_phy = phy_get_drvdata(phy); reset_control_assert(aspeed_phy->rst); clk_disable_unprepare(aspeed_phy->clk); return 0; } static const struct phy_ops aspeed_usb3_phy_ops = { .init = aspeed_usb3_phy_init, .exit = aspeed_usb3_phy_exit, .owner = THIS_MODULE, }; static int aspeed_usb3_phy_probe(struct platform_device *pdev) { struct aspeed_usb3_phy *aspeed_phy; struct phy_provider *phy_provider; struct device *dev = &pdev->dev; struct phy *phy; aspeed_phy = devm_kzalloc(dev, sizeof(*aspeed_phy), GFP_KERNEL); if (!aspeed_phy) return -ENOMEM; aspeed_phy->dev = dev; aspeed_phy->clk = devm_clk_get(dev, NULL); if (IS_ERR(aspeed_phy->clk)) return PTR_ERR(aspeed_phy->clk); aspeed_phy->rst = devm_reset_control_get_exclusive(dev, NULL); if (IS_ERR(aspeed_phy->rst)) return PTR_ERR(aspeed_phy->rst); aspeed_phy->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(aspeed_phy->regs)) return PTR_ERR(aspeed_phy->regs); phy = devm_phy_create(dev, NULL, &aspeed_usb3_phy_ops); if (IS_ERR(phy)) return PTR_ERR(phy); phy_set_drvdata(phy, aspeed_phy); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); return PTR_ERR_OR_ZERO(phy_provider); } static const struct of_device_id aspeed_usb3_phy_match_table[] = { { .compatible = "aspeed,ast2700-usb3-phy", }, { } }; MODULE_DEVICE_TABLE(of, aspeed_usb3_phy_match_table); static struct platform_driver aspeed_usb3_phy_driver = { .probe = aspeed_usb3_phy_probe, .driver = { .name = KBUILD_MODNAME, .of_match_table = aspeed_usb3_phy_match_table, }, }; module_platform_driver(aspeed_usb3_phy_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ASPEED USB3.2 PHY Driver"); MODULE_AUTHOR("Ryan Chen ");