--- /dev/null
+From 74badb8b0b146668cc6c03eb58e2a814f9463d02 Mon Sep 17 00:00:00 2001
+Date: Thu, 20 Feb 2025 15:12:46 +0530
+Subject: [PATCH] phy: qcom: Introduce PCIe UNIPHY 28LP driver
+
+Add Qualcomm PCIe UNIPHY 28LP driver support present in Qualcomm IPQ5332
+SoC and the phy init sequence.
+
+---
+ drivers/phy/qualcomm/Kconfig | 12 +
+ drivers/phy/qualcomm/Makefile | 1 +
+ .../phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c | 286 ++++++++++++++++++
+ 3 files changed, 299 insertions(+)
+ create mode 100644 drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
+
+--- a/drivers/phy/qualcomm/Kconfig
++++ b/drivers/phy/qualcomm/Kconfig
+@@ -154,6 +154,18 @@ config PHY_QCOM_M31_USB
+ management. This driver is required even for peripheral only or
+ host only mode configurations.
+
++config PHY_QCOM_UNIPHY_PCIE_28LP
++ bool "PCIE UNIPHY 28LP PHY driver"
++ depends on ARCH_QCOM
++ depends on HAS_IOMEM
++ depends on OF
++ select GENERIC_PHY
++ help
++ Enable this to support the PCIe UNIPHY 28LP phy transceiver that
++ is used with PCIe controllers on Qualcomm IPQ5332 chips. It
++ handles PHY initialization, clock management required after
++ resetting the hardware and power management.
++
+ config PHY_QCOM_USB_HS
+ tristate "Qualcomm USB HS PHY module"
+ depends on USB_ULPI_BUS
+--- a/drivers/phy/qualcomm/Makefile
++++ b/drivers/phy/qualcomm/Makefile
+@@ -17,6 +17,7 @@ obj-$(CONFIG_PHY_QCOM_QMP_USB_LEGACY) +=
+ obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
+ obj-$(CONFIG_PHY_QCOM_SNPS_EUSB2) += phy-qcom-snps-eusb2.o
+ obj-$(CONFIG_PHY_QCOM_EUSB2_REPEATER) += phy-qcom-eusb2-repeater.o
++obj-$(CONFIG_PHY_QCOM_UNIPHY_PCIE_28LP) += phy-qcom-uniphy-pcie-28lp.o
+ obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o
+ obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
+ obj-$(CONFIG_PHY_QCOM_USB_HS_28NM) += phy-qcom-usb-hs-28nm.o
+--- /dev/null
++++ b/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
+@@ -0,0 +1,286 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (c) 2025, The Linux Foundation. All rights reserved.
++ */
++
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/of.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <linux/reset.h>
++#include <linux/units.h>
++
++#define RST_ASSERT_DELAY_MIN_US 100
++#define RST_ASSERT_DELAY_MAX_US 150
++#define PIPE_CLK_DELAY_MIN_US 5000
++#define PIPE_CLK_DELAY_MAX_US 5100
++#define CLK_EN_DELAY_MIN_US 30
++#define CLK_EN_DELAY_MAX_US 50
++#define CDR_CTRL_REG_1 0x80
++#define CDR_CTRL_REG_2 0x84
++#define CDR_CTRL_REG_3 0x88
++#define CDR_CTRL_REG_4 0x8c
++#define CDR_CTRL_REG_5 0x90
++#define CDR_CTRL_REG_6 0x94
++#define CDR_CTRL_REG_7 0x98
++#define SSCG_CTRL_REG_1 0x9c
++#define SSCG_CTRL_REG_2 0xa0
++#define SSCG_CTRL_REG_3 0xa4
++#define SSCG_CTRL_REG_4 0xa8
++#define SSCG_CTRL_REG_5 0xac
++#define SSCG_CTRL_REG_6 0xb0
++#define PCS_INTERNAL_CONTROL_2 0x2d8
++
++#define PHY_CFG_PLLCFG 0x220
++#define PHY_CFG_EIOS_DTCT_REG 0x3e4
++#define PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME 0x3e8
++
++enum qcom_uniphy_pcie_type {
++ PHY_TYPE_PCIE = 1,
++ PHY_TYPE_PCIE_GEN2,
++ PHY_TYPE_PCIE_GEN3,
++};
++
++struct qcom_uniphy_pcie_regs {
++ u32 offset;
++ u32 val;
++};
++
++struct qcom_uniphy_pcie_data {
++ int lane_offset; /* offset between the lane register bases */
++ u32 phy_type;
++ const struct qcom_uniphy_pcie_regs *init_seq;
++ u32 init_seq_num;
++ u32 pipe_clk_rate;
++};
++
++struct qcom_uniphy_pcie {
++ struct phy phy;
++ struct device *dev;
++ const struct qcom_uniphy_pcie_data *data;
++ struct clk_bulk_data *clks;
++ int num_clks;
++ struct reset_control *resets;
++ void __iomem *base;
++ int lanes;
++};
++
++#define phy_to_dw_phy(x) container_of((x), struct qca_uni_pcie_phy, phy)
++
++static const struct qcom_uniphy_pcie_regs ipq5332_regs[] = {
++ {
++ .offset = PHY_CFG_PLLCFG,
++ .val = 0x30,
++ }, {
++ .offset = PHY_CFG_EIOS_DTCT_REG,
++ .val = 0x53ef,
++ }, {
++ .offset = PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME,
++ .val = 0xcf,
++ },
++};
++
++static const struct qcom_uniphy_pcie_data ipq5332_data = {
++ .lane_offset = 0x800,
++ .phy_type = PHY_TYPE_PCIE_GEN3,
++ .init_seq = ipq5332_regs,
++ .init_seq_num = ARRAY_SIZE(ipq5332_regs),
++ .pipe_clk_rate = 250 * MEGA,
++};
++
++static void qcom_uniphy_pcie_init(struct qcom_uniphy_pcie *phy)
++{
++ const struct qcom_uniphy_pcie_data *data = phy->data;
++ const struct qcom_uniphy_pcie_regs *init_seq;
++ void __iomem *base = phy->base;
++ int lane, i;
++
++ for (lane = 0; lane < phy->lanes; lane++) {
++ init_seq = data->init_seq;
++
++ for (i = 0; i < data->init_seq_num; i++)
++ writel(init_seq[i].val, base + init_seq[i].offset);
++
++ base += data->lane_offset;
++ }
++}
++
++static int qcom_uniphy_pcie_power_off(struct phy *x)
++{
++ struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
++
++ clk_bulk_disable_unprepare(phy->num_clks, phy->clks);
++
++ return reset_control_assert(phy->resets);
++}
++
++static int qcom_uniphy_pcie_power_on(struct phy *x)
++{
++ struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
++ int ret;
++
++ ret = reset_control_assert(phy->resets);
++ if (ret) {
++ dev_err(phy->dev, "reset assert failed (%d)\n", ret);
++ return ret;
++ }
++
++ usleep_range(RST_ASSERT_DELAY_MIN_US, RST_ASSERT_DELAY_MAX_US);
++
++ ret = reset_control_deassert(phy->resets);
++ if (ret) {
++ dev_err(phy->dev, "reset deassert failed (%d)\n", ret);
++ return ret;
++ }
++
++ usleep_range(PIPE_CLK_DELAY_MIN_US, PIPE_CLK_DELAY_MAX_US);
++
++ ret = clk_bulk_prepare_enable(phy->num_clks, phy->clks);
++ if (ret) {
++ dev_err(phy->dev, "clk prepare and enable failed %d\n", ret);
++ return ret;
++ }
++
++ usleep_range(CLK_EN_DELAY_MIN_US, CLK_EN_DELAY_MAX_US);
++
++ qcom_uniphy_pcie_init(phy);
++
++ return 0;
++}
++
++static inline int qcom_uniphy_pcie_get_resources(struct platform_device *pdev,
++ struct qcom_uniphy_pcie *phy)
++{
++ struct resource *res;
++
++ phy->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
++ if (IS_ERR(phy->base))
++ return PTR_ERR(phy->base);
++
++ phy->num_clks = devm_clk_bulk_get_all(phy->dev, &phy->clks);
++ if (phy->num_clks < 0)
++ return phy->num_clks;
++
++ phy->resets = devm_reset_control_array_get_exclusive(phy->dev);
++ if (IS_ERR(phy->resets))
++ return PTR_ERR(phy->resets);
++
++ return 0;
++}
++
++/*
++ * Register a fixed rate pipe clock.
++ *
++ * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
++ * controls it. The <s>_pipe_clk coming out of the GCC is requested
++ * by the PHY driver for its operations.
++ * We register the <s>_pipe_clksrc here. The gcc driver takes care
++ * of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.
++ * Below picture shows this relationship.
++ *
++ * +---------------+
++ * | PHY block |<<---------------------------------------+
++ * | | |
++ * | +-------+ | +-----+ |
++ * I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
++ * clk | +-------+ | +-----+
++ * +---------------+
++ */
++static inline int phy_pipe_clk_register(struct qcom_uniphy_pcie *phy, int id)
++{
++ const struct qcom_uniphy_pcie_data *data = phy->data;
++ struct clk_hw *hw;
++ char name[64];
++
++ snprintf(name, sizeof(name), "phy%d_pipe_clk_src", id);
++ hw = devm_clk_hw_register_fixed_rate(phy->dev, name, NULL, 0,
++ data->pipe_clk_rate);
++ if (IS_ERR(hw))
++ return dev_err_probe(phy->dev, PTR_ERR(hw),
++ "Unable to register %s\n", name);
++
++ return devm_of_clk_add_hw_provider(phy->dev, of_clk_hw_simple_get, hw);
++}
++
++static const struct of_device_id qcom_uniphy_pcie_id_table[] = {
++ {
++ .compatible = "qcom,ipq5332-uniphy-pcie-phy",
++ .data = &ipq5332_data,
++ }, {
++ /* Sentinel */
++ },
++};
++MODULE_DEVICE_TABLE(of, qcom_uniphy_pcie_id_table);
++
++static const struct phy_ops pcie_ops = {
++ .power_on = qcom_uniphy_pcie_power_on,
++ .power_off = qcom_uniphy_pcie_power_off,
++ .owner = THIS_MODULE,
++};
++
++static int qcom_uniphy_pcie_probe(struct platform_device *pdev)
++{
++ struct phy_provider *phy_provider;
++ struct device *dev = &pdev->dev;
++ struct qcom_uniphy_pcie *phy;
++ struct phy *generic_phy;
++ int ret;
++
++ phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
++ if (!phy)
++ return -ENOMEM;
++
++ platform_set_drvdata(pdev, phy);
++ phy->dev = &pdev->dev;
++
++ phy->data = of_device_get_match_data(dev);
++ if (!phy->data)
++ return -EINVAL;
++
++ ret = of_property_read_u32(dev_of_node(dev), "num-lanes", &phy->lanes);
++ if (ret)
++ return dev_err_probe(dev, ret, "Couldn't read num-lanes\n");
++
++ ret = qcom_uniphy_pcie_get_resources(pdev, phy);
++ if (ret < 0)
++ return dev_err_probe(&pdev->dev, ret,
++ "failed to get resources: %d\n", ret);
++
++ generic_phy = devm_phy_create(phy->dev, NULL, &pcie_ops);
++ if (IS_ERR(generic_phy))
++ return PTR_ERR(generic_phy);
++
++ phy_set_drvdata(generic_phy, phy);
++
++ ret = phy_pipe_clk_register(phy, generic_phy->id);
++ if (ret)
++ dev_err(&pdev->dev, "failed to register phy pipe clk\n");
++
++ phy_provider = devm_of_phy_provider_register(phy->dev,
++ of_phy_simple_xlate);
++ if (IS_ERR(phy_provider))
++ return PTR_ERR(phy_provider);
++
++ return 0;
++}
++
++static struct platform_driver qcom_uniphy_pcie_driver = {
++ .probe = qcom_uniphy_pcie_probe,
++ .driver = {
++ .name = "qcom-uniphy-pcie",
++ .of_match_table = qcom_uniphy_pcie_id_table,
++ },
++};
++
++module_platform_driver(qcom_uniphy_pcie_driver);
++
++MODULE_DESCRIPTION("PCIE QCOM UNIPHY driver");
++MODULE_LICENSE("GPL");
--- /dev/null
+From dfc820d2f8a8ea90bbc02269b5362e3678e58cac Mon Sep 17 00:00:00 2001
+Date: Wed, 26 Mar 2025 12:10:56 +0400
+Subject: [PATCH] phy: qualcomm: qcom-uniphy-pcie 28LP add support for IPQ5018
+
+The Qualcomm UNIPHY PCIe PHY 28LP is found on both IPQ5332 and IPQ5018.
+Adding the PHY init sequence, pipe clock rate, and compatible for IPQ5018.
+
+---
+ .../phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c | 45 +++++++++++++++++++
+ 1 file changed, 45 insertions(+)
+
+--- a/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
++++ b/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
+@@ -75,6 +75,40 @@ struct qcom_uniphy_pcie {
+
+ #define phy_to_dw_phy(x) container_of((x), struct qca_uni_pcie_phy, phy)
+
++static const struct qcom_uniphy_pcie_regs ipq5018_regs[] = {
++ {
++ .offset = SSCG_CTRL_REG_4,
++ .val = 0x1cb9,
++ }, {
++ .offset = SSCG_CTRL_REG_5,
++ .val = 0x023a,
++ }, {
++ .offset = SSCG_CTRL_REG_3,
++ .val = 0xd360,
++ }, {
++ .offset = SSCG_CTRL_REG_1,
++ .val = 0x1,
++ }, {
++ .offset = SSCG_CTRL_REG_2,
++ .val = 0xeb,
++ }, {
++ .offset = CDR_CTRL_REG_4,
++ .val = 0x3f9,
++ }, {
++ .offset = CDR_CTRL_REG_5,
++ .val = 0x1c9,
++ }, {
++ .offset = CDR_CTRL_REG_2,
++ .val = 0x419,
++ }, {
++ .offset = CDR_CTRL_REG_1,
++ .val = 0x200,
++ }, {
++ .offset = PCS_INTERNAL_CONTROL_2,
++ .val = 0xf101,
++ },
++};
++
+ static const struct qcom_uniphy_pcie_regs ipq5332_regs[] = {
+ {
+ .offset = PHY_CFG_PLLCFG,
+@@ -88,6 +122,14 @@ static const struct qcom_uniphy_pcie_reg
+ },
+ };
+
++static const struct qcom_uniphy_pcie_data ipq5018_data = {
++ .lane_offset = 0x800,
++ .phy_type = PHY_TYPE_PCIE_GEN2,
++ .init_seq = ipq5018_regs,
++ .init_seq_num = ARRAY_SIZE(ipq5018_regs),
++ .pipe_clk_rate = 125 * MEGA,
++};
++
+ static const struct qcom_uniphy_pcie_data ipq5332_data = {
+ .lane_offset = 0x800,
+ .phy_type = PHY_TYPE_PCIE_GEN3,
+@@ -212,6 +254,9 @@ static inline int phy_pipe_clk_register(
+
+ static const struct of_device_id qcom_uniphy_pcie_id_table[] = {
+ {
++ .compatible = "qcom,ipq5018-uniphy-pcie-phy",
++ .data = &ipq5018_data,
++ }, {
+ .compatible = "qcom,ipq5332-uniphy-pcie-phy",
+ .data = &ipq5332_data,
+ }, {
--- /dev/null
+From 3e5127469a8d41153fb30031a271788f52dd17ec Mon Sep 17 00:00:00 2001
+Date: Wed, 26 Mar 2025 12:10:58 +0400
+Subject: [PATCH] PCI: qcom: Add support for IPQ5018
+
+Add IPQ5018 platform with is based on Qcom IP rev. 2.9.0 and Synopsys IP
+rev. 5.00a.
+
+The platform itself has two PCIe Gen2 controllers: one single-lane and
+one dual-lane. So add the IPQ5018 compatible and re-use 2_9_0 ops.
+
+---
+ drivers/pci/controller/dwc/pcie-qcom.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/pci/controller/dwc/pcie-qcom.c
++++ b/drivers/pci/controller/dwc/pcie-qcom.c
+@@ -1827,6 +1827,7 @@ static const struct of_device_id qcom_pc
+ { .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 },
+ { .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 },
+ { .compatible = "qcom,pcie-ipq4019", .data = &cfg_2_4_0 },
++ { .compatible = "qcom,pcie-ipq5018", .data = &cfg_2_9_0 },
+ { .compatible = "qcom,pcie-ipq6018", .data = &cfg_2_9_0 },
+ { .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 },
+ { .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 },
+++ /dev/null
-From 3e5127469a8d41153fb30031a271788f52dd17ec Mon Sep 17 00:00:00 2001
-Date: Wed, 26 Mar 2025 12:10:58 +0400
-Subject: [PATCH] PCI: qcom: Add support for IPQ5018
-
-Add IPQ5018 platform with is based on Qcom IP rev. 2.9.0 and Synopsys IP
-rev. 5.00a.
-
-The platform itself has two PCIe Gen2 controllers: one single-lane and
-one dual-lane. So add the IPQ5018 compatible and re-use 2_9_0 ops.
-
----
- drivers/pci/controller/dwc/pcie-qcom.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/pci/controller/dwc/pcie-qcom.c
-+++ b/drivers/pci/controller/dwc/pcie-qcom.c
-@@ -1827,6 +1827,7 @@ static const struct of_device_id qcom_pc
- { .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 },
- { .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 },
- { .compatible = "qcom,pcie-ipq4019", .data = &cfg_2_4_0 },
-+ { .compatible = "qcom,pcie-ipq5018", .data = &cfg_2_9_0 },
- { .compatible = "qcom,pcie-ipq6018", .data = &cfg_2_9_0 },
- { .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 },
- { .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 },
--- /dev/null
+From 18a5bf00a02ca54d51266b861518f2844c4f08d7 Mon Sep 17 00:00:00 2001
+Date: Wed, 14 May 2025 09:52:13 +0400
+Subject: [PATCH] arm64: dts: qcom: ipq5018: Add PCIe related nodes
+
+Add phy and controller nodes for a 2-lane Gen2 and
+a 1-lane Gen2 PCIe bus. IPQ5018 has 8 MSI SPI interrupts and
+one global interrupt.
+
+NOTE: the PCIe controller supports gen3, yet the phy is limited to gen2.
+
+---
+ arch/arm64/boot/dts/qcom/ipq5018.dtsi | 240 +++++++++++++++++++++++++-
+ 1 file changed, 238 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+@@ -147,6 +147,40 @@
+ status = "disabled";
+ };
+
++ pcie1_phy: phy@7e000 {
++ compatible = "qcom,ipq5018-uniphy-pcie-phy";
++ reg = <0x0007e000 0x800>;
++
++ clocks = <&gcc GCC_PCIE1_PIPE_CLK>;
++
++ resets = <&gcc GCC_PCIE1_PHY_BCR>,
++ <&gcc GCC_PCIE1PHY_PHY_BCR>;
++
++ #clock-cells = <0>;
++ #phy-cells = <0>;
++
++ num-lanes = <1>;
++
++ status = "disabled";
++ };
++
++ pcie0_phy: phy@86000 {
++ compatible = "qcom,ipq5018-uniphy-pcie-phy";
++ reg = <0x00086000 0x1000>;
++
++ clocks = <&gcc GCC_PCIE0_PIPE_CLK>;
++
++ resets = <&gcc GCC_PCIE0_PHY_BCR>,
++ <&gcc GCC_PCIE0PHY_PHY_BCR>;
++
++ #clock-cells = <0>;
++ #phy-cells = <0>;
++
++ num-lanes = <2>;
++
++ status = "disabled";
++ };
++
+ tlmm: pinctrl@1000000 {
+ compatible = "qcom,ipq5018-tlmm";
+ reg = <0x01000000 0x300000>;
+@@ -170,8 +204,8 @@
+ reg = <0x01800000 0x80000>;
+ clocks = <&xo_board_clk>,
+ <&sleep_clk>,
+- <0>,
+- <0>,
++ <&pcie0_phy>,
++ <&pcie1_phy>,
+ <0>,
+ <0>,
+ <0>,
+@@ -387,6 +421,208 @@
+ status = "disabled";
+ };
+ };
++
++ pcie1: pcie@80000000 {
++ compatible = "qcom,pcie-ipq5018";
++ reg = <0x80000000 0xf1d>,
++ <0x80000f20 0xa8>,
++ <0x80001000 0x1000>,
++ <0x00078000 0x3000>,
++ <0x80100000 0x1000>,
++ <0x0007b000 0x1000>;
++ reg-names = "dbi",
++ "elbi",
++ "atu",
++ "parf",
++ "config",
++ "mhi";
++ device_type = "pci";
++ linux,pci-domain = <1>;
++ bus-range = <0x00 0xff>;
++ num-lanes = <1>;
++ #address-cells = <3>;
++ #size-cells = <2>;
++
++ /* The controller supports Gen3, but the connected PHY is Gen2-capable */
++ max-link-speed = <2>;
++
++ phys = <&pcie1_phy>;
++ phy-names ="pciephy";
++
++ ranges = <0x01000000 0 0x00000000 0x80200000 0 0x00100000>,
++ <0x02000000 0 0x80300000 0x80300000 0 0x10000000>;
++
++ msi-map = <0x0 &v2m0 0x0 0xff8>;
++
++ interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "msi0",
++ "msi1",
++ "msi2",
++ "msi3",
++ "msi4",
++ "msi5",
++ "msi6",
++ "msi7",
++ "global";
++
++ #interrupt-cells = <1>;
++ interrupt-map-mask = <0 0 0 0x7>;
++ interrupt-map = <0 0 0 1 &intc 0 0 142 IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 2 &intc 0 0 143 IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 3 &intc 0 0 144 IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 4 &intc 0 0 145 IRQ_TYPE_LEVEL_HIGH>;
++
++ clocks = <&gcc GCC_SYS_NOC_PCIE1_AXI_CLK>,
++ <&gcc GCC_PCIE1_AXI_M_CLK>,
++ <&gcc GCC_PCIE1_AXI_S_CLK>,
++ <&gcc GCC_PCIE1_AHB_CLK>,
++ <&gcc GCC_PCIE1_AUX_CLK>,
++ <&gcc GCC_PCIE1_AXI_S_BRIDGE_CLK>;
++ clock-names = "iface",
++ "axi_m",
++ "axi_s",
++ "ahb",
++ "aux",
++ "axi_bridge";
++
++ resets = <&gcc GCC_PCIE1_PIPE_ARES>,
++ <&gcc GCC_PCIE1_SLEEP_ARES>,
++ <&gcc GCC_PCIE1_CORE_STICKY_ARES>,
++ <&gcc GCC_PCIE1_AXI_MASTER_ARES>,
++ <&gcc GCC_PCIE1_AXI_SLAVE_ARES>,
++ <&gcc GCC_PCIE1_AHB_ARES>,
++ <&gcc GCC_PCIE1_AXI_MASTER_STICKY_ARES>,
++ <&gcc GCC_PCIE1_AXI_SLAVE_STICKY_ARES>;
++ reset-names = "pipe",
++ "sleep",
++ "sticky",
++ "axi_m",
++ "axi_s",
++ "ahb",
++ "axi_m_sticky",
++ "axi_s_sticky";
++
++ status = "disabled";
++
++ pcie@0 {
++ device_type = "pci";
++ reg = <0x0 0x0 0x0 0x0 0x0>;
++ bus-range = <0x01 0xff>;
++
++ #address-cells = <3>;
++ #size-cells = <2>;
++ ranges;
++ };
++ };
++
++ pcie0: pcie@a0000000 {
++ compatible = "qcom,pcie-ipq5018";
++ reg = <0xa0000000 0xf1d>,
++ <0xa0000f20 0xa8>,
++ <0xa0001000 0x1000>,
++ <0x00080000 0x3000>,
++ <0xa0100000 0x1000>,
++ <0x00083000 0x1000>;
++ reg-names = "dbi",
++ "elbi",
++ "atu",
++ "parf",
++ "config",
++ "mhi";
++ device_type = "pci";
++ linux,pci-domain = <0>;
++ bus-range = <0x00 0xff>;
++ num-lanes = <2>;
++ #address-cells = <3>;
++ #size-cells = <2>;
++
++ /* The controller supports Gen3, but the connected PHY is Gen2-capable */
++ max-link-speed = <2>;
++
++ phys = <&pcie0_phy>;
++ phy-names ="pciephy";
++
++ ranges = <0x01000000 0 0x00000000 0xa0200000 0 0x00100000>,
++ <0x02000000 0 0xa0300000 0xa0300000 0 0x10000000>;
++
++ msi-map = <0x0 &v2m0 0x0 0xff8>;
++
++ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "msi0",
++ "msi1",
++ "msi2",
++ "msi3",
++ "msi4",
++ "msi5",
++ "msi6",
++ "msi7",
++ "global";
++
++ #interrupt-cells = <1>;
++ interrupt-map-mask = <0 0 0 0x7>;
++ interrupt-map = <0 0 0 1 &intc 0 0 75 IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 2 &intc 0 0 78 IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 3 &intc 0 0 79 IRQ_TYPE_LEVEL_HIGH>,
++ <0 0 0 4 &intc 0 0 83 IRQ_TYPE_LEVEL_HIGH>;
++
++ clocks = <&gcc GCC_SYS_NOC_PCIE0_AXI_CLK>,
++ <&gcc GCC_PCIE0_AXI_M_CLK>,
++ <&gcc GCC_PCIE0_AXI_S_CLK>,
++ <&gcc GCC_PCIE0_AHB_CLK>,
++ <&gcc GCC_PCIE0_AUX_CLK>,
++ <&gcc GCC_PCIE0_AXI_S_BRIDGE_CLK>;
++ clock-names = "iface",
++ "axi_m",
++ "axi_s",
++ "ahb",
++ "aux",
++ "axi_bridge";
++
++ resets = <&gcc GCC_PCIE0_PIPE_ARES>,
++ <&gcc GCC_PCIE0_SLEEP_ARES>,
++ <&gcc GCC_PCIE0_CORE_STICKY_ARES>,
++ <&gcc GCC_PCIE0_AXI_MASTER_ARES>,
++ <&gcc GCC_PCIE0_AXI_SLAVE_ARES>,
++ <&gcc GCC_PCIE0_AHB_ARES>,
++ <&gcc GCC_PCIE0_AXI_MASTER_STICKY_ARES>,
++ <&gcc GCC_PCIE0_AXI_SLAVE_STICKY_ARES>;
++ reset-names = "pipe",
++ "sleep",
++ "sticky",
++ "axi_m",
++ "axi_s",
++ "ahb",
++ "axi_m_sticky",
++ "axi_s_sticky";
++
++ status = "disabled";
++
++ pcie@0 {
++ device_type = "pci";
++ reg = <0x0 0x0 0x0 0x0 0x0>;
++ bus-range = <0x01 0xff>;
++
++ #address-cells = <3>;
++ #size-cells = <2>;
++ ranges;
++ };
++ };
+ };
+
+ timer {
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -147,6 +147,117 @@
+@@ -181,6 +181,117 @@
status = "disabled";
};
tlmm: pinctrl@1000000 {
compatible = "qcom,ipq5018-tlmm";
reg = <0x01000000 0x300000>;
-@@ -388,6 +499,64 @@
+@@ -624,6 +735,64 @@
};
};
};
+++ /dev/null
-Date: Thu, 2 Jan 2025 17:00:15 +0530
-Subject: [PATCH] dt-bindings: phy: qcom,uniphy-pcie: Document PCIe uniphy
-
-
-Document the Qualcomm UNIPHY PCIe 28LP present in IPQ5332.
-
----
---- /dev/null
-+++ b/Documentation/devicetree/bindings/phy/qcom,ipq5332-uniphy-pcie-phy.yaml
-@@ -0,0 +1,71 @@
-+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/phy/qcom,ipq5332-uniphy-pcie-phy.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Qualcomm UNIPHY PCIe 28LP PHY
-+
-+maintainers:
-+
-+description:
-+ PCIe and USB combo PHY found in Qualcomm IPQ5332 SoC
-+
-+properties:
-+ compatible:
-+ enum:
-+ - qcom,ipq5332-uniphy-pcie-phy
-+
-+ reg:
-+ maxItems: 1
-+
-+ clocks:
-+ items:
-+ - description: pcie pipe clock
-+ - description: pcie ahb clock
-+
-+ resets:
-+ items:
-+ - description: phy reset
-+ - description: ahb reset
-+ - description: cfg reset
-+
-+ "#phy-cells":
-+ const: 0
-+
-+ "#clock-cells":
-+ const: 0
-+
-+ num-lanes: true
-+
-+required:
-+ - compatible
-+ - reg
-+ - clocks
-+ - resets
-+ - "#phy-cells"
-+ - "#clock-cells"
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ #include <dt-bindings/clock/qcom,ipq5332-gcc.h>
-+
-+ pcie0_phy: phy@4b0000 {
-+ compatible = "qcom,ipq5332-uniphy-pcie-phy";
-+ reg = <0x004b0000 0x800>;
-+
-+ clocks = <&gcc GCC_PCIE3X1_0_PIPE_CLK>,
-+ <&gcc GCC_PCIE3X1_PHY_AHB_CLK>;
-+
-+ resets = <&gcc GCC_PCIE3X1_0_PHY_BCR>,
-+ <&gcc GCC_PCIE3X1_PHY_AHB_CLK_ARES>,
-+ <&gcc GCC_PCIE3X1_0_PHY_PHY_BCR>;
-+
-+ #clock-cells = <0>;
-+
-+ #phy-cells = <0>;
-+ };
+++ /dev/null
-Date: Thu, 2 Jan 2025 17:00:16 +0530
-Subject: [PATCH] phy: qcom: Introduce PCIe UNIPHY 28LP driver
-
-
-Add Qualcomm PCIe UNIPHY 28LP driver support present
-in Qualcomm IPQ5332 SoC and the phy init sequence.
-
----
---- a/drivers/phy/qualcomm/Kconfig
-+++ b/drivers/phy/qualcomm/Kconfig
-@@ -154,6 +154,18 @@ config PHY_QCOM_M31_USB
- management. This driver is required even for peripheral only or
- host only mode configurations.
-
-+config PHY_QCOM_UNIPHY_PCIE_28LP
-+ bool "PCIE UNIPHY 28LP PHY driver"
-+ depends on ARCH_QCOM
-+ depends on HAS_IOMEM
-+ depends on OF
-+ select GENERIC_PHY
-+ help
-+ Enable this to support the PCIe UNIPHY 28LP phy transceiver that
-+ is used with PCIe controllers on Qualcomm IPQ5332 chips. It
-+ handles PHY initialization, clock management required after
-+ resetting the hardware and power management.
-+
- config PHY_QCOM_USB_HS
- tristate "Qualcomm USB HS PHY module"
- depends on USB_ULPI_BUS
---- a/drivers/phy/qualcomm/Makefile
-+++ b/drivers/phy/qualcomm/Makefile
-@@ -17,6 +17,7 @@ obj-$(CONFIG_PHY_QCOM_QMP_USB_LEGACY) +=
- obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
- obj-$(CONFIG_PHY_QCOM_SNPS_EUSB2) += phy-qcom-snps-eusb2.o
- obj-$(CONFIG_PHY_QCOM_EUSB2_REPEATER) += phy-qcom-eusb2-repeater.o
-+obj-$(CONFIG_PHY_QCOM_UNIPHY_PCIE_28LP) += phy-qcom-uniphy-pcie-28lp.o
- obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o
- obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
- obj-$(CONFIG_PHY_QCOM_USB_HS_28NM) += phy-qcom-usb-hs-28nm.o
---- /dev/null
-+++ b/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
-@@ -0,0 +1,285 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (c) 2025, The Linux Foundation. All rights reserved.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/io.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/module.h>
-+#include <linux/of_device.h>
-+#include <linux/of.h>
-+#include <linux/phy/phy.h>
-+#include <linux/platform_device.h>
-+#include <linux/regmap.h>
-+#include <linux/reset.h>
-+
-+#define RST_ASSERT_DELAY_MIN_US 100
-+#define RST_ASSERT_DELAY_MAX_US 150
-+#define PIPE_CLK_DELAY_MIN_US 5000
-+#define PIPE_CLK_DELAY_MAX_US 5100
-+#define CLK_EN_DELAY_MIN_US 30
-+#define CLK_EN_DELAY_MAX_US 50
-+#define CDR_CTRL_REG_1 0x80
-+#define CDR_CTRL_REG_2 0x84
-+#define CDR_CTRL_REG_3 0x88
-+#define CDR_CTRL_REG_4 0x8c
-+#define CDR_CTRL_REG_5 0x90
-+#define CDR_CTRL_REG_6 0x94
-+#define CDR_CTRL_REG_7 0x98
-+#define SSCG_CTRL_REG_1 0x9c
-+#define SSCG_CTRL_REG_2 0xa0
-+#define SSCG_CTRL_REG_3 0xa4
-+#define SSCG_CTRL_REG_4 0xa8
-+#define SSCG_CTRL_REG_5 0xac
-+#define SSCG_CTRL_REG_6 0xb0
-+#define PCS_INTERNAL_CONTROL_2 0x2d8
-+
-+#define PHY_CFG_PLLCFG 0x220
-+#define PHY_CFG_EIOS_DTCT_REG 0x3e4
-+#define PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME 0x3e8
-+
-+#define PHY_MODE_FIXED 0x1
-+
-+enum qcom_uniphy_pcie_type {
-+ PHY_TYPE_PCIE = 1,
-+ PHY_TYPE_PCIE_GEN2,
-+ PHY_TYPE_PCIE_GEN3,
-+};
-+
-+struct qcom_uniphy_pcie_regs {
-+ u32 offset;
-+ u32 val;
-+};
-+
-+struct qcom_uniphy_pcie_data {
-+ int lane_offset; /* offset between the lane register bases */
-+ u32 phy_type;
-+ const struct qcom_uniphy_pcie_regs *init_seq;
-+ u32 init_seq_num;
-+ u32 pipe_clk_rate;
-+};
-+
-+struct qcom_uniphy_pcie {
-+ struct phy phy;
-+ struct device *dev;
-+ const struct qcom_uniphy_pcie_data *data;
-+ struct clk_bulk_data *clks;
-+ int num_clks;
-+ struct reset_control *resets;
-+ void __iomem *base;
-+ int lanes;
-+};
-+
-+#define phy_to_dw_phy(x) container_of((x), struct qca_uni_pcie_phy, phy)
-+
-+static const struct qcom_uniphy_pcie_regs ipq5332_regs[] = {
-+ {
-+ .offset = PHY_CFG_PLLCFG,
-+ .val = 0x30,
-+ }, {
-+ .offset = PHY_CFG_EIOS_DTCT_REG,
-+ .val = 0x53ef,
-+ }, {
-+ .offset = PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME,
-+ .val = 0xcf,
-+ },
-+};
-+
-+static const struct qcom_uniphy_pcie_data ipq5332_data = {
-+ .lane_offset = 0x800,
-+ .phy_type = PHY_TYPE_PCIE_GEN3,
-+ .init_seq = ipq5332_regs,
-+ .init_seq_num = ARRAY_SIZE(ipq5332_regs),
-+ .pipe_clk_rate = 250000000,
-+};
-+
-+static void qcom_uniphy_pcie_init(struct qcom_uniphy_pcie *phy)
-+{
-+ const struct qcom_uniphy_pcie_data *data = phy->data;
-+ const struct qcom_uniphy_pcie_regs *init_seq;
-+ void __iomem *base = phy->base;
-+ int lane, i;
-+
-+ for (lane = 0; lane < phy->lanes; lane++) {
-+ init_seq = data->init_seq;
-+
-+ for (i = 0; i < data->init_seq_num; i++)
-+ writel(init_seq[i].val, base + init_seq[i].offset);
-+
-+ base += data->lane_offset;
-+ }
-+}
-+
-+static int qcom_uniphy_pcie_power_off(struct phy *x)
-+{
-+ struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
-+
-+ clk_bulk_disable_unprepare(phy->num_clks, phy->clks);
-+
-+ return reset_control_assert(phy->resets);
-+}
-+
-+static int qcom_uniphy_pcie_power_on(struct phy *x)
-+{
-+ struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
-+ int ret;
-+
-+ ret = reset_control_assert(phy->resets);
-+ if (ret) {
-+ dev_err(phy->dev, "reset assert failed (%d)\n", ret);
-+ return ret;
-+ }
-+
-+ usleep_range(RST_ASSERT_DELAY_MIN_US, RST_ASSERT_DELAY_MAX_US);
-+
-+ ret = reset_control_deassert(phy->resets);
-+ if (ret) {
-+ dev_err(phy->dev, "reset deassert failed (%d)\n", ret);
-+ return ret;
-+ }
-+
-+ usleep_range(PIPE_CLK_DELAY_MIN_US, PIPE_CLK_DELAY_MAX_US);
-+
-+ ret = clk_bulk_prepare_enable(phy->num_clks, phy->clks);
-+ if (ret) {
-+ dev_err(phy->dev, "clk prepare and enable failed %d\n", ret);
-+ return ret;
-+ }
-+
-+ usleep_range(CLK_EN_DELAY_MIN_US, CLK_EN_DELAY_MAX_US);
-+
-+ qcom_uniphy_pcie_init(phy);
-+ return 0;
-+}
-+
-+static inline int qcom_uniphy_pcie_get_resources(struct platform_device *pdev,
-+ struct qcom_uniphy_pcie *phy)
-+{
-+ struct resource *res;
-+
-+ phy->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
-+ if (IS_ERR(phy->base))
-+ return PTR_ERR(phy->base);
-+
-+ phy->num_clks = devm_clk_bulk_get_all(phy->dev, &phy->clks);
-+ if (phy->num_clks < 0)
-+ return phy->num_clks;
-+
-+ phy->resets = devm_reset_control_array_get_exclusive(phy->dev);
-+ if (IS_ERR(phy->resets))
-+ return PTR_ERR(phy->resets);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Register a fixed rate pipe clock.
-+ *
-+ * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
-+ * controls it. The <s>_pipe_clk coming out of the GCC is requested
-+ * by the PHY driver for its operations.
-+ * We register the <s>_pipe_clksrc here. The gcc driver takes care
-+ * of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.
-+ * Below picture shows this relationship.
-+ *
-+ * +---------------+
-+ * | PHY block |<<---------------------------------------+
-+ * | | |
-+ * | +-------+ | +-----+ |
-+ * I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
-+ * clk | +-------+ | +-----+
-+ * +---------------+
-+ */
-+static inline int phy_pipe_clk_register(struct qcom_uniphy_pcie *phy, int id)
-+{
-+ const struct qcom_uniphy_pcie_data *data = phy->data;
-+ struct clk_hw *hw;
-+ char name[64];
-+
-+ snprintf(name, sizeof(name), "phy%d_pipe_clk_src", id);
-+ hw = devm_clk_hw_register_fixed_rate(phy->dev, name, NULL, 0,
-+ data->pipe_clk_rate);
-+ if (IS_ERR(hw))
-+ return dev_err_probe(phy->dev, PTR_ERR(hw),
-+ "Unable to register %s\n", name);
-+
-+ return devm_of_clk_add_hw_provider(phy->dev, of_clk_hw_simple_get, hw);
-+}
-+
-+static const struct of_device_id qcom_uniphy_pcie_id_table[] = {
-+ {
-+ .compatible = "qcom,ipq5332-uniphy-pcie-phy",
-+ .data = &ipq5332_data,
-+ }, {
-+ /* Sentinel */
-+ },
-+};
-+MODULE_DEVICE_TABLE(of, qcom_uniphy_pcie_id_table);
-+
-+static const struct phy_ops pcie_ops = {
-+ .power_on = qcom_uniphy_pcie_power_on,
-+ .power_off = qcom_uniphy_pcie_power_off,
-+ .owner = THIS_MODULE,
-+};
-+
-+static int qcom_uniphy_pcie_probe(struct platform_device *pdev)
-+{
-+ struct phy_provider *phy_provider;
-+ struct device *dev = &pdev->dev;
-+ struct qcom_uniphy_pcie *phy;
-+ struct phy *generic_phy;
-+ int ret;
-+
-+ phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
-+ if (!phy)
-+ return -ENOMEM;
-+
-+ platform_set_drvdata(pdev, phy);
-+ phy->dev = &pdev->dev;
-+
-+ phy->data = of_device_get_match_data(dev);
-+ if (!phy->data)
-+ return -EINVAL;
-+
-+ phy->lanes = 1;
-+ ret = of_property_read_u32(dev->of_node, "num-lanes", &phy->lanes);
-+
-+ ret = qcom_uniphy_pcie_get_resources(pdev, phy);
-+ if (ret < 0)
-+ return dev_err_probe(&pdev->dev, ret,
-+ "failed to get resources: %d\n", ret);
-+
-+ generic_phy = devm_phy_create(phy->dev, NULL, &pcie_ops);
-+ if (IS_ERR(generic_phy))
-+ return PTR_ERR(generic_phy);
-+
-+ phy_set_drvdata(generic_phy, phy);
-+
-+ ret = phy_pipe_clk_register(phy, generic_phy->id);
-+ if (ret)
-+ dev_err(&pdev->dev, "failed to register phy pipe clk\n");
-+
-+ phy_provider = devm_of_phy_provider_register(phy->dev,
-+ of_phy_simple_xlate);
-+ if (IS_ERR(phy_provider))
-+ return PTR_ERR(phy_provider);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver qcom_uniphy_pcie_driver = {
-+ .probe = qcom_uniphy_pcie_probe,
-+ .driver = {
-+ .name = "qcom-uniphy-pcie",
-+ .of_match_table = qcom_uniphy_pcie_id_table,
-+ },
-+};
-+
-+module_platform_driver(qcom_uniphy_pcie_driver);
-+
-+MODULE_DESCRIPTION("PCIE QCOM UNIPHY driver");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-Date: Tue, 07 Jan 2025 17:34:13 +0400
-Subject: [PATCH] phy: qualcomm: qcom-uniphy-pcie add IPQ5018 compatible
-
-The Qualcomm UNIPHY PCIe PHY 28lp part of the IPQ5332 SoC is also present on
-the IPQ5018 SoC, so adding the compatible for IPQ5018.
-
----
---- a/Documentation/devicetree/bindings/phy/qcom,ipq5332-uniphy-pcie-phy.yaml
-+++ b/Documentation/devicetree/bindings/phy/qcom,ipq5332-uniphy-pcie-phy.yaml
-@@ -11,11 +11,12 @@ maintainers:
-
- description:
-- PCIe and USB combo PHY found in Qualcomm IPQ5332 SoC
-+ PCIe and USB combo PHY found in Qualcomm IPQ5018 and IPQ5332 SoCs
-
- properties:
- compatible:
- enum:
-+ - qcom,ipq5018-uniphy-pcie-phy
- - qcom,ipq5332-uniphy-pcie-phy
-
- reg:
+++ /dev/null
-Date: Tue, 07 Jan 2025 17:34:13 +0400
-Subject: [PATCH] phy: qualcomm: qcom-uniphy-pcie 28lp add support for IPQ5018
-
-The Qualcomm UNIPHY PCIe PHY 28lp is found on both IPQ5332 and IPQ5018.
-Adding the PHY init sequence, pipe clock rate, and compatible for IPQ5018.
-
----
---- a/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
-+++ b/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
-@@ -76,6 +76,40 @@ struct qcom_uniphy_pcie {
-
- #define phy_to_dw_phy(x) container_of((x), struct qca_uni_pcie_phy, phy)
-
-+static const struct qcom_uniphy_pcie_regs ipq5018_regs[] = {
-+ {
-+ .offset = SSCG_CTRL_REG_4,
-+ .val = 0x1cb9,
-+ }, {
-+ .offset = SSCG_CTRL_REG_5,
-+ .val = 0x023a,
-+ }, {
-+ .offset = SSCG_CTRL_REG_3,
-+ .val = 0xd360,
-+ }, {
-+ .offset = SSCG_CTRL_REG_1,
-+ .val = 0x1,
-+ }, {
-+ .offset = SSCG_CTRL_REG_2,
-+ .val = 0xeb,
-+ }, {
-+ .offset = CDR_CTRL_REG_4,
-+ .val = 0x3f9,
-+ }, {
-+ .offset = CDR_CTRL_REG_5,
-+ .val = 0x1c9,
-+ }, {
-+ .offset = CDR_CTRL_REG_2,
-+ .val = 0x419,
-+ }, {
-+ .offset = CDR_CTRL_REG_1,
-+ .val = 0x200,
-+ }, {
-+ .offset = PCS_INTERNAL_CONTROL_2,
-+ .val = 0xf101,
-+ },
-+};
-+
- static const struct qcom_uniphy_pcie_regs ipq5332_regs[] = {
- {
- .offset = PHY_CFG_PLLCFG,
-@@ -89,6 +123,14 @@ static const struct qcom_uniphy_pcie_reg
- },
- };
-
-+static const struct qcom_uniphy_pcie_data ipq5018_data = {
-+ .lane_offset = 0x800,
-+ .phy_type = PHY_TYPE_PCIE_GEN2,
-+ .init_seq = ipq5018_regs,
-+ .init_seq_num = ARRAY_SIZE(ipq5018_regs),
-+ .pipe_clk_rate = 125000000,
-+};
-+
- static const struct qcom_uniphy_pcie_data ipq5332_data = {
- .lane_offset = 0x800,
- .phy_type = PHY_TYPE_PCIE_GEN3,
-@@ -212,6 +254,9 @@ static inline int phy_pipe_clk_register(
-
- static const struct of_device_id qcom_uniphy_pcie_id_table[] = {
- {
-+ .compatible = "qcom,ipq5018-uniphy-pcie-phy",
-+ .data = &ipq5018_data,
-+ }, {
- .compatible = "qcom,ipq5332-uniphy-pcie-phy",
- .data = &ipq5332_data,
- }, {
+++ /dev/null
-From patchwork Sat Apr 26 08:47:20 2025
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-X-Patchwork-Id: 14067566
-Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org
- [10.30.226.201])
- (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
- (No client certificate requested)
- by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7F4681C84B1;
- Sat, 26 Apr 2025 08:47:51 +0000 (UTC)
-Authentication-Results: smtp.subspace.kernel.org;
- arc=none smtp.client-ip=10.30.226.201
-ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;
- t=1745657271; cv=none;
- b=M866cJf/V6RxRwZ+Z/t6DUNC/4uUC28M2tFr3KZNsWjzpmjRvEQ0F/GNa8h5aJBvGnSEePGU/O/HxHPBxi4GiTA9ZVp/lf7Hs+r8IFTvSggG31OxmOlVKLlPaHAGfmFWYM/IFRz9vGSrVQ7gbQanlaR8yvblfamuIEHX1oJ+/ik=
-ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org;
- s=arc-20240116; t=1745657271; c=relaxed/simple;
- bh=s2C/YfnCIJHh91xdt3j52t+/ImXU3ihecScu2Iibt88=;
- h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References:
- In-Reply-To:To:Cc;
- b=dKXYWKjuQJO3BeaVAC5JVuoSJ538vu9FvW/1eGwbMzm5ZwQFOa1zMpipPc6YxOD9XZd4ckdLgr+eMg725RGmHklL/kvGpno5/oBRxdVmPAJLGO231PJgUdUGSvEZ3l2chja2181+a1mSPHhJ4aErT3SEYuWMrRf2NHDfC/Ac5wY=
-ARC-Authentication-Results: i=1; smtp.subspace.kernel.org;
- header.b=oFiqwO9r; arc=none smtp.client-ip=10.30.226.201
-Authentication-Results: smtp.subspace.kernel.org;
- header.b="oFiqwO9r"
-Received: by smtp.kernel.org (Postfix) with ESMTPS id EBA53C4CEEB;
- Sat, 26 Apr 2025 08:47:50 +0000 (UTC)
-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;
- s=k20201202; t=1745657271;
- bh=s2C/YfnCIJHh91xdt3j52t+/ImXU3ihecScu2Iibt88=;
- h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From;
- b=oFiqwO9r8uxa64raZD61ax5LqtigXQBAXL9AvrSRrZA/GiwcA1rmMAHQKdSaS/zin
- LpatrrfpB+O005agqR5ce8kxbHa6402LS4WZPYz6H+1xJYPjUmLnNsl2vboufmGrG6
- b+JrwDy5UWsBWZVvZgTUF5D9U95ZWI3iHDOUek0lkyR9EHvqUiMb/ELtA7feFItqEs
- M/QeZWHKvGgfhpOtfEcRZYcdS5c8FdFDlTf5k2r0sRBKBM2XzzyIrtNtQqi+/bhvtr
- sIu+wvwZhfGgJsGT8dDpLTcukN2anyL01bB076AHp3MzI2d4ggYYRFv09yVnzj50XD
- 5nMOYnjtjTZQw==
-Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org
- (localhost.localdomain [127.0.0.1])
- by smtp.lore.kernel.org (Postfix) with ESMTP id DB3E5C369D1;
- Sat, 26 Apr 2025 08:47:50 +0000 (UTC)
-Date: Sat, 26 Apr 2025 12:47:20 +0400
-Subject: [PATCH v9 1/2] arm64: dts: qcom: ipq5018: Add PCIe related nodes
-Precedence: bulk
-List-Id: <linux-arm-msm.vger.kernel.org>
-MIME-Version: 1.0
-X-Mailer: b4 0.14.2
-X-Developer-Signature: v=1; a=ed25519-sha256; t=1745657268; l=7874;
- bh=kGrZ/VHv+p7/RMeNwr0Kf61p0n/Ee/GyXpuErx0N1DQ=;
- b=dmN2go3sL7VarHf/cZsYp30QQnlAI+awY3vAVLx+86ukud+nG2PwQ8rx7Aw64wCDmqdJayYWz
- AhTM382VJf9AvbWcGs1CzUJw16JbmI8XNWnRHjhwbchkLu3okeDVfqI
- pk=/PuRTSI9iYiHwcc6Nrde8qF4ZDhJBlUgpHdhsIjnqIk=
- with auth_id=364
-
-
-Add phy and controller nodes for a 2-lane Gen2 and
-a 1-lane Gen2 PCIe bus. IPQ5018 has 8 MSI SPI interrupts and
-one global interrupt.
-
-NOTE: the PCIe controller supports gen3, yet the phy is limited to gen2.
-
----
- arch/arm64/boot/dts/qcom/ipq5018.dtsi | 238 +++++++++++++++++++++++++++++++++-
- 1 file changed, 236 insertions(+), 2 deletions(-)
-
---- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -258,6 +258,40 @@
- #thermal-sensor-cells = <1>;
- };
-
-+ pcie1_phy: phy@7e000 {
-+ compatible = "qcom,ipq5018-uniphy-pcie-phy";
-+ reg = <0x0007e000 0x800>;
-+
-+ clocks = <&gcc GCC_PCIE1_PIPE_CLK>;
-+
-+ resets = <&gcc GCC_PCIE1_PHY_BCR>,
-+ <&gcc GCC_PCIE1PHY_PHY_BCR>;
-+
-+ #clock-cells = <0>;
-+ #phy-cells = <0>;
-+
-+ num-lanes = <1>;
-+
-+ status = "disabled";
-+ };
-+
-+ pcie0_phy: phy@86000 {
-+ compatible = "qcom,ipq5018-uniphy-pcie-phy";
-+ reg = <0x00086000 0x1000>;
-+
-+ clocks = <&gcc GCC_PCIE0_PIPE_CLK>;
-+
-+ resets = <&gcc GCC_PCIE0_PHY_BCR>,
-+ <&gcc GCC_PCIE0PHY_PHY_BCR>;
-+
-+ #clock-cells = <0>;
-+ #phy-cells = <0>;
-+
-+ num-lanes = <2>;
-+
-+ status = "disabled";
-+ };
-+
- tlmm: pinctrl@1000000 {
- compatible = "qcom,ipq5018-tlmm";
- reg = <0x01000000 0x300000>;
-@@ -281,8 +315,8 @@
- reg = <0x01800000 0x80000>;
- clocks = <&xo_board_clk>,
- <&sleep_clk>,
-- <0>,
-- <0>,
-+ <&pcie0_phy>,
-+ <&pcie1_phy>,
- <0>,
- <0>,
- <0>,
-@@ -498,6 +532,208 @@
- status = "disabled";
- };
- };
-+
-+ pcie1: pcie@80000000 {
-+ compatible = "qcom,pcie-ipq5018";
-+ reg = <0x80000000 0xf1d>,
-+ <0x80000f20 0xa8>,
-+ <0x80001000 0x1000>,
-+ <0x00078000 0x3000>,
-+ <0x80100000 0x1000>,
-+ <0x0007b000 0x1000>;
-+ reg-names = "dbi",
-+ "elbi",
-+ "atu",
-+ "parf",
-+ "config",
-+ "mhi";
-+ device_type = "pci";
-+ linux,pci-domain = <1>;
-+ bus-range = <0x00 0xff>;
-+ num-lanes = <1>;
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+
-+ /* The controller supports Gen3, but the connected PHY is Gen2-capable */
-+ max-link-speed = <2>;
-+
-+ phys = <&pcie1_phy>;
-+ phy-names ="pciephy";
-+
-+ ranges = <0x01000000 0 0x00000000 0x80200000 0 0x00100000>,
-+ <0x02000000 0 0x80300000 0x80300000 0 0x10000000>;
-+
-+ msi-map = <0x0 &v2m0 0x0 0xff8>;
-+
-+ interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "msi0",
-+ "msi1",
-+ "msi2",
-+ "msi3",
-+ "msi4",
-+ "msi5",
-+ "msi6",
-+ "msi7",
-+ "global";
-+
-+ #interrupt-cells = <1>;
-+ interrupt-map-mask = <0 0 0 0x7>;
-+ interrupt-map = <0 0 0 1 &intc 0 0 142 IRQ_TYPE_LEVEL_HIGH>,
-+ <0 0 0 2 &intc 0 0 143 IRQ_TYPE_LEVEL_HIGH>,
-+ <0 0 0 3 &intc 0 0 144 IRQ_TYPE_LEVEL_HIGH>,
-+ <0 0 0 4 &intc 0 0 145 IRQ_TYPE_LEVEL_HIGH>;
-+
-+ clocks = <&gcc GCC_SYS_NOC_PCIE1_AXI_CLK>,
-+ <&gcc GCC_PCIE1_AXI_M_CLK>,
-+ <&gcc GCC_PCIE1_AXI_S_CLK>,
-+ <&gcc GCC_PCIE1_AHB_CLK>,
-+ <&gcc GCC_PCIE1_AUX_CLK>,
-+ <&gcc GCC_PCIE1_AXI_S_BRIDGE_CLK>;
-+ clock-names = "iface",
-+ "axi_m",
-+ "axi_s",
-+ "ahb",
-+ "aux",
-+ "axi_bridge";
-+
-+ resets = <&gcc GCC_PCIE1_PIPE_ARES>,
-+ <&gcc GCC_PCIE1_SLEEP_ARES>,
-+ <&gcc GCC_PCIE1_CORE_STICKY_ARES>,
-+ <&gcc GCC_PCIE1_AXI_MASTER_ARES>,
-+ <&gcc GCC_PCIE1_AXI_SLAVE_ARES>,
-+ <&gcc GCC_PCIE1_AHB_ARES>,
-+ <&gcc GCC_PCIE1_AXI_MASTER_STICKY_ARES>,
-+ <&gcc GCC_PCIE1_AXI_SLAVE_STICKY_ARES>;
-+ reset-names = "pipe",
-+ "sleep",
-+ "sticky",
-+ "axi_m",
-+ "axi_s",
-+ "ahb",
-+ "axi_m_sticky",
-+ "axi_s_sticky";
-+
-+ status = "disabled";
-+
-+ pcie@0 {
-+ device_type = "pci";
-+ reg = <0x0 0x0 0x0 0x0 0x0>;
-+ bus-range = <0x01 0xff>;
-+
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+ ranges;
-+ };
-+ };
-+
-+ pcie0: pcie@a0000000 {
-+ compatible = "qcom,pcie-ipq5018";
-+ reg = <0xa0000000 0xf1d>,
-+ <0xa0000f20 0xa8>,
-+ <0xa0001000 0x1000>,
-+ <0x00080000 0x3000>,
-+ <0xa0100000 0x1000>,
-+ <0x00083000 0x1000>;
-+ reg-names = "dbi",
-+ "elbi",
-+ "atu",
-+ "parf",
-+ "config",
-+ "mhi";
-+ device_type = "pci";
-+ linux,pci-domain = <0>;
-+ bus-range = <0x00 0xff>;
-+ num-lanes = <2>;
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+
-+ /* The controller supports Gen3, but the connected PHY is Gen2-capable */
-+ max-link-speed = <2>;
-+
-+ phys = <&pcie0_phy>;
-+ phy-names ="pciephy";
-+
-+ ranges = <0x01000000 0 0x00000000 0xa0200000 0 0x00100000>,
-+ <0x02000000 0 0xa0300000 0xa0300000 0 0x10000000>;
-+
-+ msi-map = <0x0 &v2m0 0x0 0xff8>;
-+
-+ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "msi0",
-+ "msi1",
-+ "msi2",
-+ "msi3",
-+ "msi4",
-+ "msi5",
-+ "msi6",
-+ "msi7",
-+ "global";
-+
-+ #interrupt-cells = <1>;
-+ interrupt-map-mask = <0 0 0 0x7>;
-+ interrupt-map = <0 0 0 1 &intc 0 0 75 IRQ_TYPE_LEVEL_HIGH>,
-+ <0 0 0 2 &intc 0 0 78 IRQ_TYPE_LEVEL_HIGH>,
-+ <0 0 0 3 &intc 0 0 79 IRQ_TYPE_LEVEL_HIGH>,
-+ <0 0 0 4 &intc 0 0 83 IRQ_TYPE_LEVEL_HIGH>;
-+
-+ clocks = <&gcc GCC_SYS_NOC_PCIE0_AXI_CLK>,
-+ <&gcc GCC_PCIE0_AXI_M_CLK>,
-+ <&gcc GCC_PCIE0_AXI_S_CLK>,
-+ <&gcc GCC_PCIE0_AHB_CLK>,
-+ <&gcc GCC_PCIE0_AUX_CLK>,
-+ <&gcc GCC_PCIE0_AXI_S_BRIDGE_CLK>;
-+ clock-names = "iface",
-+ "axi_m",
-+ "axi_s",
-+ "ahb",
-+ "aux",
-+ "axi_bridge";
-+
-+ resets = <&gcc GCC_PCIE0_PIPE_ARES>,
-+ <&gcc GCC_PCIE0_SLEEP_ARES>,
-+ <&gcc GCC_PCIE0_CORE_STICKY_ARES>,
-+ <&gcc GCC_PCIE0_AXI_MASTER_ARES>,
-+ <&gcc GCC_PCIE0_AXI_SLAVE_ARES>,
-+ <&gcc GCC_PCIE0_AHB_ARES>,
-+ <&gcc GCC_PCIE0_AXI_MASTER_STICKY_ARES>,
-+ <&gcc GCC_PCIE0_AXI_SLAVE_STICKY_ARES>;
-+ reset-names = "pipe",
-+ "sleep",
-+ "sticky",
-+ "axi_m",
-+ "axi_s",
-+ "ahb",
-+ "axi_m_sticky",
-+ "axi_s_sticky";
-+
-+ status = "disabled";
-+
-+ pcie@0 {
-+ device_type = "pci";
-+ reg = <0x0 0x0 0x0 0x0 0x0>;
-+ bus-range = <0x01 0xff>;
-+
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+ ranges;
-+ };
-+ };
- };
-
- thermal-zones {
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
@@ -293,6 +293,30 @@
- status = "disabled";
+ #thermal-sensor-cells = <1>;
};
+ cryptobam: dma-controller@704000 {
---
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -220,6 +220,14 @@
+@@ -254,6 +254,14 @@
};
};
sleep_clk: sleep-clk {
compatible = "fixed-clock";
#clock-cells = <0>;
-@@ -148,6 +154,19 @@
+@@ -182,6 +188,19 @@
status = "disabled";
};
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -154,6 +154,30 @@
+@@ -188,6 +188,30 @@
status = "disabled";
};
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
-@@ -164,6 +164,21 @@
+@@ -198,6 +198,21 @@
clock-names = "gcc_mdio_ahb_clk";
status = "disabled";