]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
pci: pcie-rcar-gen4: Add Renesas R-Car Gen4 DW PCIe controller driver
authorMarek Vasut <marek.vasut+renesas@mailbox.org>
Tue, 17 Jun 2025 08:16:31 +0000 (10:16 +0200)
committerTom Rini <trini@konsulko.com>
Fri, 27 Jun 2025 14:25:56 +0000 (08:25 -0600)
Add R-Car Gen4 PCIe controller support for host mode.

This controller is based on Synopsys DesignWare PCIe. However, this
particular controller has a number of vendor-specific registers, and as
such, requires initialization code, including PHY firmware loading.

The PHY firmware loading is implemented in an entirely generic manner,
by calling a firmware loading script, which the user can configure in
a way they require. This provides the user with flexibility of loading
the PCIe firmware from whichever storage device they need to load it
from.

Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
drivers/pci/Kconfig
drivers/pci/Makefile
drivers/pci/pci-rcar-gen4.c [new file with mode: 0644]
drivers/pci/pcie_dw_common.h

index 409049137cc90eed0a601e615b45d52ff73a91e9..8ffd88c722d91958a9fb58886437e02b8254c987 100644 (file)
@@ -389,6 +389,16 @@ config PCIE_DW_QCOM
          Say Y here if you want to enable DW PCIe controller support on
          Qualcomm SoCs.
 
+config PCI_RCAR_GEN4
+       bool "Renesas R-Car Gen4 PCIe driver"
+       depends on RCAR_GEN4
+       select DM_RESET
+       select DM_GPIO
+       select PCIE_DW_COMMON
+       help
+         Say Y here if you want to enable PCIe controller support on
+         Renesas R-Car Gen4 SoCs.
+
 config PCIE_ROCKCHIP
        bool "Enable Rockchip PCIe driver"
        depends on ARCH_ROCKCHIP
index ba53f5949639ce2ecf2509bba2e357a94926b011..a0420e733ed236bbe99ee40493a924303349f26d 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_PCIE_IMX) += pcie_imx.o
 obj-$(CONFIG_PCI_MVEBU) += pci_mvebu.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
 obj-$(CONFIG_PCI_RCAR_GEN3) += pci-rcar-gen3.o
+obj-$(CONFIG_PCI_RCAR_GEN4) += pci-rcar-gen4.o
 obj-$(CONFIG_SH7751_PCI) +=pci_sh7751.o
 obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o
 obj-$(CONFIG_PCIE_IPROC) += pcie_iproc.o
diff --git a/drivers/pci/pci-rcar-gen4.c b/drivers/pci/pci-rcar-gen4.c
new file mode 100644 (file)
index 0000000..87cd69f
--- /dev/null
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PCIe controller driver for Renesas R-Car Gen4 Series SoCs
+ * Copyright (C) 2025 Marek Vasut <marek.vasut+renesas@mailbox.org>
+ * Based on Linux kernel driver
+ * Copyright (C) 2022-2023 Renesas Electronics Corporation
+ *
+ * The r8a779g0 (R-Car V4H) controller requires a specific firmware to be
+ * provided, to initialize the PHY. Otherwise, the PCIe controller will not
+ * work.
+ */
+
+#include <asm-generic/gpio.h>
+#include <asm/arch/gpio.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <command.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <env.h>
+#include <log.h>
+#include <reset.h>
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+
+#include "pcie_dw_common.h"
+
+/* Renesas-specific */
+/* PCIe Mode Setting Register 0 */
+#define PCIEMSR0                               0x0000
+#define APP_SRIS_MODE                          BIT(6)
+#define DEVICE_TYPE_EP                         0
+#define DEVICE_TYPE_RC                         BIT(4)
+#define BIFUR_MOD_SET_ON                       BIT(0)
+
+/* PCIe Interrupt Status 0 */
+#define PCIEINTSTS0                            0x0084
+
+/* PCIe Interrupt Status 0 Enable */
+#define PCIEINTSTS0EN                          0x0310
+#define MSI_CTRL_INT                           BIT(26)
+#define SMLH_LINK_UP                           BIT(7)
+#define RDLH_LINK_UP                           BIT(6)
+
+/* PCIe DMA Interrupt Status Enable */
+#define PCIEDMAINTSTSEN                                0x0314
+#define PCIEDMAINTSTSEN_INIT                   GENMASK(15, 0)
+
+/* Port Logic Registers 89 */
+#define PRTLGC89                               0x0b70
+
+/* Port Logic Registers 90 */
+#define PRTLGC90                               0x0b74
+
+/* PCIe Reset Control Register 1 */
+#define PCIERSTCTRL1                           0x0014
+#define APP_HOLD_PHY_RST                       BIT(16)
+#define APP_LTSSM_ENABLE                       BIT(0)
+
+/* PCIe Power Management Control */
+#define PCIEPWRMNGCTRL                         0x0070
+#define APP_CLK_REQ_N                          BIT(11)
+#define APP_CLK_PM_EN                          BIT(10)
+
+#define RCAR_NUM_SPEED_CHANGE_RETRIES          10
+#define RCAR_MAX_LINK_SPEED                    4
+
+#define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET      0x1000
+#define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET     0x800
+
+#define RCAR_GEN4_PCIE_FIRMWARE_NAME           "rcar_gen4_pcie.bin"
+#define RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR      0xc000
+
+#define PCIE_T_PVPERL_MS                       100
+
+/**
+ * struct rcar_gen4_pcie - Renesas R-Car Gen4 DW PCIe controller state
+ *
+ * @rcar:              The common PCIe DW structure
+ * @pwr_rst:           The PWR reset of the PCIe core
+ * @core_clk:          The core clock of the PCIe core
+ * @ref_clk:           The reference clock of the PCIe core and possibly bus
+ * @pe_rst:            PERST GPIO
+ * @app_base:          The base address of application register space
+ * @dbi2_base:         The base address of DBI2 register space
+ * @phy_base:          The base address of PHY register space
+ * @max_link_speed:    Maximum PCIe link speed supported by the setup
+ * @num_lanes:         Number of PCIe lanes used by the setup
+ * @firmware:          PHY firmware
+ * @firmware_size:     PHY firmware size in Bytes
+ */
+struct rcar_gen4_pcie {
+       /* Must be first member of the struct */
+       struct                  pcie_dw dw;
+       struct reset_ctl        pwr_rst;
+       struct clk              *core_clk;
+       struct clk              *ref_clk;
+       struct gpio_desc        pe_rst;
+       void                    *app_base;
+       void                    *dbi2_base;
+       void                    *phy_base;
+       u32                     max_link_speed;
+       u32                     num_lanes;
+       u16                     *firmware;
+       u32                     firmware_size;
+};
+
+/* Common */
+static bool rcar_gen4_pcie_link_up(struct rcar_gen4_pcie *rcar)
+{
+       u32 val, mask;
+
+       val = readl(rcar->app_base + PCIEINTSTS0);
+       mask = RDLH_LINK_UP | SMLH_LINK_UP;
+
+       return (val & mask) == mask;
+}
+
+/*
+ * Manually initiate the speed change. Return 0 if change succeeded; otherwise
+ * -ETIMEDOUT.
+ */
+static int rcar_gen4_pcie_speed_change(struct rcar_gen4_pcie *rcar)
+{
+       u32 val;
+       int i;
+
+       clrbits_le32(rcar->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
+                    PORT_LOGIC_SPEED_CHANGE);
+
+       setbits_le32(rcar->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
+                    PORT_LOGIC_SPEED_CHANGE);
+
+       for (i = 0; i < RCAR_NUM_SPEED_CHANGE_RETRIES; i++) {
+               val = readl(rcar->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+               if (!(val & PORT_LOGIC_SPEED_CHANGE))
+                       return 0;
+               mdelay(10);
+       }
+
+       return -ETIMEDOUT;
+}
+
+/*
+ * SoC datasheet suggests checking port logic register bits during firmware
+ * write. If read returns non-zero value, then this function returns -EAGAIN
+ * indicating that the write needs to be done again. If read returns zero,
+ * then return 0 to indicate success.
+ */
+static int rcar_gen4_pcie_reg_test_bit(struct rcar_gen4_pcie *rcar,
+                                      u32 offset, u32 mask)
+{
+       if (readl(rcar->dw.dbi_base + offset) & mask)
+               return -EAGAIN;
+
+       return 0;
+}
+
+static int rcar_gen4_pcie_download_phy_firmware(struct rcar_gen4_pcie *rcar)
+{
+       /* The check_addr values are magical numbers in the datasheet */
+       static const u32 check_addr[] = {
+               0x00101018,
+               0x00101118,
+               0x00101021,
+               0x00101121,
+       };
+       unsigned int i, timeout;
+       u32 data;
+       int ret;
+
+       for (i = 0; i < rcar->firmware_size / 2; i++) {
+               data = rcar->firmware[i];
+               timeout = 100;
+               do {
+                       writel(RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR + i, rcar->dw.dbi_base + PRTLGC89);
+                       writel(data, rcar->dw.dbi_base + PRTLGC90);
+                       if (!rcar_gen4_pcie_reg_test_bit(rcar, PRTLGC89, BIT(30)))
+                               break;
+                       if (!(--timeout))
+                               return -ETIMEDOUT;
+                       udelay(100);
+               } while (1);
+       }
+
+       setbits_le32(rcar->phy_base + 0x0f8, BIT(17));
+
+       for (i = 0; i < ARRAY_SIZE(check_addr); i++) {
+               timeout = 100;
+               do {
+                       writel(check_addr[i], rcar->dw.dbi_base + PRTLGC89);
+                       ret = rcar_gen4_pcie_reg_test_bit(rcar, PRTLGC89, BIT(30));
+                       ret |= rcar_gen4_pcie_reg_test_bit(rcar, PRTLGC90, BIT(0));
+                       if (!ret)
+                               break;
+                       if (!(--timeout))
+                               return -ETIMEDOUT;
+                       udelay(100);
+               } while (1);
+       }
+
+       return ret;
+}
+
+static int rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable)
+{
+       u32 val;
+       int ret;
+
+       if (!enable) {
+               clrbits_le32(rcar->app_base + PCIERSTCTRL1, APP_LTSSM_ENABLE);
+               return 0;
+       }
+
+       setbits_le32(rcar->dw.dbi_base + PCIE_PORT_FORCE,
+                    PORT_FORCE_DO_DESKEW_FOR_SRIS);
+
+       setbits_le32(rcar->app_base + PCIEMSR0, APP_SRIS_MODE);
+
+       /*
+        * The R-Car Gen4 datasheet doesn't describe the PHY registers' name.
+        * But, the initialization procedure describes these offsets. So,
+        * this driver has magical offset numbers.
+        */
+       clrsetbits_le32(rcar->phy_base + 0x700, BIT(28), 0);
+       clrsetbits_le32(rcar->phy_base + 0x700, BIT(20), 0);
+       clrsetbits_le32(rcar->phy_base + 0x700, BIT(12), 0);
+       clrsetbits_le32(rcar->phy_base + 0x700, BIT(4), 0);
+
+       clrsetbits_le32(rcar->phy_base + 0x148, GENMASK(23, 22), BIT(22));
+       clrsetbits_le32(rcar->phy_base + 0x148, GENMASK(18, 16), GENMASK(17, 16));
+       clrsetbits_le32(rcar->phy_base + 0x148, GENMASK(7, 6), BIT(6));
+       clrsetbits_le32(rcar->phy_base + 0x148, GENMASK(2, 0), GENMASK(11, 0));
+       clrsetbits_le32(rcar->phy_base + 0x1d4, GENMASK(16, 15), GENMASK(16, 15));
+       clrsetbits_le32(rcar->phy_base + 0x514, BIT(26), BIT(26));
+       clrsetbits_le32(rcar->phy_base + 0x0f8, BIT(16), 0);
+       clrsetbits_le32(rcar->phy_base + 0x0f8, BIT(19), BIT(19));
+
+       clrbits_le32(rcar->app_base + PCIERSTCTRL1, APP_HOLD_PHY_RST);
+
+       ret = readl_poll_timeout(rcar->phy_base + 0x0f8, val, !(val & BIT(18)), 10000);
+       if (ret < 0)
+               return ret;
+
+       ret = rcar_gen4_pcie_download_phy_firmware(rcar);
+       if (ret)
+               return ret;
+
+       setbits_le32(rcar->app_base + PCIERSTCTRL1, APP_LTSSM_ENABLE);
+
+       return 0;
+}
+
+/*
+ * Enable LTSSM of this controller and manually initiate the speed change.
+ * Always return 0.
+ */
+static int rcar_gen4_pcie_start_link(struct rcar_gen4_pcie *rcar)
+{
+       int i, ret;
+
+       ret = rcar_gen4_pcie_ltssm_control(rcar, true);
+       if (ret)
+               return ret;
+
+       /*
+        * Require direct speed change with retrying here if the max_link_speed
+        * is PCIe Gen2 or higher.
+        */
+       if (rcar->max_link_speed == LINK_SPEED_GEN_1)
+               return 0;
+
+       for (i = 0; i < RCAR_MAX_LINK_SPEED; i++) {
+               /* It may not be connected in EP mode yet. So, break the loop */
+               if (rcar_gen4_pcie_speed_change(rcar))
+                       break;
+       }
+
+       return 0;
+}
+
+static void rcar_gen4_pcie_additional_common_init(struct rcar_gen4_pcie *rcar)
+{
+       clrsetbits_le32(rcar->dw.dbi_base + PCIE_PORT_LANE_SKEW,
+                       PORT_LANE_SKEW_INSERT_MASK,
+                       (rcar->num_lanes < 4) ? BIT(6) : 0);
+
+       setbits_le32(rcar->app_base + PCIEPWRMNGCTRL,
+                    APP_CLK_REQ_N | APP_CLK_PM_EN);
+}
+
+static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
+{
+       int ret;
+
+       ret = clk_prepare_enable(rcar->core_clk);
+       if (ret)
+               return ret;
+
+       ret = reset_assert(&rcar->pwr_rst);
+       if (ret)
+               goto err_unprepare;
+
+       setbits_le32(rcar->app_base + PCIEMSR0,
+                    DEVICE_TYPE_RC |
+                    ((rcar->num_lanes < 4) ? BIFUR_MOD_SET_ON : 0));
+
+       ret = reset_deassert(&rcar->pwr_rst);
+       if (ret)
+               goto err_unprepare;
+
+       rcar_gen4_pcie_additional_common_init(rcar);
+
+       return 0;
+
+err_unprepare:
+       clk_disable_unprepare(rcar->core_clk);
+
+       return ret;
+}
+
+/* Host mode */
+static int rcar_gen4_pcie_host_init(struct udevice *dev)
+{
+       struct rcar_gen4_pcie *rcar = dev_get_priv(dev);
+       int ret;
+
+       dm_gpio_set_value(&rcar->pe_rst, 1);
+
+       ret = rcar_gen4_pcie_common_init(rcar);
+       if (ret)
+               return ret;
+
+       /*
+        * According to the section 3.5.7.2 "RC Mode" in DWC PCIe Dual Mode
+        * Rev.5.20a and 3.5.6.1 "RC mode" in DWC PCIe RC databook v5.20a, we
+        * should disable two BARs to avoid unnecessary memory assignment
+        * during device enumeration.
+        */
+       writel(0x0, rcar->dbi2_base + PCI_BASE_ADDRESS_0);
+       writel(0x0, rcar->dbi2_base + PCI_BASE_ADDRESS_1);
+
+       /* Disable MSI interrupt signal */
+       clrbits_le32(rcar->app_base + PCIEINTSTS0EN, MSI_CTRL_INT);
+
+       mdelay(PCIE_T_PVPERL_MS);       /* pe_rst requires 100msec delay */
+
+       dm_gpio_set_value(&rcar->pe_rst, 0);
+
+       return 0;
+}
+
+static int rcar_gen4_pcie_load_firmware(struct rcar_gen4_pcie *rcar)
+{
+       ulong addr, size;
+       int ret;
+
+       /*
+        * Run user specified firmware loading script, which loads the
+        * firmware from whichever location the user decides it should
+        * load the firmware from, by whatever means the user decides.
+        */
+       ret = run_command_list("run renesas_rcar_gen4_load_firmware", -1, 0);
+       if (ret) {
+               printf("Firmware loading script 'renesas_rcar_gen4_load_firmware' not defined or failed.\n");
+               goto fail;
+       }
+
+       /* Find out where the firmware got loaded and how long it is. */
+       addr = env_get_hex("renesas_rcar_gen4_load_firmware_addr", 0);
+       size = env_get_hex("renesas_rcar_gen4_load_firmware_size", 0);
+
+       /*
+        * Clear the variables set by the firmware loading script, as
+        * their content would become stale once this function exits.
+        */
+       env_set("renesas_rcar_gen4_load_firmware_addr", NULL);
+       env_set("renesas_rcar_gen4_load_firmware_size", NULL);
+
+       if (!addr || !size) {
+               printf("Firmware address (%lx) or size (%lx) are invalid.\n", addr, size);
+               goto fail;
+       }
+
+       /* Create local copy of the loaded firmware. */
+       rcar->firmware = (u16 *)memdup((void *)addr, size);
+       if (!rcar->firmware)
+               return -ENOMEM;
+
+       rcar->firmware_size = size;
+
+       return 0;
+
+fail:
+       printf("Define 'renesas_rcar_gen4_load_firmware' script which loads the R-Car\n"
+              "Gen4 PCIe controller firmware from storage into memory and sets these\n"
+              "two environment variables:\n"
+              "  renesas_rcar_gen4_load_firmware_addr ... address of firmware in memory\n"
+              "  renesas_rcar_gen4_load_firmware_size ... length of firmware in bytes\n"
+              "\n"
+              "Example:\n"
+              "  => env set renesas_rcar_gen4_load_firmware 'env set renesas_rcar_gen4_load_firmware_addr 0x54000000 && load mmc 0:1 ${renesas_rcar_gen4_load_firmware_addr} lib/firmware/rcar_gen4_pcie.bin && env set renesas_rcar_gen4_load_firmware_size ${filesize}'\n"
+              );
+       return -EINVAL;
+}
+
+/**
+ * rcar_gen4_pcie_probe() - Probe the PCIe bus for active link
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Probe for an active link on the PCIe bus and configure the controller
+ * to enable this port.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int rcar_gen4_pcie_probe(struct udevice *dev)
+{
+       struct rcar_gen4_pcie *rcar = dev_get_priv(dev);
+       struct udevice *ctlr = pci_get_controller(dev);
+       struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+       int ret;
+
+       ret = rcar_gen4_pcie_load_firmware(rcar);
+       if (ret)
+               return ret;
+
+       rcar->dw.first_busno = dev_seq(dev);
+       rcar->dw.dev = dev;
+
+       ret = reset_get_by_name(dev, "pwr", &rcar->pwr_rst);
+       if (ret)
+               return ret;
+
+       rcar->core_clk = devm_clk_get(dev, "core");
+       if (IS_ERR(rcar->core_clk))
+               return PTR_ERR(rcar->core_clk);
+
+       rcar->ref_clk = devm_clk_get(dev, "ref");
+       if (IS_ERR(rcar->ref_clk))
+               return PTR_ERR(rcar->ref_clk);
+
+       ret = clk_prepare_enable(rcar->ref_clk);
+       if (ret)
+               return ret;
+
+       ret = gpio_request_by_name(dev, "reset-gpios", 0, &rcar->pe_rst,
+                                  GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+       if (ret)
+               return ret;
+
+       ret = rcar_gen4_pcie_host_init(dev);
+       if (ret)
+               return ret;
+
+       pcie_dw_setup_host(&rcar->dw);
+
+       dw_pcie_dbi_write_enable(&rcar->dw, true);
+
+       dw_pcie_link_set_max_link_width(&rcar->dw, rcar->num_lanes);
+
+       ret = rcar_gen4_pcie_start_link(rcar);
+       if (ret)
+               return ret;
+
+       dw_pcie_dbi_write_enable(&rcar->dw, false);
+
+       if (!rcar_gen4_pcie_link_up(rcar)) {
+               printf("PCIE-%d: Link down\n", dev_seq(dev));
+               return -ENODEV;
+       }
+
+       printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev_seq(dev),
+              pcie_dw_get_link_speed(&rcar->dw),
+              pcie_dw_get_link_width(&rcar->dw),
+              hose->first_busno);
+
+       pcie_dw_prog_outbound_atu_unroll(&rcar->dw, PCIE_ATU_REGION_INDEX0,
+                                        PCIE_ATU_TYPE_MEM,
+                                        rcar->dw.mem.phys_start,
+                                        rcar->dw.mem.bus_start, rcar->dw.mem.size);
+
+       return 0;
+}
+
+/**
+ * rcar_gen4_pcie_of_to_plat() - Translate from DT to device state
+ *
+ * @dev: A pointer to the device being operated on
+ *
+ * Translate relevant data from the device tree pertaining to device @dev into
+ * state that the driver will later make use of. This state is stored in the
+ * device's private data structure.
+ *
+ * Return: 0 on success, else -EINVAL
+ */
+static int rcar_gen4_pcie_of_to_plat(struct udevice *dev)
+{
+       struct rcar_gen4_pcie *rcar = dev_get_priv(dev);
+
+       /* Get the controller base address */
+       rcar->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbi");
+       if ((fdt_addr_t)rcar->dw.dbi_base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the config space base address and size */
+       rcar->dw.cfg_base = (void *)dev_read_addr_size_name(dev, "config",
+                                                           &rcar->dw.cfg_size);
+       if ((fdt_addr_t)rcar->dw.cfg_base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the iATU base address and size */
+       rcar->dw.atu_base = (void *)dev_read_addr_name(dev, "atu");
+       if ((fdt_addr_t)rcar->dw.atu_base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the PHY base address and size */
+       rcar->phy_base = (void *)dev_read_addr_name(dev, "phy");
+       if ((fdt_addr_t)rcar->phy_base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the app base address and size */
+       rcar->app_base = (void *)dev_read_addr_name(dev, "app");
+       if ((fdt_addr_t)rcar->app_base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       /* Get the dbi2 base address and size */
+       rcar->dbi2_base = (void *)dev_read_addr_name(dev, "dbi2");
+       if ((fdt_addr_t)rcar->dbi2_base == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       rcar->max_link_speed =
+               clamp(dev_read_u32_default(dev, "max-link-speed",
+                                          LINK_SPEED_GEN_4),
+                     LINK_SPEED_GEN_1, RCAR_MAX_LINK_SPEED);
+
+       rcar->num_lanes = dev_read_u32_default(dev, "num-lanes", 4);
+
+       return 0;
+}
+
+static const struct dm_pci_ops rcar_gen4_pcie_ops = {
+       .read_config    = pcie_dw_read_config,
+       .write_config   = pcie_dw_write_config,
+};
+
+static const struct udevice_id rcar_gen4_pcie_ids[] = {
+       { .compatible = "renesas,rcar-gen4-pcie" },
+       { }
+};
+
+U_BOOT_DRIVER(rcar_gen4_pcie) = {
+       .name           = "rcar_gen4_pcie",
+       .id             = UCLASS_PCI,
+       .of_match       = rcar_gen4_pcie_ids,
+       .ops            = &rcar_gen4_pcie_ops,
+       .of_to_plat     = rcar_gen4_pcie_of_to_plat,
+       .probe          = rcar_gen4_pcie_probe,
+       .priv_auto      = sizeof(struct rcar_gen4_pcie),
+};
index ccd423081eb30169ab970ed500a24a1101fcba84..5fa50f3dc3aed2285854c3b8c222c576ddaf418c 100644 (file)
 #define LINK_SPEED_GEN_1               0x1
 #define LINK_SPEED_GEN_2               0x2
 #define LINK_SPEED_GEN_3               0x3
+#define LINK_SPEED_GEN_4               0x4
 
 /* Synopsys-specific PCIe configuration registers */
+#define PCIE_PORT_FORCE                        0x708
+#define PORT_FORCE_DO_DESKEW_FOR_SRIS  BIT(23)
+
 #define PCIE_PORT_LINK_CONTROL         0x710
 #define PORT_LINK_DLL_LINK_EN          BIT(5)
 #define PORT_LINK_FAST_LINK_MODE       BIT(7)
@@ -78,6 +82,9 @@
 #define PORT_LINK_MODE_4_LANES         PORT_LINK_MODE(0x7)
 #define PORT_LINK_MODE_8_LANES         PORT_LINK_MODE(0xf)
 
+#define PCIE_PORT_LANE_SKEW            0x714
+#define PORT_LANE_SKEW_INSERT_MASK     GENMASK(23, 0)
+
 #define PCIE_LINK_WIDTH_SPEED_CONTROL  0x80C
 #define PORT_LOGIC_N_FTS_MASK          GENMASK(7, 0)
 #define PORT_LOGIC_SPEED_CHANGE                BIT(17)