Introduce support for Aspeed PCIe PHY controller available in
AST2600/2700.
Signed-off-by: Jacky Chou <jacky_chou@aspeedtech.com>
---
drivers/phy/Kconfig | 1 +
drivers/phy/Makefile | 1 +
drivers/phy/aspeed/Kconfig | 15 ++
drivers/phy/aspeed/Makefile | 2 +
drivers/phy/aspeed/phy-aspeed-pcie.c | 209 +++++++++++++++++++++++++++
5 files changed, 228 insertions(+)
create mode 100644 drivers/phy/aspeed/Kconfig
create mode 100644 drivers/phy/aspeed/Makefile
create mode 100644 drivers/phy/aspeed/phy-aspeed-pcie.c
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 58c911e1b2d2..ac4bf46f24e2 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -103,6 +103,7 @@ config PHY_NXP_PTN3222
source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/amlogic/Kconfig"
+source "drivers/phy/aspeed/Kconfig"
source "drivers/phy/broadcom/Kconfig"
source "drivers/phy/cadence/Kconfig"
source "drivers/phy/freescale/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index c670a8dac468..12fd50e5ea9b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o
obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o
obj-y += allwinner/ \
amlogic/ \
+ aspeed/ \
broadcom/ \
cadence/ \
freescale/ \
diff --git a/drivers/phy/aspeed/Kconfig b/drivers/phy/aspeed/Kconfig
new file mode 100644
index 000000000000..6aeeca84091f
--- /dev/null
+++ b/drivers/phy/aspeed/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Phy drivers for Aspeed platforms
+#
+config PHY_ASPEED_PCIE
+ tristate "ASPEED PCIe PHY driver"
+ select GENERIC_PHY
+ depends on ARCH_ASPEED
+ default y
+ help
+ This option enables support for the ASPEED PCIe PHY driver.
+ The driver provides the necessary interface to control and
+ configure the PCIe PHY hardware found on ASPEED SoCs.
+ It is required for proper operation of PCIe devices on
+ platforms using ASPEED chips.
\ No newline at end of file
diff --git a/drivers/phy/aspeed/Makefile b/drivers/phy/aspeed/Makefile
new file mode 100644
index 000000000000..7203152f44bf
--- /dev/null
+++ b/drivers/phy/aspeed/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_PHY_ASPEED_PCIE) += phy-aspeed-pcie.o
\ No newline at end of file
diff --git a/drivers/phy/aspeed/phy-aspeed-pcie.c b/drivers/phy/aspeed/phy-aspeed-pcie.c
new file mode 100644
index 000000000000..4b78ceeb5a5e
--- /dev/null
+++ b/drivers/phy/aspeed/phy-aspeed-pcie.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 Aspeed Technology Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/pcie.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+/* AST2600 PCIe Host Controller Registers */
+#define PEHR_GLOBAL 0x30
+#define AST2600_PORT_TYPE_MASK GENMASK(5, 4)
+#define AST2600_PORT_TYPE(x) FIELD_PREP(AST2600_PORT_TYPE_MASK, x)
+#define PEHR_LOCK 0x7c
+#define PCIE_UNLOCK 0xa8
+
+/* AST2700 PEHR */
+#define PEHR_MISC_58 0x58
+#define LOCAL_SCALE_SUP BIT(0)
+#define PEHR_MISC_5C 0x5c
+#define CONFIG_RC_DEVICE BIT(30)
+#define PEHR_MISC_60 0x60
+#define AST2700_PORT_TYPE_MASK GENMASK(7, 4)
+#define PORT_TYPE_ROOT BIT(6)
+#define PEHR_MISC_70 0x70
+#define POSTED_DATA_CREDITS(x) FIELD_PREP(GENMASK(15, 0), x)
+#define POSTED_HEADER_CREDITS(x) FIELD_PREP(GENMASK(27, 16), x)
+#define PEHR_MISC_78 0x78
+#define COMPLETION_DATA_CREDITS(x) FIELD_PREP(GENMASK(15, 0), x)
+#define COMPLETION_HEADER_CREDITS(x) FIELD_PREP(GENMASK(27, 16), x)
+
+/**
+ * struct aspeed_pcie_phy - PCIe PHY information
+ * @dev: pointer to device structure
+ * @reg: PCIe host register base address
+ * @phy: pointer to PHY structure
+ * @platform: platform specific information
+ */
+struct aspeed_pcie_phy {
+ struct device *dev;
+ void __iomem *reg;
+ struct phy *phy;
+ const struct aspeed_pcie_phy_platform *platform;
+};
+
+/**
+ * struct aspeed_pcie_phy_platform - Platform information
+ * @phy_ops: phy operations
+ */
+struct aspeed_pcie_phy_platform {
+ const struct phy_ops *phy_ops;
+};
+
+static int ast2600_phy_init(struct phy *phy)
+{
+ struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+
+ writel(PCIE_UNLOCK, pcie_phy->reg + PEHR_LOCK);
+
+ return 0;
+}
+
+static int ast2600_phy_set_mode(struct phy *phy, enum phy_mode mode,
+ int submode)
+{
+ struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+
+ switch (submode) {
+ case PHY_MODE_PCIE_RC:
+ writel(AST2600_PORT_TYPE(0x3), pcie_phy->reg + PEHR_GLOBAL);
+ break;
+ default:
+ dev_err(&phy->dev, "Unsupported submode %d\n", submode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct phy_ops ast2600_phy_ops = {
+ .init = ast2600_phy_init,
+ .set_mode = ast2600_phy_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static int ast2700_phy_init(struct phy *phy)
+{
+ struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+
+ writel(POSTED_DATA_CREDITS(0xc0) | POSTED_HEADER_CREDITS(0xa),
+ pcie_phy->reg + PEHR_MISC_70);
+ writel(COMPLETION_DATA_CREDITS(0x30) | COMPLETION_HEADER_CREDITS(0x8),
+ pcie_phy->reg + PEHR_MISC_78);
+ writel(LOCAL_SCALE_SUP, pcie_phy->reg + PEHR_MISC_58);
+
+ return 0;
+}
+
+static int ast2700_phy_set_mode(struct phy *phy, enum phy_mode mode,
+ int submode)
+{
+ struct aspeed_pcie_phy *pcie_phy = phy_get_drvdata(phy);
+ u32 cfg_val;
+
+ switch (submode) {
+ case PHY_MODE_PCIE_RC:
+ writel(CONFIG_RC_DEVICE, pcie_phy->reg + PEHR_MISC_5C);
+ cfg_val = readl(pcie_phy->reg + PEHR_MISC_60);
+ cfg_val &= ~AST2700_PORT_TYPE_MASK;
+ cfg_val |= PORT_TYPE_ROOT;
+ writel(cfg_val, pcie_phy->reg + PEHR_MISC_60);
+ break;
+ default:
+ dev_err(&phy->dev, "Unsupported submode %d\n", submode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct phy_ops ast2700_phy_ops = {
+ .init = ast2700_phy_init,
+ .set_mode = ast2700_phy_set_mode,
+ .owner = THIS_MODULE,
+};
+
+const struct aspeed_pcie_phy_platform pcie_phy_ast2600 = {
+ .phy_ops = &ast2600_phy_ops,
+};
+
+const struct aspeed_pcie_phy_platform pcie_phy_ast2700 = {
+ .phy_ops = &ast2700_phy_ops,
+};
+
+static int aspeed_pcie_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy_provider *phy_provider;
+ struct aspeed_pcie_phy *pcie_phy;
+ const struct aspeed_pcie_phy_platform *md;
+
+ md = of_device_get_match_data(dev);
+ if (!md)
+ return -ENODEV;
+
+ pcie_phy = devm_kzalloc(dev, sizeof(*pcie_phy), GFP_KERNEL);
+ if (!pcie_phy)
+ return -ENOMEM;
+
+ pcie_phy->reg = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pcie_phy->reg))
+ return PTR_ERR(pcie_phy->reg);
+
+ pcie_phy->dev = dev;
+ pcie_phy->platform = md;
+
+ pcie_phy->phy = devm_phy_create(dev, dev->of_node,
+ pcie_phy->platform->phy_ops);
+ if (IS_ERR(pcie_phy->phy))
+ return dev_err_probe(dev, PTR_ERR(pcie_phy->phy),
+ "failed to create PHY\n");
+
+ phy_set_drvdata(pcie_phy->phy, pcie_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_pcie_phy_of_match_table[] = {
+ {
+ .compatible = "aspeed,ast2600-pcie-phy",
+ .data = &pcie_phy_ast2600,
+ },
+ {
+ .compatible = "aspeed,ast2700-pcie-phy",
+ .data = &pcie_phy_ast2700,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, aspeed_pcie_of_match_table);
+
+static struct platform_driver aspeed_pcie_driver = {
+ .probe = aspeed_pcie_phy_probe,
+ .driver = {
+ .name = "aspeed-pcie-phy",
+ .of_match_table = aspeed_pcie_phy_of_match_table,
+ },
+};
+
+module_platform_driver(aspeed_pcie_driver);
+
+MODULE_AUTHOR("Jacky Chou <jacky_chou@aspeedtech.com>");
+MODULE_DESCRIPTION("ASPEED PCIe PHY");
+MODULE_LICENSE("GPL");
--
2.43.0
Hi Jacky, kernel test robot noticed the following build errors: [auto build test ERROR on pci/for-linus] [also build test ERROR on robh/for-next linusw-pinctrl/devel linusw-pinctrl/for-next linus/master v6.17-rc4 next-20250902] [cannot apply to pci/next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Jacky-Chou/dt-bindings-soc-aspeed-Add-ASPEED-PCIe-Config/20250901-140231 base: https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git for-linus patch link: https://lore.kernel.org/r/20250901055922.1553550-8-jacky_chou%40aspeedtech.com patch subject: [PATCH v3 07/10] PHY: aspeed: Add ASPEED PCIe PHY driver config: arm-allmodconfig (https://download.01.org/0day-ci/archive/20250902/202509021806.1NtrcLpF-lkp@intel.com/config) compiler: arm-linux-gnueabi-gcc (GCC) 15.1.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250902/202509021806.1NtrcLpF-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202509021806.1NtrcLpF-lkp@intel.com/ All errors (new ones prefixed by >>): In file included from drivers/phy/aspeed/phy-aspeed-pcie.c:14: >> drivers/phy/aspeed/phy-aspeed-pcie.c:195:25: error: 'aspeed_pcie_of_match_table' undeclared here (not in a function); did you mean 'aspeed_pcie_phy_of_match_table'? 195 | MODULE_DEVICE_TABLE(of, aspeed_pcie_of_match_table); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/module.h:250:15: note: in definition of macro 'MODULE_DEVICE_TABLE' 250 | static typeof(name) __mod_device_table__##type##__##name \ | ^~~~ >> include/linux/module.h:250:21: error: '__mod_device_table__of__aspeed_pcie_of_match_table' aliased to undefined symbol 'aspeed_pcie_of_match_table' 250 | static typeof(name) __mod_device_table__##type##__##name \ | ^~~~~~~~~~~~~~~~~~~~ drivers/phy/aspeed/phy-aspeed-pcie.c:195:1: note: in expansion of macro 'MODULE_DEVICE_TABLE' 195 | MODULE_DEVICE_TABLE(of, aspeed_pcie_of_match_table); | ^~~~~~~~~~~~~~~~~~~ -- In file included from phy-aspeed-pcie.c:14: phy-aspeed-pcie.c:195:25: error: 'aspeed_pcie_of_match_table' undeclared here (not in a function); did you mean 'aspeed_pcie_phy_of_match_table'? 195 | MODULE_DEVICE_TABLE(of, aspeed_pcie_of_match_table); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/module.h:250:15: note: in definition of macro 'MODULE_DEVICE_TABLE' 250 | static typeof(name) __mod_device_table__##type##__##name \ | ^~~~ >> include/linux/module.h:250:21: error: '__mod_device_table__of__aspeed_pcie_of_match_table' aliased to undefined symbol 'aspeed_pcie_of_match_table' 250 | static typeof(name) __mod_device_table__##type##__##name \ | ^~~~~~~~~~~~~~~~~~~~ phy-aspeed-pcie.c:195:1: note: in expansion of macro 'MODULE_DEVICE_TABLE' 195 | MODULE_DEVICE_TABLE(of, aspeed_pcie_of_match_table); | ^~~~~~~~~~~~~~~~~~~ vim +195 drivers/phy/aspeed/phy-aspeed-pcie.c 183 184 static const struct of_device_id aspeed_pcie_phy_of_match_table[] = { 185 { 186 .compatible = "aspeed,ast2600-pcie-phy", 187 .data = &pcie_phy_ast2600, 188 }, 189 { 190 .compatible = "aspeed,ast2700-pcie-phy", 191 .data = &pcie_phy_ast2700, 192 }, 193 { }, 194 }; > 195 MODULE_DEVICE_TABLE(of, aspeed_pcie_of_match_table); 196 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.