From: John Crispin <[email protected]>

This adds PCIe controller support for the MediaTek Filogic family..

Signed-off-by: John Crispin <[email protected]>
Signed-off-by: Frank Wunderlich <[email protected]>
---
Note for mt7988: pcie2 needs a dedicated phy which has no driver
in uboot yet, so this pcie port is not enabled in the board device-
trees.

Note for mt7981: i have no board and have no dts nodes yet for it,
so only clock change first.
---
 arch/arm/dts/mt7986.dtsi               |  46 +++
 arch/arm/dts/mt7988-rfb.dts            |  12 +
 arch/arm/dts/mt7988-sd-rfb.dts         |  12 +
 arch/arm/dts/mt7988.dtsi               | 164 +++++++++++
 drivers/clk/mediatek/clk-mt7986.c      |   5 +-
 drivers/pci/Kconfig                    |   7 +
 drivers/pci/Makefile                   |   1 +
 drivers/pci/pcie_mediatek_gen3.c       | 382 +++++++++++++++++++++++++
 include/dt-bindings/clock/mt7981-clk.h |   3 +-
 include/dt-bindings/clock/mt7986-clk.h |   3 +-
 10 files changed, 631 insertions(+), 4 deletions(-)
 create mode 100644 drivers/pci/pcie_mediatek_gen3.c

diff --git a/arch/arm/dts/mt7986.dtsi b/arch/arm/dts/mt7986.dtsi
index c9aeeaca2b11..9a9b0b64cc68 100644
--- a/arch/arm/dts/mt7986.dtsi
+++ b/arch/arm/dts/mt7986.dtsi
@@ -375,5 +375,51 @@
                        #phy-cells = <1>;
                        status = "okay";
                };
+
+               pcie_port: pcie-phy@11c00000 {
+                       reg = <0x11c00000 0x20000>;
+                       clocks = <&dummy_clk>;
+                       clock-names = "ref";
+                       #phy-cells = <1>;
+                       status = "okay";
+               };
+       };
+
+       pcie: pcie@11280000 {
+               compatible = "mediatek,mt7986-pcie",
+                            "mediatek,mt8192-pcie";
+               device_type = "pci";
+               reg = <0x11280000 0x4000>;
+               reg-names = "pcie-mac";
+               #address-cells = <3>;
+               #size-cells = <2>;
+
+               clocks = <&infracfg_ao CK_INFRA_IPCIE_PIPE_CK>,
+                        <&infracfg_ao CK_INFRA_IPCIE_CK>,
+                        <&infracfg_ao CK_INFRA_IPCIER_CK>,
+                        <&infracfg_ao CK_INFRA_IPCIEB_CK>;
+               clock-names = "pl_250m", "tl_26m", "peri_26m", "top_133m";
+
+               bus-range = <0x00 0xff>;
+               ranges = <0x82000000 0 0x20000000 0x20000000 0 0x10000000>;
+
+               interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+               #interrupt-cells = <2>;
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pcie_intc 0>, /* INTA */
+                               <0 0 0 2 &pcie_intc 1>, /* INTB */
+                               <0 0 0 3 &pcie_intc 2>, /* INTC */
+                               <0 0 0 4 &pcie_intc 3>; /* INTD */
+
+               phy-names = "pcie-phy";
+               phys = <&pcie_port PHY_TYPE_PCIE>;
+
+               status = "okay";
+
+               pcie_intc: legacy-interrupt-controller {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+               };
        };
 };
diff --git a/arch/arm/dts/mt7988-rfb.dts b/arch/arm/dts/mt7988-rfb.dts
index 2c1142843091..2f0d00b6950b 100644
--- a/arch/arm/dts/mt7988-rfb.dts
+++ b/arch/arm/dts/mt7988-rfb.dts
@@ -180,3 +180,15 @@
        non-removable;
        status = "okay";
 };
+
+&pcie0 {
+       status = "okay";
+};
+
+&pcie1 {
+       status = "okay";
+};
+
+&pcie3 {
+       status = "okay";
+};
diff --git a/arch/arm/dts/mt7988-sd-rfb.dts b/arch/arm/dts/mt7988-sd-rfb.dts
index a3df37d252de..0a3eb5360d21 100644
--- a/arch/arm/dts/mt7988-sd-rfb.dts
+++ b/arch/arm/dts/mt7988-sd-rfb.dts
@@ -132,3 +132,15 @@
        vqmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
+
+&pcie0 {
+       status = "okay";
+};
+
+&pcie1 {
+       status = "okay";
+};
+
+&pcie3 {
+       status = "okay";
+};
diff --git a/arch/arm/dts/mt7988.dtsi b/arch/arm/dts/mt7988.dtsi
index ac476d5cdd7f..b2e2724732fc 100644
--- a/arch/arm/dts/mt7988.dtsi
+++ b/arch/arm/dts/mt7988.dtsi
@@ -194,6 +194,152 @@
                status = "okay";
        };
 
+       pcie2: pcie@11280000 {
+               compatible = "mediatek,mt7988-pcie",
+                            "mediatek,mt7986-pcie",
+                            "mediatek,mt8192-pcie";
+               device_type = "pci";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               reg = <0 0x11280000 0 0x2000>;
+               reg-names = "pcie-mac";
+               linux,pci-domain = <3>;
+               interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
+               bus-range = <0x00 0xff>;
+               ranges = <0x82000000 0 0x20200000 0 0x20200000 0 0x07e00000>;
+               clocks = <&infracfg_ao_cgs CK_INFRA_PCIE_PIPE_P2>,
+                        <&infracfg_ao_cgs CK_INFRA_PCIE_GFMUX_TL_P2>,
+                        <&infracfg_ao_cgs CK_INFRA_PCIE_PERI_26M_CK_P2>,
+                        <&infracfg_ao_cgs CK_INFRA_133M_PCIE_CK_P2>;
+               clock-names = "pl_250m", "tl_26m", "peri_26m",
+                             "top_133m";
+               phys = <&xphyu3port0 PHY_TYPE_PCIE>;
+               phy-names = "pcie-phy";
+
+               status = "disabled";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0x7>;
+               interrupt-map = <0 0 0 1 &pcie_intc2 0>,
+                               <0 0 0 2 &pcie_intc2 1>,
+                               <0 0 0 3 &pcie_intc2 2>,
+                               <0 0 0 4 &pcie_intc2 3>;
+
+               pcie_intc2: interrupt-controller {
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+                       interrupt-controller;
+               };
+       };
+
+       pcie3: pcie@11290000 {
+               compatible = "mediatek,mt7988-pcie",
+                            "mediatek,mt7986-pcie",
+                            "mediatek,mt8192-pcie";
+               device_type = "pci";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               reg = <0 0x11290000 0 0x2000>;
+               reg-names = "pcie-mac";
+               linux,pci-domain = <2>;
+               interrupts = <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
+               bus-range = <0x00 0xff>;
+               ranges = <0x82000000 0 0x28200000 0 0x28200000 0 0x07e00000>;
+               clocks = <&infracfg_ao_cgs CK_INFRA_PCIE_PIPE_P3>,
+                        <&infracfg_ao_cgs CK_INFRA_PCIE_GFMUX_TL_P3>,
+                        <&infracfg_ao_cgs CK_INFRA_PCIE_PERI_26M_CK_P3>,
+                        <&infracfg_ao_cgs CK_INFRA_133M_PCIE_CK_P3>;
+               clock-names = "pl_250m", "tl_26m", "peri_26m",
+                             "top_133m";
+               use-dedicated-phy;
+
+               status = "disabled";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0x7>;
+               interrupt-map = <0 0 0 1 &pcie_intc3 0>,
+                               <0 0 0 2 &pcie_intc3 1>,
+                               <0 0 0 3 &pcie_intc3 2>,
+                               <0 0 0 4 &pcie_intc3 3>;
+               pcie_intc3: interrupt-controller {
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+                       interrupt-controller;
+               };
+       };
+
+       pcie0: pcie@11300000 {
+               compatible = "mediatek,mt7988-pcie",
+                            "mediatek,mt7986-pcie",
+                            "mediatek,mt8192-pcie";
+               device_type = "pci";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               reg = <0 0x11300000 0 0x2000>;
+               reg-names = "pcie-mac";
+               linux,pci-domain = <0>;
+               interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+               bus-range = <0x00 0xff>;
+               ranges = <0x82000000 0 0x30200000 0 0x30200000 0 0x07e00000>;
+               clocks = <&infracfg_ao_cgs CK_INFRA_PCIE_PIPE_P0>,
+                        <&infracfg_ao_cgs CK_INFRA_PCIE_GFMUX_TL_P0>,
+                        <&infracfg_ao_cgs CK_INFRA_PCIE_PERI_26M_CK_P0>,
+                        <&infracfg_ao_cgs CK_INFRA_133M_PCIE_CK_P0>;
+               clock-names = "pl_250m", "tl_26m", "peri_26m",
+                             "top_133m";
+               use-dedicated-phy;
+
+               status = "disabled";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0x7>;
+               interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+                               <0 0 0 2 &pcie_intc0 1>,
+                               <0 0 0 3 &pcie_intc0 2>,
+                               <0 0 0 4 &pcie_intc0 3>;
+               pcie_intc0: interrupt-controller {
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+                       interrupt-controller;
+               };
+       };
+
+       pcie1: pcie@11310000 {
+               compatible = "mediatek,mt7988-pcie",
+                            "mediatek,mt7986-pcie",
+                            "mediatek,mt8192-pcie";
+               device_type = "pci";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               reg = <0 0x11310000 0 0x2000>;
+               reg-names = "pcie-mac";
+               linux,pci-domain = <1>;
+               interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+               bus-range = <0x00 0xff>;
+               ranges = <0x82000000 0 0x38200000 0 0x38200000 0 0x07e00000>;
+               clocks = <&infracfg_ao_cgs CK_INFRA_PCIE_PIPE_P1>,
+                        <&infracfg_ao_cgs CK_INFRA_PCIE_GFMUX_TL_P1>,
+                        <&infracfg_ao_cgs CK_INFRA_PCIE_PERI_26M_CK_P1>,
+                        <&infracfg_ao_cgs CK_INFRA_133M_PCIE_CK_P1>;
+               clock-names = "pl_250m", "tl_26m", "peri_26m",
+                             "top_133m";
+               use-dedicated-phy;
+
+               status = "disabled";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0x7>;
+               interrupt-map = <0 0 0 1 &pcie_intc1 0>,
+                               <0 0 0 2 &pcie_intc1 1>,
+                               <0 0 0 3 &pcie_intc1 2>,
+                               <0 0 0 4 &pcie_intc1 3>;
+               pcie_intc1: interrupt-controller {
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+                       interrupt-controller;
+               };
+       };
+
        usbtphy: usb-phy@11c50000 {
                compatible = "mediatek,mt7988",
                             "mediatek,generic-tphy-v2";
@@ -219,6 +365,24 @@
                        mediatek,usb3-pll-ssc-delta1;
                        status = "okay";
                };
+
+       };
+
+       xphy: xphy@11e10000 {
+               compatible = "mediatek,mt7988",
+               "mediatek,xsphy";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+               status = "disabled";
+
+               xphyu3port0: usb-phy@11e13000 {
+                       reg = <0 0x11e13400 0 0x500>;
+                       clocks = <&dummy_clk>;
+                       clock-names = "ref";
+                       #phy-cells = <1>;
+                       status = "okay";
+               };
        };
 
        xfi_pextp0: syscon@11f20000 {
diff --git a/drivers/clk/mediatek/clk-mt7986.c 
b/drivers/clk/mediatek/clk-mt7986.c
index b3fa63fc0ab4..93e02cd23ac1 100644
--- a/drivers/clk/mediatek/clk-mt7986.c
+++ b/drivers/clk/mediatek/clk-mt7986.c
@@ -504,8 +504,9 @@ static const struct mtk_gate infracfg_ao_gates[] = {
        GATE_INFRA2(CK_INFRA_IUSB_SYS_CK, "infra_iusb_sys", CK_INFRA_USB_SYS_CK,
                    2),
        GATE_INFRA2(CK_INFRA_IUSB_CK, "infra_iusb", CK_INFRA_USB_CK, 3),
-       GATE_INFRA2(CK_INFRA_IPCIE_CK, "infra_ipcie", CK_INFRA_PCIE_CK, 13),
-       GATE_INFRA2(CK_INFRA_IPCIER_CK, "infra_ipcier", CK_INFRA_F26M_CK0, 15),
+       GATE_INFRA2(CK_INFRA_IPCIE_CK, "infra_ipcie", CK_INFRA_PCIE_CK, 12),
+       GATE_INFRA2(CK_INFRA_IPCIE_PIPE_CK, "infra_ipcie_pipe", 
CK_INFRA_PCIE_CK, 13),
+       GATE_INFRA2(CK_INFRA_IPCIER_CK, "infra_ipcier", CK_INFRA_F26M_CK0, 14),
        GATE_INFRA2(CK_INFRA_IPCIEB_CK, "infra_ipcieb", CK_INFRA_133M_PHCK, 15),
 };
 
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 463ec47eb92d..f62a9844b1ef 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -350,6 +350,13 @@ config PCIE_MEDIATEK
          Say Y here if you want to enable Gen2 PCIe controller,
          which could be found on MT7623 SoC family.
 
+config PCIE_MEDIATEK_GEN3
+       bool "MediaTek PCIe Gen3 controller"
+       depends on ARCH_MEDIATEK
+       help
+         Say Y here if you want to enable Gen3 PCIe controller,
+         which could be found on the Mediatek Filogic SoC family.
+
 config PCIE_DW_MESON
        bool "Amlogic Meson DesignWare based PCIe controller"
        depends on ARCH_MESON
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 72ef8b4bc772..aa254a2f4338 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
 obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o
 obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o
 obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
+obj-$(CONFIG_PCIE_MEDIATEK_GEN3) += pcie_mediatek_gen3.o
 obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o
 obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie_dw_rockchip.o
 obj-$(CONFIG_PCIE_DW_MESON) += pcie_dw_meson.o
diff --git a/drivers/pci/pcie_mediatek_gen3.c b/drivers/pci/pcie_mediatek_gen3.c
new file mode 100644
index 000000000000..a273ea123aaa
--- /dev/null
+++ b/drivers/pci/pcie_mediatek_gen3.c
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek PCIe host controller driver.
+ *
+ * Copyright (c) 2023 John Crispin <[email protected]>
+ * Driver is based on u-boot gen1/2 and upstream linux gen3 code
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <malloc.h>
+#include <pci.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <dm/devres.h>
+#include <linux/bitops.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include "pci_internal.h"
+
+/* PCIe shared registers */
+#define PCIE_CFG_ADDR                  0x20
+#define PCIE_CFG_DATA                  0x24
+
+#define PCIE_SETTING_REG               0x80
+
+#define PCIE_PCI_IDS_1                 0x9c
+#define PCIE_RC_MODE                   BIT(0)
+#define PCI_CLASS(class)               (class << 8)
+
+#define PCIE_CFGNUM_REG                        0x140
+#define PCIE_CFG_DEVFN(devfn)          ((devfn) & GENMASK(7, 0))
+#define PCIE_CFG_BUS(bus)              (((bus) << 8) & GENMASK(15, 8))
+#define PCIE_CFG_BYTE_EN(bytes)                (((bytes) << 16) & GENMASK(19, 
16))
+#define PCIE_CFG_FORCE_BYTE_EN         BIT(20)
+#define PCIE_CFG_OFFSET_ADDR           0x1000
+#define PCIE_CFG_HEADER(bus, devfn)    (PCIE_CFG_BUS(bus) | 
PCIE_CFG_DEVFN(devfn))
+
+#define PCIE_RST_CTRL_REG              0x148
+#define PCIE_MAC_RSTB                  BIT(0)
+#define PCIE_PHY_RSTB                  BIT(1)
+#define PCIE_BRG_RSTB                  BIT(2)
+#define PCIE_PE_RSTB                   BIT(3)
+
+#define PCIE_LINK_STATUS_REG           0x154
+#define PCIE_PORT_LINKUP               BIT(8)
+
+#define PCIE_INT_ENABLE_REG            0x180
+
+#define PCIE_MISC_CTRL_REG             0x348
+#define PCIE_DISABLE_DVFSRC_VLT_REQ    BIT(1)
+
+#define PCIE_TRANS_TABLE_BASE_REG       0x800
+#define PCIE_ATR_SRC_ADDR_MSB_OFFSET    0x4
+#define PCIE_ATR_TRSL_ADDR_LSB_OFFSET   0x8
+#define PCIE_ATR_TRSL_ADDR_MSB_OFFSET   0xc
+#define PCIE_ATR_TRSL_PARAM_OFFSET      0x10
+#define PCIE_ATR_TLB_SET_OFFSET         0x20
+
+#define PCIE_MAX_TRANS_TABLES           8
+#define PCIE_ATR_EN                     BIT(0)
+#define PCIE_ATR_SIZE(size) \
+       (((((size) - 1) << 1) & GENMASK(6, 1)) | PCIE_ATR_EN)
+#define PCIE_ATR_ID(id)                 ((id) & GENMASK(3, 0))
+#define PCIE_ATR_TYPE_MEM               PCIE_ATR_ID(0)
+#define PCIE_ATR_TYPE_IO                PCIE_ATR_ID(1)
+#define PCIE_ATR_TLP_TYPE(type)         (((type) << 16) & GENMASK(18, 16))
+#define PCIE_ATR_TLP_TYPE_MEM           PCIE_ATR_TLP_TYPE(0)
+#define PCIE_ATR_TLP_TYPE_IO            PCIE_ATR_TLP_TYPE(2)
+
+struct mtk_pcie {
+       void __iomem *base;
+       void *priv;
+       struct clk pl_250m_ck;
+       struct clk tl_26m_ck;
+       struct clk peri_26m_ck;
+       struct clk top_133m_ck;
+       struct reset_ctl reset_phy;
+       struct reset_ctl reset_mac;
+       bool use_dedicated_phy;
+       struct phy phy;
+};
+
+static void mtk_pcie_config_tlp_header(const struct udevice *bus,
+                                      pci_dev_t devfn,
+                                      int where, int size)
+{
+       struct mtk_pcie *pcie = dev_get_priv(bus);
+       int bytes;
+       u32 val;
+
+       size = 1 << size;
+       bytes = (GENMASK(size - 1, 0) & 0xf) << (where & 0x3);
+
+       val = PCIE_CFG_FORCE_BYTE_EN | PCIE_CFG_BYTE_EN(bytes) |
+             PCIE_CFG_HEADER(PCI_BUS(devfn), (devfn >> 8));
+
+       writel(val, pcie->base + PCIE_CFGNUM_REG);
+}
+
+static int mtk_pcie_config_address(const struct udevice *udev, pci_dev_t bdf,
+                                  uint offset, void **paddress)
+{
+       struct mtk_pcie *pcie = dev_get_priv(udev);
+
+       *paddress = pcie->base + PCIE_CFG_OFFSET_ADDR + offset;
+
+       return 0;
+}
+
+static int mtk_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
+                               uint offset, ulong *valuep,
+                               enum pci_size_t size)
+{
+       int ret;
+
+       mtk_pcie_config_tlp_header(bus, bdf, offset, size);
+       ret = pci_generic_mmap_read_config(bus, mtk_pcie_config_address,
+                                          bdf, offset, valuep, size);
+       return ret;
+}
+
+static int mtk_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
+                                uint offset, ulong value,
+                                enum pci_size_t size)
+{
+       mtk_pcie_config_tlp_header(bus, bdf, offset, size);
+
+       switch (size) {
+       case PCI_SIZE_8:
+       case PCI_SIZE_16:
+               value <<= (offset & 0x3) * 8;
+       case PCI_SIZE_32:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return pci_generic_mmap_write_config(bus, mtk_pcie_config_address,
+                                            bdf, (offset & ~0x3), value, 
PCI_SIZE_32);
+}
+
+static const struct dm_pci_ops mtk_pcie_ops = {
+       .read_config    = mtk_pcie_read_config,
+       .write_config   = mtk_pcie_write_config,
+};
+
+static int mtk_pcie_set_trans_table(struct mtk_pcie *pcie, u64 cpu_addr,
+                                   u64 pci_addr, u64 size,
+                                   unsigned long type, int num)
+{
+       void __iomem *table;
+       u32 val;
+
+       if (num >= PCIE_MAX_TRANS_TABLES) {
+               printf("not enough translate table for addr: %#llx, limited to 
[%d]\n",
+                      (unsigned long long)cpu_addr, PCIE_MAX_TRANS_TABLES);
+               return -ENODEV;
+       }
+
+       table = pcie->base + PCIE_TRANS_TABLE_BASE_REG +
+               num * PCIE_ATR_TLB_SET_OFFSET;
+
+       writel(lower_32_bits(cpu_addr) | PCIE_ATR_SIZE(fls(size) - 1), table);
+       writel(upper_32_bits(cpu_addr), table + PCIE_ATR_SRC_ADDR_MSB_OFFSET);
+       writel(lower_32_bits(pci_addr), table + PCIE_ATR_TRSL_ADDR_LSB_OFFSET);
+       writel(upper_32_bits(pci_addr), table + PCIE_ATR_TRSL_ADDR_MSB_OFFSET);
+
+       if (type == PCI_REGION_IO)
+               val = PCIE_ATR_TYPE_IO | PCIE_ATR_TLP_TYPE_IO;
+       else
+               val = PCIE_ATR_TYPE_MEM | PCIE_ATR_TLP_TYPE_MEM;
+       writel(val, table + PCIE_ATR_TRSL_PARAM_OFFSET);
+
+       return 0;
+}
+
+static int mtk_pcie_startup_port(struct udevice *dev)
+{
+       struct mtk_pcie *pcie = dev_get_priv(dev);
+       struct udevice *ctlr = pci_get_controller(dev);
+       struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+       u32 val;
+       int i, err;
+
+       /* Set as RC mode */
+       val = readl(pcie->base + PCIE_SETTING_REG);
+       val |= PCIE_RC_MODE;
+       writel(val, pcie->base + PCIE_SETTING_REG);
+
+       /* setup RC BARs */
+       writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
+              pcie->base + PCI_BASE_ADDRESS_0);
+       writel(0x0, pcie->base + PCI_BASE_ADDRESS_1);
+
+       /* setup interrupt pins */
+       clrsetbits_le32(pcie->base + PCI_INTERRUPT_LINE,
+                       0xff00, 0x100);
+
+       /* setup bus numbers */
+       clrsetbits_le32(pcie->base + PCI_PRIMARY_BUS,
+                       0xffffff, 0x00ff0100);
+
+       /* setup command register */
+       clrsetbits_le32(pcie->base + PCI_PRIMARY_BUS,
+                       0xffff,
+                       PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+                       PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
+
+       /* Set class code */
+       val = readl(pcie->base + PCIE_PCI_IDS_1);
+       val &= ~GENMASK(31, 8);
+       val |= PCI_CLASS(PCI_CLASS_BRIDGE_PCI << 8);
+       writel(val, pcie->base + PCIE_PCI_IDS_1);
+
+       /* Mask all INTx interrupts */
+       val = readl(pcie->base + PCIE_INT_ENABLE_REG);
+       val &= ~0xFF000000;
+       writel(val, pcie->base + PCIE_INT_ENABLE_REG);
+
+       /* Disable DVFSRC voltage request */
+       val = readl(pcie->base + PCIE_MISC_CTRL_REG);
+       val |= PCIE_DISABLE_DVFSRC_VLT_REQ;
+       writel(val, pcie->base + PCIE_MISC_CTRL_REG);
+
+       /* Assert all reset signals */
+       val = readl(pcie->base + PCIE_RST_CTRL_REG);
+       val |= PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB | PCIE_PE_RSTB;
+       writel(val, pcie->base + PCIE_RST_CTRL_REG);
+
+       /*
+        * Described in PCIe CEM specification sections 2.2 (PERST# Signal)
+        * and 2.2.1 (Initial Power-Up (G3 to S0)).
+        * The deassertion of PERST# should be delayed 100ms (TPVPERL)
+        * for the power and clock to become stable.
+        */
+       mdelay(100);
+
+       /* De-assert reset signals */
+       val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB);
+       writel(val, pcie->base + PCIE_RST_CTRL_REG);
+
+       mdelay(100);
+
+       /* De-assert PERST# signals */
+       val &= ~(PCIE_PE_RSTB);
+       writel(val, pcie->base + PCIE_RST_CTRL_REG);
+
+       /* 100ms timeout value should be enough for Gen1/2 training */
+       err = readl_poll_timeout(pcie->base + PCIE_LINK_STATUS_REG, val,
+                                !!(val & PCIE_PORT_LINKUP),
+                                100 * 1000);
+       if (err) {
+               printf("no card detected at 0x%08lx\n", (unsigned 
long)pcie->base);
+               return -ETIMEDOUT;
+       }
+       printf("detected a card at 0x%08lx\n", (unsigned long)pcie->base);
+
+       for (i = 0; i < hose->region_count; i++) {
+               struct pci_region *reg = &hose->regions[i];
+
+               if (reg->flags != PCI_REGION_MEM)
+                       continue;
+
+               mtk_pcie_set_trans_table(pcie, reg->bus_start, reg->phys_start,
+                                        reg->size, reg->flags, 0);
+       }
+
+       return 0;
+}
+
+static int mtk_pcie_power_on(struct udevice *dev)
+{
+       struct mtk_pcie *pcie = dev_get_priv(dev);
+       int err;
+
+       pcie->base = dev_remap_addr_name(dev, "pcie-mac");
+       if (!pcie->base)
+               return -ENOENT;
+
+       pcie->priv = dev;
+
+       pcie->use_dedicated_phy  = dev_read_bool(dev, "use-dedicated-phy");
+
+       if (!pcie->use_dedicated_phy) {
+               err = generic_phy_get_by_name(dev, "pcie-phy", &pcie->phy);
+               if (err)
+                       return err;
+       }
+
+       err = clk_get_by_name(dev, "pl_250m", &pcie->pl_250m_ck);
+       if (err)
+               return err;
+
+       err = clk_get_by_name(dev, "tl_26m", &pcie->tl_26m_ck);
+       if (err)
+               return err;
+
+       err = clk_get_by_name(dev, "peri_26m", &pcie->peri_26m_ck);
+       if (err)
+               return err;
+
+       err = clk_get_by_name(dev, "top_133m", &pcie->top_133m_ck);
+       if (err)
+               return err;
+
+       err = generic_phy_init(&pcie->phy);
+       if (err)
+               return err;
+
+       if (!pcie->use_dedicated_phy) {
+               err = generic_phy_power_on(&pcie->phy);
+               if (err)
+                       goto err_phy_on;
+       }
+
+       err = clk_enable(&pcie->pl_250m_ck);
+       if (err)
+               goto err_clk_pl_250m;
+
+       err = clk_enable(&pcie->tl_26m_ck);
+       if (err)
+               goto err_clk_tl_26m;
+
+       err = clk_enable(&pcie->peri_26m_ck);
+       if (err)
+               goto err_clk_peri_26m;
+
+       err = clk_enable(&pcie->top_133m_ck);
+       if (err)
+               goto err_clk_top_133m;
+
+       err = mtk_pcie_startup_port(dev);
+       if (err)
+               goto err_startup;
+
+       return 0;
+
+err_startup:
+err_clk_top_133m:
+       clk_disable(&pcie->top_133m_ck);
+err_clk_peri_26m:
+       clk_disable(&pcie->peri_26m_ck);
+err_clk_tl_26m:
+       clk_disable(&pcie->tl_26m_ck);
+err_clk_pl_250m:
+       clk_disable(&pcie->pl_250m_ck);
+err_phy_on:
+       generic_phy_exit(&pcie->phy);
+
+       return err;
+}
+
+static int mtk_pcie_probe(struct udevice *dev)
+{
+       struct mtk_pcie *pcie = dev_get_priv(dev);
+       int err;
+
+       pcie->priv = dev;
+
+       err = mtk_pcie_power_on(dev);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static const struct udevice_id mtk_pcie_ids[] = {
+       { .compatible = "mediatek,mt8192-pcie" },
+       { }
+};
+
+U_BOOT_DRIVER(pcie_mediatek_gen3) = {
+       .name           = "pcie_mediatek_gen3",
+       .id             = UCLASS_PCI,
+       .of_match       = mtk_pcie_ids,
+       .ops            = &mtk_pcie_ops,
+       .probe          = mtk_pcie_probe,
+       .priv_auto      = sizeof(struct mtk_pcie),
+};
diff --git a/include/dt-bindings/clock/mt7981-clk.h 
b/include/dt-bindings/clock/mt7981-clk.h
index e24c759e4992..1c2781cd765c 100644
--- a/include/dt-bindings/clock/mt7981-clk.h
+++ b/include/dt-bindings/clock/mt7981-clk.h
@@ -226,7 +226,8 @@
 #define CK_INFRA_IPCIE_CK              (54 - INFRACFG_AO_OFFSET)
 #define CK_INFRA_IPCIER_CK             (55 - INFRACFG_AO_OFFSET)
 #define CK_INFRA_IPCIEB_CK             (56 - INFRACFG_AO_OFFSET)
-#define CLK_INFRA_AO_NR_CLK            (57 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_IPCIE_PIPE_CK         (57 - INFRACFG_AO_OFFSET)
+#define CLK_INFRA_AO_NR_CLK            (58 - INFRACFG_AO_OFFSET)
 
 /* APMIXEDSYS */
 
diff --git a/include/dt-bindings/clock/mt7986-clk.h 
b/include/dt-bindings/clock/mt7986-clk.h
index 820f86318316..fdf705921700 100644
--- a/include/dt-bindings/clock/mt7986-clk.h
+++ b/include/dt-bindings/clock/mt7986-clk.h
@@ -205,7 +205,8 @@
 #define CK_INFRA_IPCIE_CK              42
 #define CK_INFRA_IPCIER_CK             43
 #define CK_INFRA_IPCIEB_CK             44
-#define CLK_INFRA_AO_NR_CLK            45
+#define CK_INFRA_IPCIE_PIPE_CK         45
+#define CLK_INFRA_AO_NR_CLK            46
 
 /* APMIXEDSYS */
 
-- 
2.34.1

Reply via email to