kernel-5.15/0616-Baikal-M-PCIe-driver-from-SDK-M-4.3.patch

1210 lines
50 KiB
Diff

Subject: [PATCH 616/625] Baikal-M: PCIe driver from SDK-M 4.3
Improvements:
* Adjusted the driver so it can built as a module. Hardware
initialization takes about 60 seconds on MBM1.0 board, and
the screen is blank during that time. When built as a module
probing runs concurrently with other boot activities (unless
booting from a PCIe device)
* Avoid loading the driver on boards with incompatible firmware
(from SDK-M 4.4) since it causes the kernel panic during probe:
[ 9.317236] SError Interrupt on CPU4, code 0xbf000002 -- SError
[ 9.317239] CPU: 4 PID: 899 Comm: systemd-udevd Not tainted 5.4.80-std-def-alt1 #1
[ 9.317241] Hardware name: Baikal Electronics Baikal-M mitx board (DT)
[ 9.317243] pstate: 20400085 (nzCv daIf +PAN -UAO)
[ 9.317246] pc : regmap_mmio_read32le+0x28/0x60
[ 9.317247] lr : regmap_mmio_read+0x48/0x70
[ 9.317249] sp : ffff800011ca3750
[ 9.317251] x29: ffff800011ca3750 x28: ffff800008e09258
[ 9.317254] x27: 0000000000000028 x26: ffff800008e07040
[ 9.317257] x25: ffff00097170c1c0 x24: ffff800008e08420
[ 9.317260] x23: ffff800011ca3874 x22: 00000000000500e8
[ 9.317262] x21: ffff800011ca3874 x20: ffff0009727d5980
[ 9.317265] x19: 00000000000500e8 x18: 0000000000000001
[ 9.317268] x17: 0000000000000000 x16: ffff800011ca37f4
[ 9.317270] x15: ffff00097170c6d8 x14: ffffffffffffffff
[ 9.317273] x13: ffff000974e747c0 x12: 0000000000000018
[ 9.317276] x11: 0101010101010101 x10: 7f7f7f7f7f7f7f7f
[ 9.317279] x9 : fefefefeff736472 x8 : 7f7f7f7f7f7f7f7f
[ 9.317281] x7 : 64712c2f6468626f x6 : ffff0009727d568c
[ 9.317284] x5 : ffff000972eee168 x4 : 0000000000000000
[ 9.317286] x3 : ffff800010813c38 x2 : ffff800010814100
[ 9.317289] x1 : 00000000000500e8 x0 : 0000000000000000
[ 9.317292] Kernel panic - not syncing: Asynchronous SError Interrupt
[ 9.317294] CPU: 4 PID: 899 Comm: systemd-udevd Not tainted 5.4.80-std-def-alt1 #1
[ 9.317296] Hardware name: Baikal Electronics Baikal-M mitx board (DT)
[ 9.317298] Call trace:
[ 9.317299] dump_backtrace+0x0/0x160
[ 9.317301] show_stack+0x24/0x30
[ 9.317302] dump_stack+0xb4/0x114
[ 9.317304] panic+0x150/0x368
[ 9.317306] nmi_panic+0x94/0x98
[ 9.317307] arm64_serror_panic+0x84/0x90
[ 9.317309] do_serror+0x11c/0x120
[ 9.317310] el1_error+0xbc/0x160
[ 9.317312] regmap_mmio_read32le+0x28/0x60
[ 9.317314] regmap_mmio_read+0x48/0x70
[ 9.317315] _regmap_bus_reg_read+0x38/0x48
[ 9.317317] _regmap_read+0x6c/0x168
[ 9.317319] regmap_read+0x50/0x78
[ 9.317320] baikal_pcie_hw_init_m+0xe4/0x170 [pcie_baikal]
[ 9.317322] baikal_pcie_probe+0x294/0x530 [pcie_baikal]
[ 9.317324] platform_drv_probe+0x58/0xa8
[ 9.317325] really_probe+0xe0/0x330
[ 9.317327] driver_probe_device+0x5c/0xf0
[ 9.317329] device_driver_attach+0x74/0x80
[ 9.317330] __driver_attach+0x64/0xe0
[ 9.317332] bus_for_each_dev+0x80/0xd0
[ 9.317334] driver_attach+0x30/0x40
[ 9.317335] bus_add_driver+0x154/0x1e8
[ 9.317337] driver_register+0x64/0x110
[ 9.317338] __platform_driver_register+0x54/0x60
[ 9.317340] baikal_pcie_driver_init+0x24/0x1000 [pcie_baikal]
[ 9.317342] do_one_initcall+0x50/0x24c
[ 9.317343] do_init_module+0x5c/0x248
[ 9.317345] load_module+0x1e08/0x2258
[ 9.317347] __do_sys_finit_module+0xd0/0xe8
[ 9.317348] __arm64_sys_finit_module+0x28/0x38
[ 9.317350] el0_svc_common.constprop.0+0x74/0x168
[ 9.317352] el0_svc_handler+0x34/0xa0
[ 9.317353] el0_svc+0x8/0x260
[ 9.324036] SMP: stopping secondary CPUs
[ 9.324038] Kernel Offset: disabled
[ 9.324039] CPU features: 0x0002,20006008
[ 9.324041] Memory Limit: none
Note: detection of new firmware is not 100% reliable.
Update for 5.15.28
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -281,6 +281,18 @@ config PCIE_BRCMSTB
Say Y here to enable PCIe host controller support for
Broadcom STB based SoCs, like the Raspberry Pi 4.
+config PCI_BAIKAL
+ tristate "Baikal SoC PCIe controller"
+ default m if ARCH_BAIKAL
+ depends on ARCH_BAIKAL
+ depends on OF && HAS_IOMEM
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIE_DW
+ help
+ Enables support for the PCIe controller in the Baikal SoC. There
+ are three instances of PCIe controller in Baikal-M. Two of the controllers
+ support PCIe 3.0 x4 and the remaining one supports PCIe 3.0 x8.
+
config PCI_HYPERV_INTERFACE
tristate "Hyper-V PCI Interface"
depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index a751553fa0db..85e6ad1954e5 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -24,6 +24,7 @@
obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
obj-$(CONFIG_PCIE_VISCONTI_HOST) += pcie-visconti.o
+obj-$(CONFIG_PCI_BAIKAL) += pcie-baikal.o
# The following drivers are for devices that use the generic ACPI
# pci_root.c driver but don't support standard ECAM config access.
diff --git a/drivers/pci/controller/dwc/pcie-baikal.c b/drivers/pci/controller/dwc/pcie-baikal.c
new file mode 100644
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-baikal.c
@@ -0,0 +1,722 @@
+/*
+ * pcie-baikal - PCIe controller driver for Baikal SoCs
+ *
+ * Copyright (C) 2019 Baikal Electronics JSC
+ * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
+ *
+ * Parts of this file were based on sources as follows:
+ * Copyright (C) 2013-2014 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define DEBUG 1
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/arm-gic-v3.h>
+#include <linux/irqdomain.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/baikal/lcru-pcie.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/resource.h>
+#include <linux/types.h>
+#include <linux/moduleparam.h>
+
+#include "pcie-designware.h"
+#include "pcie-baikal.h"
+
+
+#define PCIE_MSI_ADDR_LO 0x820
+#define PCIE_MSI_ADDR_HI 0x824
+
+
+struct baikal_pcie {
+ struct dw_pcie *pci;
+ int bus_nr;
+ struct regmap *lcru;
+ struct gpio_desc *reset_gpio;
+ char reset_name[32];
+};
+
+#define to_baikal_pcie(x) dev_get_drvdata((x)->dev)
+#define LINK_RETRAIN_TIMEOUT HZ
+
+#define PORT_LINK_FAST_LINK_MODE (1 << 7) /* Fast Link Mode. */
+
+#define PCIE_PHY_RETRIES 1000000
+#define PHY_ALL_LANES 0xF
+#define PHY_LANE0 0x1
+
+/* Baikal-specific registers. */
+#define PCIE_BK_MGMT_SEL_LANE (0xd04) /* Select lane. */
+#define PCIE_BK_MGMT_CTRL (0xd08) /* Control management register. */
+#define PCIE_BK_MGMT_WRITE_DATA (0xd0c) /* Data write register. */
+#define PCIE_BK_MGMT_READ_DATA (0xd10) /* Data read register. */
+
+#define PCIE_MISC_CONTROL_1_OFF (0x8bc) /* to open RO DBI register. */
+#define DBI_RO_RW_EN (1 << 0)
+
+#define PCIE_COHERENCE_CONTROL_3_OFF (0x8e8) /* to set cache coherence register. */
+
+/* PCIE_BK_MGMT_CTRL */
+#define BK_MGMT_CTRL_ADDR_MASK (0xFFFFF) /* bits [20:0] */
+#define BK_MGMT_CTRL_READ (0 << 29)
+#define BK_MGMT_CTRL_WRITE (1 << 29)
+#define BK_MGMT_CTRL_DONE (1 << 30)
+#define BK_MGMT_CTRL_BUSY (1 << 31)
+
+#define PCIE_LINK_CAPABILITIES_REG (0x7c) /* Link Capabilities Register. */
+#define PCIE_ROOT_CONTROL_ROOT_CAPABILITIES_REG (0x8c) /* Root Control and Capabilities Register. */
+
+#define PCIE_LINK_CONTROL_LINK_STATUS_REG (0x80) /* Link Control and Status Register. */
+/* LINK_CONTROL_LINK_STATUS_REG */
+#define PCIE_CAP_LINK_SPEED_SHIFT 16
+#define PCIE_CAP_LINK_SPEED_MASK 0xF0000
+#define PCIE_CAP_LINK_SPEED_GEN1 0x1
+#define PCIE_CAP_LINK_SPEED_GEN2 0x2
+#define PCIE_CAP_LINK_SPEED_GEN3 0x3
+#define PCIE_STA_LINK_TRAINING 0x8000000
+#define PCIE_STA_LINK_WIDTH_MASK 0x3f00000
+#define PCIE_STA_LINK_WIDTH_SHIFT (20)
+
+#define PCIE_LINK_CONTROL2_LINK_STATUS2_REG (0xa0) /* Link Control 2 and Status 2 Register. */
+/* PCIE_LINK_CONTROL2_LINK_STATUS2 */
+#define PCIE_LINK_CONTROL2_GEN_MASK (0xF)
+#define PCIE_LINK_CONTROL2_GEN1 (1)
+#define PCIE_LINK_CONTROL2_GEN2 (2)
+#define PCIE_LINK_CONTROL2_GEN3 (3)
+
+static inline int dw_pcie_link_is_training(struct dw_pcie *pci)
+{
+ int reg = dw_pcie_readl_dbi(pci, PCIE_LINK_CONTROL_LINK_STATUS_REG);
+ return reg & PCIE_STA_LINK_TRAINING;
+}
+
+static void dw_wait_pcie_link_training_done(struct dw_pcie *pci)
+{
+ unsigned long start_jiffies = jiffies;
+ while (dw_pcie_link_is_training(pci)) {
+ if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) {
+ pr_err("%s: link retrained for too long, timeout occured\n", __func__);
+ break;
+ }
+ udelay(100);
+ }
+}
+
+static int dw_report_link_performance(struct dw_pcie *pci)
+{
+ int reg = dw_pcie_readl_dbi(pci, PCIE_LINK_CONTROL_LINK_STATUS_REG);
+ int speed = (reg & PCIE_CAP_LINK_SPEED_MASK) >> PCIE_CAP_LINK_SPEED_SHIFT;
+ int width = (reg & PCIE_STA_LINK_WIDTH_MASK) >> PCIE_STA_LINK_WIDTH_SHIFT;
+ dev_info(pci->dev, "Link Status is GEN%d, x%d\n", speed, width);
+ return speed;
+}
+
+static inline void dw_pcie_link_retrain(struct dw_pcie *pci, int target_speed)
+{
+ int reg;
+ unsigned long start_jiffies;
+
+ // In case link is already training wait for training to complete
+ dw_wait_pcie_link_training_done(pci);
+
+ // Set desired speed
+ reg = dw_pcie_readl_dbi(pci, PCIE_LINK_CONTROL2_LINK_STATUS2_REG);
+ reg &= ~PCIE_LINK_CONTROL2_GEN_MASK;
+ reg |= target_speed;
+ dw_pcie_writel_dbi(pci, PCIE_LINK_CONTROL2_LINK_STATUS2_REG, reg);
+
+ // Set Retrain Link bit
+ reg = dw_pcie_readl_dbi(pci, PCIE_LINK_CONTROL_LINK_STATUS_REG);
+ reg |= PCI_EXP_LNKCTL_RL;
+ dw_pcie_writel_dbi(pci, PCIE_LINK_CONTROL_LINK_STATUS_REG, reg);
+
+ /* Wait for link training begin */
+ start_jiffies = jiffies;
+ while (!dw_pcie_link_is_training(pci)) {
+ if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) {
+ pr_err("%s: link retrained for too long, timeout occured\n", __func__);
+ break;
+ }
+ udelay(100);
+ }
+
+ /* Wait for link training end */
+ dw_wait_pcie_link_training_done(pci);
+
+ if(dw_pcie_wait_for_link(pci) == 0) {
+ dw_report_link_performance(pci);
+ }
+}
+
+
+static void baikal_pcie_link_speed_fixup(struct pci_dev *pdev)
+{
+ int reg, speed, width, target_speed;
+ struct pcie_port *pp = pdev->bus->sysdata;
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+ reg = dw_pcie_readl_dbi(pci, PCIE_LINK_CAPABILITIES_REG);
+ speed = reg & PCI_EXP_LNKCAP_SLS;
+ if (speed > PCI_EXP_LNKCAP_SLS_2_5GB) {
+ pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &reg);
+ speed = reg & PCI_EXP_LNKCAP_SLS;
+ width = (reg & PCI_EXP_LNKCAP_MLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
+ dev_info(&pdev->dev, "Link Capability is GEN%d, x%d\n", speed, width);
+ if (speed > PCI_EXP_LNKCAP_SLS_2_5GB) {
+ target_speed = speed;
+ if (dw_report_link_performance(pci) < target_speed) {
+ dev_info(&pdev->dev, "retrain link to GEN%d\n", target_speed);
+ dw_pcie_link_retrain(pci, target_speed);
+ dw_report_link_performance(pci);
+ return;
+ }
+ }
+ }
+}
+
+static void baikal_pcie_retrain_links(const struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+ struct pci_bus *child;
+
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ baikal_pcie_link_speed_fixup(dev);
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ child = dev->subordinate;
+ if (child)
+ baikal_pcie_retrain_links(child);
+ }
+}
+
+static int baikal_pcie_link_up(struct dw_pcie *pci)
+{
+ struct baikal_pcie *rc = to_baikal_pcie(pci);
+ uint32_t misc_reg;
+ uint32_t class_reg;
+ u32 lcru_reg, reg;
+
+ // Set class
+ lcru_reg = baikal_pcie_lcru_readl(rc->lcru, BAIKAL_LCRU_PCIE_GEN_CTL(rc->bus_nr));
+ baikal_pcie_lcru_writel(rc->lcru, BAIKAL_LCRU_PCIE_GEN_CTL(rc->bus_nr), lcru_reg & (~BAIKAL_PCIE_DBI2_MODE));
+
+ misc_reg = dw_pcie_readl_dbi(pci, PCIE_MISC_CONTROL_1_OFF);
+ misc_reg |= DBI_RO_RW_EN;
+
+ dw_pcie_writel_dbi(pci, PCIE_MISC_CONTROL_1_OFF, misc_reg);
+ class_reg = dw_pcie_readl_dbi(pci, PCI_CLASS_REVISION);
+
+ class_reg = (0x604 << 16) | (class_reg & 0xff); // class PCI_PCI_BRIDGE=0x604
+ dw_pcie_writel_dbi(pci, PCI_CLASS_REVISION, class_reg);
+
+ misc_reg &= ~DBI_RO_RW_EN;
+ dw_pcie_writel_dbi(pci, PCIE_MISC_CONTROL_1_OFF, misc_reg);
+ baikal_pcie_lcru_writel(rc->lcru, BAIKAL_LCRU_PCIE_GEN_CTL(rc->bus_nr), lcru_reg);
+ reg = baikal_pcie_lcru_readl(rc->lcru, BAIKAL_LCRU_PCIE_STATUS(rc->bus_nr));
+ return !!(reg & (BAIKAL_PCIE_RDLH_LINKUP | BAIKAL_PCIE_SMLH_LINKUP));
+}
+
+static void baikal_pcie_cease_link(struct baikal_pcie *rc)
+{
+ u32 reg;
+ reg = baikal_pcie_lcru_readl(rc->lcru, BAIKAL_LCRU_PCIE_GEN_CTL(rc->bus_nr));
+ reg &= ~BAIKAL_PCIE_LTSSM_ENABLE;
+ baikal_pcie_lcru_writel(rc->lcru, BAIKAL_LCRU_PCIE_GEN_CTL(rc->bus_nr), reg);
+}
+
+static int baikal_pcie_establish_link(struct baikal_pcie *rc)
+{
+ struct dw_pcie *pci = rc->pci;
+ struct device *dev = pci->dev;
+ u32 reg;
+ int ok;
+
+ if (baikal_pcie_link_up(pci)) {
+ dev_err(dev, "link is already up\n");
+ return 0;
+ }
+
+ reg = baikal_pcie_lcru_readl(rc->lcru, BAIKAL_LCRU_PCIE_GEN_CTL(rc->bus_nr));
+ reg |= BAIKAL_PCIE_LTSSM_ENABLE;
+ baikal_pcie_lcru_writel(rc->lcru, BAIKAL_LCRU_PCIE_GEN_CTL(rc->bus_nr), reg);
+
+ ok = dw_pcie_wait_for_link(pci);
+ if(ok == 0) {
+ dw_report_link_performance(pci);
+ }
+ return ok;
+}
+
+static int baikal_pcie_host_init(struct pcie_port *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct baikal_pcie *baikal_pcie = to_baikal_pcie(pci);
+
+ dw_pcie_setup_rc(pp);
+ baikal_pcie_establish_link(baikal_pcie);
+ return 0;
+}
+
+static int baikal_pcie_msi_host_init(struct pcie_port *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct device *dev = pci->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *msi_node;
+
+ /*
+ * The MSI domain is set by the generic of_msi_configure(). This
+ * .msi_host_init() function keeps us from doing the default MSI
+ * domain setup in dw_pcie_host_init() and also enforces the
+ * requirement that "msi-parent" exists.
+ */
+ msi_node = of_parse_phandle(np, "msi-parent", 0);
+ if (!msi_node) {
+ dev_warn(dev, "failed to find msi-parent\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct dw_pcie_host_ops baikal_pcie_host_ops = {
+ .host_init = baikal_pcie_host_init,
+ .msi_host_init = baikal_pcie_msi_host_init,
+};
+
+static const struct dw_pcie_ops baikal_pcie_ops = {
+ .link_up = baikal_pcie_link_up,
+};
+
+static int baikal_pcie_get_msi(struct baikal_pcie *rc,
+ struct device_node *msi_node,
+ u64 *msi_addr)
+{
+ struct dw_pcie *pci = rc->pci;
+ struct device *dev = pci->dev;
+ int ret;
+ struct resource res;
+ memset(&res, 0, sizeof(res));
+
+ /*
+ * Check if 'msi-parent' points to ARM GICv3 ITS, which is the only
+ * supported MSI controller.
+ */
+ if (!of_device_is_compatible(msi_node, "arm,gic-v3-its")) {
+ dev_err(dev, "unable to find compatible MSI controller\n");
+ return -ENODEV;
+ }
+
+ /* derive GITS_TRANSLATER address from GICv3 */
+ ret = of_address_to_resource(msi_node, 0, &res);
+ if (ret < 0) {
+ dev_err(dev, "unable to obtain MSI controller resources\n");
+ return ret;
+ }
+
+ *msi_addr = res.start + GITS_TRANSLATER;
+ return 0;
+}
+
+static int baikal_pcie_msi_steer(struct baikal_pcie *rc,
+ struct device_node *msi_node)
+{
+ struct dw_pcie *pci = rc->pci;
+ struct device *dev = pci->dev;
+ int ret;
+ u64 msi_addr;
+
+ ret = baikal_pcie_get_msi(rc, msi_node, &msi_addr);
+ if (ret < 0) {
+ dev_err(dev, "MSI steering failed\n");
+ return ret;
+ }
+
+ /* Program the msi_data */
+ dw_pcie_write(pci->dbi_base + PCIE_MSI_ADDR_LO, 4,
+ lower_32_bits(msi_addr));
+ dw_pcie_write(pci->dbi_base + PCIE_MSI_ADDR_HI, 4,
+ upper_32_bits(msi_addr));
+
+ return 0;
+}
+
+int baikal_msi_init(struct baikal_pcie *rc, struct device_node *node)
+{
+ if (!of_find_property(node, "msi-controller", NULL)) {
+ pr_err("%s: couldn't find msi-controller property in FDT\n", __func__);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int baikal_pcie_msi_enable(struct baikal_pcie *rc)
+{
+ struct dw_pcie *pci = rc->pci;
+ struct device *dev = pci->dev;
+ struct device_node *msi_node;
+ int ret;
+
+ /*
+ * The "msi-parent" phandle needs to exist
+ * for us to obtain the MSI node.
+ */
+
+ msi_node = of_parse_phandle(dev->of_node, "msi-parent", 0);
+ if (!msi_node) {
+ dev_err(dev, "failed to read msi-parent from FDT\n");
+ return -ENODEV;
+ }
+
+ ret = baikal_pcie_msi_steer(rc, msi_node);
+ if (ret)
+ goto out_put_node;
+
+out_put_node:
+ of_node_put(msi_node);
+ return ret;
+}
+
+static irqreturn_t baikal_pcie_handle_error_irq(struct baikal_pcie *rc)
+{
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t baikal_pcie_err_irq_handler(int irq, void *priv)
+{
+ struct baikal_pcie *rc = priv;
+
+ return baikal_pcie_handle_error_irq(rc);
+}
+
+static int baikal_add_pcie_port(struct baikal_pcie *rc,
+ struct platform_device *pdev)
+{
+ struct dw_pcie *pci = rc->pci;
+ struct pcie_port *pp = &pci->pp;
+ struct resource *res;
+ int irq;
+ int ret;
+
+ pci->dev = &pdev->dev;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+ if (res) {
+ pci->dbi_base = devm_ioremap_resource(pci->dev, res);
+ if (IS_ERR(pci->dbi_base)) {
+ dev_err(pci->dev, "error with ioremap\n");
+ return PTR_ERR(pci->dbi_base);
+ }
+ } else {
+ dev_err(pci->dev, "missing *dbi* reg space\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(pci->dev, "missing IRQ resource: %d\n", irq);
+ return irq;
+ }
+
+ /* TODO enable it later */
+ ret = request_irq(irq, baikal_pcie_err_irq_handler, IRQF_SHARED,
+ "baikal-pcie-error-irq", rc);
+ if (ret < 0) {
+ dev_err(pci->dev, "failed to request error IRQ %d\n",
+ irq);
+ return ret;
+ }
+ /* end TODO */
+
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ ret = baikal_pcie_msi_enable(rc);
+ if (ret) {
+ dev_err(pci->dev, "failed to initialize MSI\n");
+ return ret;
+ }
+ }
+
+ pp->ops = &baikal_pcie_host_ops;
+
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+ dev_err(pci->dev, "failed to initialize host\n");
+ return ret;
+ }
+ baikal_pcie_retrain_links(pp->bridge->bus);
+
+ return 0;
+}
+
+static int baikal_pcie_hw_init_m(struct baikal_pcie *rc)
+{
+ u32 reg;
+
+ // TODO add PHY configuration if needed
+
+ /* Deassert PHY reset */
+ reg = baikal_pcie_lcru_readl(rc->lcru, BAIKAL_LCRU_PCIE_RESET(rc->bus_nr));
+ reg &= ~BAIKAL_PCIE_PHY_RESET;
+ baikal_pcie_lcru_writel(rc->lcru, BAIKAL_LCRU_PCIE_RESET(rc->bus_nr), reg);
+
+ // TODO timeout?
+
+ /* Enable access to the PHY registers */
+ reg = baikal_pcie_lcru_readl(rc->lcru, BAIKAL_LCRU_PCIE_GEN_CTL(rc->bus_nr));
+ reg |= (BAIKAL_PCIE_PHY_MGMT_ENABLE | BAIKAL_PCIE_DBI2_MODE);
+ baikal_pcie_lcru_writel(rc->lcru, BAIKAL_LCRU_PCIE_GEN_CTL(rc->bus_nr), reg);
+
+ // TODO timeout?
+
+ /* Clear all software controlled resets of the controller */
+ reg = baikal_pcie_lcru_readl(rc->lcru, BAIKAL_LCRU_PCIE_RESET(rc->bus_nr));
+ reg &= ~(BAIKAL_PCIE_ADB_PWRDWN | BAIKAL_PCIE_HOT_RESET |
+ BAIKAL_PCIE_NONSTICKY_RST | BAIKAL_PCIE_STICKY_RST |
+ BAIKAL_PCIE_PWR_RST | BAIKAL_PCIE_CORE_RST | BAIKAL_PCIE_PIPE_RESET);
+ baikal_pcie_lcru_writel(rc->lcru, BAIKAL_LCRU_PCIE_RESET(rc->bus_nr), reg);
+
+ // TODO timeout?
+
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+
+ /* Set up the MSI translation mechanism: */
+
+ /* First, set MSI_AWUSER to 0 */
+ reg = baikal_pcie_lcru_readl(rc->lcru, BAIKAL_LCRU_PCIE_MSI_TRANS_CTL0);
+ reg &= ~BAIKAL_PCIE_MSI_AWUSER_MASK;
+ reg |= (0 << BAIKAL_PCIE_MSI_AWUSER_SHIFT);
+ baikal_pcie_lcru_writel(rc->lcru, BAIKAL_LCRU_PCIE_MSI_TRANS_CTL0, reg);
+
+ // TODO timeout?
+
+ /* Second, enable MSI, the RC number for all RC is 0*/
+ reg = baikal_pcie_lcru_readl(rc->lcru, BAIKAL_LCRU_PCIE_MSI_TRANS_CTL2);
+ reg |= BAIKAL_PCIE_MSI_TRANS_EN(rc->bus_nr);
+ reg &= ~BAIKAL_PCIE_MSI_RCNUM_MASK(rc->bus_nr);
+ baikal_pcie_lcru_writel(rc->lcru, BAIKAL_LCRU_PCIE_MSI_TRANS_CTL2, reg);
+
+ }
+
+ return 0;
+
+}
+
+static const struct of_device_id of_baikal_pcie_match[] = {
+ {
+ .compatible = "baikal,pcie-m",
+ .data = baikal_pcie_hw_init_m,
+ },
+ {},
+};
+
+/* XXX: this driver is incompatible with firmware from SDK-M version 4.4
+ * (and possibly later versions). Unfortunately the vendor does not provide
+ * any reasonable way to find out the firmware version. Hence this guess:
+ * if the "/soc" node exists - it's SDK-M 4.4
+ * otherwise it's SDK-M 4.3 (hopefully)
+ */
+static int guess_incompat_firmware(void)
+{
+ int ret = 0;
+ struct device_node *np = NULL;
+ np = of_find_node_by_path("/soc");
+ if (np) {
+ ret = 1;
+ of_node_put(np);
+ }
+ return ret;
+}
+
+static int baikal_pcie_probe(struct platform_device *pdev)
+{
+ struct dw_pcie *pci;
+ struct baikal_pcie *pcie;
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id;
+ int err;
+ int (*hw_init_fn)(struct baikal_pcie *);
+ u32 index[2];
+ enum of_gpio_flags flags;
+ int reset_gpio;
+ pr_info("%s: ENTER\n", __func__);
+
+ if (guess_incompat_firmware()) {
+ dev_err(dev, "detected incompatible firmware, bailing out\n");
+ return -ENODEV;
+ }
+
+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie) {
+ dev_err(dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
+ if (!pci) {
+ dev_err(dev, "failed to allocate memory [2]\n");
+ return -ENOMEM;
+ }
+ pci->dev = dev;
+ pci->ops = &baikal_pcie_ops;
+
+ pcie->pci = pci;
+
+ pcie->lcru = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "baikal,pcie-lcru");
+ if (IS_ERR(pcie->lcru)) {
+ dev_err(dev, "No LCRU phandle specified\n");
+ pcie->lcru = NULL;
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32_array(dev->of_node,
+ "baikal,pcie-lcru", index, 2)) {
+ dev_err(dev, "failed to read LCRU\n");
+ pcie->lcru = NULL;
+ return -EINVAL;
+ }
+ pcie->bus_nr = index[1];
+
+ of_id = of_match_device(of_baikal_pcie_match, dev);
+ if (!of_id || !of_id->data) {
+ dev_err(dev, "device can't be handled by pcie-baikal\n");
+ return -EINVAL;
+ }
+ hw_init_fn = of_id->data;
+
+ pm_runtime_enable(dev);
+ err = pm_runtime_get_sync(dev);
+ if (err < 0) {
+ dev_err(dev, "pm_runtime_get_sync failed\n");
+ goto err_pm_disable;
+ }
+
+
+ baikal_pcie_cease_link(pcie);
+
+ /* LINK DISABLED */
+ reset_gpio = of_get_named_gpio_flags(dev->of_node, "reset-gpios", 0, &flags);
+ if (reset_gpio != -EPROBE_DEFER && gpio_is_valid(reset_gpio)) {
+ unsigned long gpio_flags;
+
+ snprintf(pcie->reset_name, 32, "pcie%d-reset", pcie->bus_nr);
+ if (flags & OF_GPIO_ACTIVE_LOW)
+ gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_LOW;
+ else
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
+ err = devm_gpio_request_one(dev, reset_gpio, gpio_flags,
+ pcie->reset_name);
+ if (err) {
+ dev_err(dev, "request GPIO failed (%d)\n", err);
+ goto err_pm_disable;
+ }
+ pcie->reset_gpio = gpio_to_desc(reset_gpio);
+
+ udelay(100);
+//vvv: do it now or later in baikal_pcie_host_init()?
+ gpiod_set_value_cansleep(pcie->reset_gpio, 0);
+ }
+
+ err = hw_init_fn(pcie);
+ if (err) {
+ //dev_info(dev, "PCIe link down\n"); // TODO PHY not initialized!
+ err = 0;
+ goto err_pm_put;
+ }
+ /* PHY INITIALIZED */
+ platform_set_drvdata(pdev, pcie);
+
+ err = baikal_add_pcie_port(pcie, pdev);
+ if (err < 0)
+ //goto err_gpio; TODO
+ goto err_pm_put;
+
+ return 0;
+
+err_pm_put:
+ pm_runtime_put(dev);
+
+err_pm_disable:
+ pm_runtime_disable(dev);
+
+err_phy:
+ return err;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int baikal_pcie_suspend(struct device *dev)
+{
+ struct baikal_pcie *rc = dev_get_drvdata(dev);
+ struct dw_pcie *pci = rc->pci;
+ u32 val;
+
+ /* clear MSE */
+ val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
+ val &= ~PCI_COMMAND_MEMORY;
+ dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
+
+ return 0;
+}
+
+static int baikal_pcie_resume(struct device *dev)
+{
+ struct baikal_pcie *rc = dev_get_drvdata(dev);
+ struct dw_pcie *pci = rc->pci;
+ u32 val;
+
+ /* set MSE */
+ val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
+ val |= PCI_COMMAND_MEMORY;
+ dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
+
+ return 0;
+}
+
+static int baikal_pcie_suspend_noirq(struct device *dev)
+{
+ return 0;
+}
+
+static int baikal_pcie_resume_noirq(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops baikal_pcie_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(baikal_pcie_suspend, baikal_pcie_resume)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(baikal_pcie_suspend_noirq,
+ baikal_pcie_resume_noirq)
+};
+
+static struct platform_driver baikal_pcie_driver = {
+ .driver = {
+ .name = "baikal-pcie",
+ .of_match_table = of_baikal_pcie_match,
+ .suppress_bind_attrs = true,
+ .pm = &baikal_pcie_pm_ops,
+ },
+ .probe = baikal_pcie_probe,
+};
+
+MODULE_DEVICE_TABLE(of, of_baikal_pcie_match);
+module_platform_driver(baikal_pcie_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/controller/dwc/pcie-baikal.h b/drivers/pci/controller/dwc/pcie-baikal.h
new file mode 100644
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-baikal.h
@@ -0,0 +1,217 @@
+/*
+ * pcie-baikal - PCIe controller driver for Baikal SoCs
+ *
+ * Copyright (C) 2019 Baikal Electronics JSC
+ * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
+ *
+ * Parts of this file were based on sources as follows:
+ * Copyright (C) 2013-2014 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define PCI_VENDOR_ID_BAIKAL 0x1d39
+
+#define PCIE_GEN2_CTRL_OFF (0x80c) /* Link Width and Speed Change Control Register. */
+
+/* PHY control registers. */
+#define PCIE_PHY_DWC_GLBL_PLL_CFG_0 (0x1c000) /* PLL Global Configuration Register #0 */
+#define PCIE_PHY_DWC_GLBL_PLL_CFG_1 (0x1c001) /* PLL Global Configuration Register #1 */
+#define PCIE_PHY_DWC_GLBL_PLL_CFG_2 (0x1c002) /* PLL Global Configuration Register #2 */
+#define PCIE_PHY_DWC_GLBL_PLL_CFG_3 (0x1c003) /* PLL Global Configuration Register #3 */
+#define PCIE_PHY_DWC_GLBL_PLL_CFG_4 (0x1c004) /* PLL Global Configuration Register #4 */
+#define PCIE_PHY_DWC_GLBL_MISC_CONFIG_0 (0x1c005) /* Global Miscellaneous Configuration #0 */
+#define PCIE_PHY_DWC_GLBL_MISC_CONFIG_1 (0x1c006) /* Global Miscellaneous Configuration #1 */
+#define PCIE_PHY_DWC_SLICE_CFG (0x1c00c) /* Slice Configuration */
+#define PCIE_PHY_DWC_GLBL_REGU_CFG (0x1c00d) /* Global Regulator Configuration */
+#define PCIE_PHY_DWC_GLBL_TERM_CFG (0x1c00e) /* Global Termination Calibration Configuration */
+#define PCIE_PHY_DWC_GLBL_CAL_CFG (0x1c00f) /* Global PLL Calibration Configuration */
+#define PCIE_PHY_DWC_GLBL_RD_SYNC_STATUS (0x1c010) /* Global Read Synchronization Status */
+#define PCIE_PHY_DWC_RX_PWR_CTRL_P0 (0x1c014) /* RX Power Controls in Power State P0 */
+#define PCIE_PHY_DWC_RX_PWR_CTRL_P0S (0x1c015) /* RX Power Controls in Power State P0S */
+#define PCIE_PHY_DWC_RX_PWR_CTRL_P1 (0x1c016) /* RX Power Controls in Power State P1 */
+#define PCIE_PHY_DWC_RX_PWR_CTRL_P2 (0x1c017) /* RX Power Controls in Power State P2 */
+#define PCIE_PHY_DWC_TX_PWR_CTRL_P0_P0S (0x1c018) /* TX Power Controls in Power States P0 and POS */
+#define PCIE_PHY_DWC_TX_PWR_CTRL_P1_P2 (0x1c019) /* TX Power Controls in Power States P1 and P2 */
+#define PCIE_PHY_DWC_GLBL_PWR_CTRL (0x1c01a) /* Global Power State Machine Control Override */
+#define PCIE_PHY_DWC_RX_TXDIR_CTRL_0 (0x1c01d) /* Far-end TX Direction Control Register #0 */
+#define PCIE_PHY_DWC_RX_TXDIR_CTRL_1 (0x1c01e) /* Far-end TX Direction Control Register #1 */
+#define PCIE_PHY_DWC_RX_TXDIR_CTRL_2 (0x1c01f) /* Far-end TX Direction Control Register #2 */
+#define PCIE_PHY_DWC_GLBL_PLL_MONITOR (0x1c020) /* Monitor for SerDes Global to Raw PCS Global Interface */
+#define PCIE_PHY_DWC_GLBL_TERM_MON_1 (0x1c022) /* Monitor for SerDes Global to Raw PCS Global Interface */
+#define PCIE_PHY_DWC_GLBL_SDS_PIN_MON_0 (0x1c023) /* Monitor for Raw PCS Global to SerDes Global to Raw PCS Interface */
+#define PCIE_PHY_DWC_GLBL_SDS_PIN_MON_1 (0x1c024) /* Monitor for Raw PCS Global to SerDes Global to Raw PCS Interface */
+#define PCIE_PHY_DWC_GLBL_PWR_MON_0 (0x1c025) /* Monitor of Global Power State Machine Values */
+#define PCIE_PHY_DWC_GLBL_PWR_MON_1 (0x1c026) /* Monitor of Global Power State Machine Values */
+#define PCIE_PHY_DWC_GLBL_PWR_MON_2 (0x1c027) /* Monitor of Global Power State Machine Values */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_FRAC_BASE (0x1c060) /* Global PLL SSC Fractional Base */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_CYCLES (0x1c061) /* Global PLL SSC Cycles Configuration */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_FMFREQ (0x1c062) /* Global PLL SSC Modulation Frequency */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_FREF (0x1c063) /* Global PLL SSC Reference Frequency */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_PPM (0x1c064) /* Global PLL SSC PPM */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_CFG (0x1c065) /* Global PLL SSC Configuration */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_ALU_CMD (0x1c067) /* Global PLL SSC ALU Command */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_MON (0x1c069) /* Global PLL SSC Monitor */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_ALU_OUT_0 (0x1c06b) /* Global PLL SSC ALU Output Register #0 */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_ALU_OUT_1 (0x1c06c) /* Global PLL SSC ALU Output Register #1 */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_DIV (0x1c06d) /* Global PLL SSC Divider */
+#define PCIE_PHY_DWC_GLBL_PLL_SSC_FRAC (0x1c06e) /* Global PLL SSC Fraction */
+#define PCIE_PHY_DWC_GLBL_TAD (0x1c080) /* Global Test Analog and Digital Monitor */
+#define PCIE_PHY_DWC_GLBL_TM_ADMON (0x1c081) /* Global Test Mode Analog/Digital Monitor Enable */
+#define PCIE_PHY_DWC_EQ_WAIT_TIME (0x3c000) /* TX and RX Equalization Wait Times */
+#define PCIE_PHY_DWC_RDET_TIME (0x3c001) /* Receiver Detect Wait Times */
+#define PCIE_PHY_DWC_PCS_LANE_LINK_CFG (0x3c002) /* Link Configuration Override */
+#define PCIE_PHY_DWC_PCS_PLL_CTLIFC_0 (0x3c003) /* PLL Control Interface Override Register #0 */
+#define PCIE_PHY_DWC_PCS_PLL_CTLIFC_1 (0x3c004) /* PLL Control Interface Override Register #1 */
+#define PCIE_PHY_DWC_PCS_REG_RD_TIMEOUT (0x3c005) /* Register Read Timeout */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE1_MODE_0 (0x3c006) /* PLL Configuration Register #0 for PCIe1 */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE1_MODE_1 (0x3c007) /* PLL Configuration Register #1 for PCIe1 */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE1_MODE_0 (0x3c008) /* Lane Configuration Register #0 for PCIe1 */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE1_MODE_1 (0x3c009) /* Lane Configuration Register #1 for PCIe1 */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE2_MODE_0 (0x3c00a) /* PLL Configuration Register #0 for PCIe2 */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE2_MODE_1 (0x3c00b) /* PLL Configuration Register #1 for PCIe2 */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE2_MODE_0 (0x3c00c) /* Lane Configuration Register #0 for PCIe2 */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE2_MODE_1 (0x3c00d) /* Lane Configuration Register #1 for PCIe2 */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE3_MODE_0 (0x3c00e) /* PLL Configuration Register #0 for PCIe3 */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE3_MODE_1 (0x3c00f) /* PLL Configuration Register #1 for PCIe3 */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE3_MODE_0 (0x3c010) /* Lane Configuration Register #0 for PCIe3 */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE3_MODE_1 (0x3c011) /* Lane Configuration Register #1 for PCIe3 */
+#define PCIE_PHY_DWC_PCS_PLL_KX_MODE_1 (0x3c013) /* PLL Configuration Register #1 for KX */
+#define PCIE_PHY_DWC_PCS_LANE_KX_MODE_0 (0x3c014) /* Lane Configuration Register #0 for KX */
+#define PCIE_PHY_DWC_PCS_LANE_KX_MODE_1 (0x3c015) /* Lane Configuration Register #1 for KX */
+#define PCIE_PHY_DWC_PCS_PLL_KX4_MODE_0 (0x3c016) /* PLL Configuration Register #0 for KX4 */
+#define PCIE_PHY_DWC_PCS_PLL_KX4_MODE_1 (0x3c017) /* PLL Configuration Register #1 for KX4 */
+#define PCIE_PHY_DWC_PCS_LANE_KX4_MODE_0 (0x3c018) /* Lane Configuration Register #0 for KX4 */
+#define PCIE_PHY_DWC_PCS_LANE_KX4_MODE_1 (0x3c019) /* Lane Configuration Register #1 for KX4 */
+#define PCIE_PHY_DWC_PCS_PLL_KR_MODE_0 (0x3c01a) /* PLL Configuration Register #0 for KR */
+#define PCIE_PHY_DWC_PCS_PLL_KR_MODE_1 (0x3c01b) /* PLL Configuration Register #1 for KR */
+#define PCIE_PHY_DWC_PCS_LANE_KR_MODE_0 (0x3c01c) /* Lane Configuration Register #0 for KR */
+#define PCIE_PHY_DWC_PCS_LANE_KR_MODE_1 (0x3c01d) /* Lane Configuration Register #1 for KR */
+#define PCIE_PHY_DWC_PCS_PLL_SGMII_MODE_0 (0x3c01e) /* PLL Configuration Register #0 for SGMII */
+#define PCIE_PHY_DWC_PCS_PLL_SGMII_MODE_1 (0x3c01f) /* PLL Configuration Register #1 for SGMII */
+#define PCIE_PHY_DWC_PCS_LANE_SGMII_MODE_0 (0x3c020) /* Lane Configuration Register #0 for SGMII */
+#define PCIE_PHY_DWC_PCS_LANE_SGMII_MODE_1 (0x3c021) /* Lane Configuration Register #1 for SGMII */
+#define PCIE_PHY_DWC_PCS_PLL_QSGMII_MODE_0 (0x3c022) /* PLL Configuration Register #0 for QSGMII */
+#define PCIE_PHY_DWC_PCS_PLL_QSGMII_MODE_1 (0x3c023) /* PLL Configuration Register #1 for QSGMII */
+#define PCIE_PHY_DWC_PCS_LANE_QSGMII_MODE_0 (0x3c024) /* Lane Configuration Register #0 for QSGMII */
+#define PCIE_PHY_DWC_PCS_LANE_QSGMII_MODE_1 (0x3c025) /* Lane Configuration Register #1 for QSGMII */
+#define PCIE_PHY_DWC_PCS_PLL_CEI_MODE_0 (0x3c026) /* PLL Configuration Register #0 for CEI */
+#define PCIE_PHY_DWC_PCS_PLL_CEI_MODE_1 (0x3c027) /* PLL Configuration Register #1 for CEI */
+#define PCIE_PHY_DWC_PCS_LANE_CEI_MODE_0 (0x3c028) /* Lane Configuration Register #0 for CEI */
+#define PCIE_PHY_DWC_PCS_LANE_CEI_MODE_1 (0x3c029) /* Lane Configuration Register #1 for CEI */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE1_125M_MODE_0 (0x3c02a) /* PLL Configuration Register #0 for PCIe1 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE1_125M_MODE_1 (0x3c02b) /* PLL Configuration Register #1 for PCIe1 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE1_125M_MODE_0 (0x3c02c) /* Lane Configuration Register #0 for PCIe1 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE1_125M_MODE_1 (0x3c02d) /* Lane Configuration Register #1 for PCIe1 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE2_125M_MODE_0 (0x3c02e) /* PLL Configuration Register #0 for PCIe2 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE2_125M_MODE_1 (0x3c02f) /* PLL Configuration Register #1 for PCIe2 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE2_125M_MODE_0 (0x3c030) /* Lane Configuration Register #0 for PCIe2 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE2_125M_MODE_1 (0x3c031) /* Lane Configuration Register #1 for PCIe2 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE3_125M_MODE_0 (0x3c032) /* PLL Configuration Register #0 for PCIe3 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_PLL_PCIE3_125M_MODE_1 (0x3c033) /* PLL Configuration Register #1 for PCIe3 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE3_125M_MODE_0 (0x3c034) /* Lane Configuration Register #0 for PCIe3 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_LANE_PCIE3_125M_MODE_1 (0x3c035) /* Lane Configuration Register #1 for PCIe3 with 125MHz refclk */
+#define PCIE_PHY_DWC_PCS_LANE_VMA_COARSE_CTRL_0 (0x3c036) /* Lane VMA Coarse Control Register #0 */
+#define PCIE_PHY_DWC_PCS_LANE_VMA_COARSE_CTRL_1 (0x3c037) /* Lane VMA Coarse Control Register #1 */
+#define PCIE_PHY_DWC_PCS_LANE_VMA_COARSE_CTRL_2 (0x3c038) /* Lane VMA Coarse Control Register #2 */
+#define PCIE_PHY_DWC_PCS_LANE_VMA_FINE_CTRL_0 (0x3c039) /* Lane VMA Fine Control Register #0 */
+#define PCIE_PHY_DWC_PCS_LANE_VMA_FINE_CTRL_1 (0x3c03a) /* Lane VMA Fine Control Register #1 */
+#define PCIE_PHY_DWC_PCS_LANE_VMA_FINE_CTRL_2 (0x3c03b) /* Lane VMA Fine Control Register #2 */
+#define PCIE_PHY_DWC_PCS_LANE_MODE_OVRD (0x3c03c) /* Lane Mode Override in Raw PCS Global and Slice */
+#define PCIE_PHY_DWC_PCS_LANE_LINK_MON (0x3c040) /* Monitor of MAC to Raw PCS Link Configuration Interface */
+#define PCIE_PHY_DWC_PCS_MAC_PLLIFC_MON_2 (0x3c043) /* Monitor of MAC to Raw PCS PLL_PCS Divider Value */
+#define PCIE_PHY_DWC_PCS_MAC_PLLIFC_MON_3 (0x3c044) /* Monitor of MAC to Raw PCS PLL OP_Range and Divider Values */
+#define PCIE_PHY_DWC_SLICE_TRIM (0x1c040) /* Slice TX and RX Bias Trim Settings */
+#define PCIE_PHY_DWC_RX_LDLL_CTRL (0x1c043) /* RX Lane DLL Test Controls */
+#define PCIE_PHY_DWC_RX_SDLL_CTRL (0x1c044) /* RX Slice DLL test controls */
+#define PCIE_PHY_DWC_SLICE_PCIE1_MODE (0x1c045) /* Slice Configuration Settings for PCIE1 @ 100MHz */
+#define PCIE_PHY_DWC_SLICE_PCIE2_MODE (0x1c046) /* Slice Configuration Settings for PCIE2 @ 100Mhz */
+#define PCIE_PHY_DWC_SLICE_PCIE3_MODE (0x1c047) /* Slice Configuration Settings for PCIE3 @ 100Mhz */
+#define PCIE_PHY_DWC_SLICE_KX_MODE (0x1c048) /* Slice Configuration Settings for KX */
+#define PCIE_PHY_DWC_SLICE_KX4_MODE (0x1c049) /* Slice Configuration Settings for KX4 */
+#define PCIE_PHY_DWC_SLICE_KR_MODE (0x1c04a) /* Slice Configuration Settings for KR */
+#define PCIE_PHY_DWC_SLICE_SGMII_MODE (0x1c04b) /* Slice Configuration Settings for SGMII */
+#define PCIE_PHY_DWC_SLICE_QSGMII_MODE (0x1c04c) /* Slice Configuration Settings for QSGMII */
+#define PCIE_PHY_DWC_SLICE_CEI_MODE (0x1c04d) /* Slice Configuration Settings for CEI */
+#define PCIE_PHY_DWC_SLICE_PCIE1_125M_MODE (0x1c04e) /* Slice Configuration Settings for PCIE1 @ 125MHz */
+#define PCIE_PHY_DWC_SLICE_PCIE2_125M_MODE (0x1c04f) /* Slice Configuration Settings for PCIE2 @ 125MHz */
+#define PCIE_PHY_DWC_SLICE_PCIE3_125M_MODE (0x1c050) /* Slice Configuration Settings for PCIE3 @ 125MHz */
+#define PCIE_PHY_DWC_SLICE_OVRD_MODE (0x1c051) /* Slice Configuration Settings Override */
+#define PCIE_PHY_DWC_RX_CFG_0 (0x18000) /* Lane RX Configuration Register #0 */
+#define PCIE_PHY_DWC_RX_CFG_1 (0x18001) /* Lane RX Configuration Register #1 */
+#define PCIE_PHY_DWC_RX_CFG_2 (0x18002) /* Lane RX Configuration Register #2 */
+#define PCIE_PHY_DWC_RX_CFG_3 (0x18003) /* Lane RX Configuration Register #3 */
+#define PCIE_PHY_DWC_RX_CFG_4 (0x18004) /* Lane RX Configuration Register #4 */
+#define PCIE_PHY_DWC_RX_CFG_5 (0x18005) /* Lane RX Configuration Register #5 */
+#define PCIE_PHY_DWC_RX_CDR_CTRL_0 (0x18006) /* Lane RX CDR Control Register #0 */
+#define PCIE_PHY_DWC_RX_CDR_CTRL_1 (0x18007) /* Lane RX CDR Control Register #1 */
+#define PCIE_PHY_DWC_RX_CDR_CTRL_2 (0x18008) /* Lane RX CDR Control Register #2 */
+#define PCIE_PHY_DWC_RX_LOOP_CTRL (0x18009) /* Lane RX Loop Control */
+#define PCIE_PHY_DWC_RX_MISC_CTRL (0x1800a) /* Lane RX Miscellaneous Control */
+#define PCIE_PHY_DWC_RX_CTLE_CTRL (0x1800b) /* Lane RX CTLE Control */
+#define PCIE_PHY_DWC_RX_PRECORR_CTRL (0x1800c) /* Lane RX Pre-Correlation Control */
+#define PCIE_PHY_DWC_RX_PHS_ACCM_CTRL (0x1800d) /* Lane RX Phase Accumulator Control */
+#define PCIE_PHY_DWC_RX_PHS_ACCM_FR_VAL (0x1800e) /* Lane RX Phase Accumulator Frequency Portion Control */
+#define PCIE_PHY_DWC_RX_PRECORR_VAL (0x1800f) /* Lane RX Pre-Correlation Count */
+#define PCIE_PHY_DWC_RX_DELTA_PM_0 (0x18010) /* Lane RX VMA Performance Metric Register #0 */
+#define PCIE_PHY_DWC_RX_DELTA_PM_1 (0x18011) /* Lane RX VMA Performance Metric Register #1 */
+#define PCIE_PHY_DWC_TX_CAPT_CTRL (0x18012) /* Lane TX Latch Control */
+#define PCIE_PHY_DWC_TX_CFG_0 (0x18015) /* Lane TX Configuration Register #0 */
+#define PCIE_PHY_DWC_TX_CFG_1 (0x18016) /* Lane TX Configuration Register #1 */
+#define PCIE_PHY_DWC_TX_CFG_2 (0x18017) /* Lane TX Configuration Register #2 */
+#define PCIE_PHY_DWC_TX_CFG_3 (0x18018) /* Lane TX Configuration Register #3 */
+#define PCIE_PHY_DWC_TX_PREEMPH_0 (0x18019) /* Lane TX Pre-Emphasis */
+#define PCIE_PHY_DWC_PMA_LOOPBACK_CTRL (0x1801a) /* Lane PMA Loopback Control */
+#define PCIE_PHY_DWC_LANE_PWR_CTRL (0x1801b) /* Lane Power Control */
+#define PCIE_PHY_DWC_TERM_CTRL (0x1801c) /* Lane Termination Control */
+#define PCIE_PHY_DWC_RX_MISC_STATUS (0x18025) /* RX Miscellaneous Status */
+#define PCIE_PHY_DWC_SDS_PIN_MON_0 (0x18026) /* SerDes Pin Monitor 0 */
+#define PCIE_PHY_DWC_SDS_PIN_MON_1 (0x18027) /* SerDes Pin Monitor 1 */
+#define PCIE_PHY_DWC_SDS_PIN_MON_2 (0x18028) /* SerDes Pin Monitor 2 */
+#define PCIE_PHY_DWC_RX_PWR_MON_0 (0x18029) /* RX Power State Machine Monitor 0 */
+#define PCIE_PHY_DWC_RX_PWR_MON_1 (0x1802a) /* RX Power State Machine Monitor 1 */
+#define PCIE_PHY_DWC_RX_PWR_MON_2 (0x1802b) /* RX Power State Machine Monitor 2 */
+#define PCIE_PHY_DWC_TX_PWR_MON_0 (0x1802c) /* TX Power State Machine Monitor 0 */
+#define PCIE_PHY_DWC_TX_PWR_MON_1 (0x1802d) /* TX Power State Machine Monitor 1 */
+#define PCIE_PHY_DWC_TX_PWR_MON_2 (0x1802e) /* TX Power State Machine Monitor 2 */
+#define PCIE_PHY_DWC_RX_VMA_CTRL (0x18040) /* Lane RX VMA Control */
+#define PCIE_PHY_DWC_RX_CDR_MISC_CTRL_0 (0x18041) /* Lane RX CDR Miscellaneous Control Register #0 */
+#define PCIE_PHY_DWC_RX_CDR_MISC_CTRL_1 (0x18042) /* Lane RX CDR Miscellaneous Control Register #1 */
+#define PCIE_PHY_DWC_RX_PWR_CTRL (0x18043) /* Lane RX Power Control */
+#define PCIE_PHY_DWC_RX_OS_MVALBBD_0 (0x18045) /* Lane RX Offset Calibration Manual Control Register #0 */
+#define PCIE_PHY_DWC_RX_OS_MVALBBD_1 (0x18046) /* Lane RX Offset Calibration Manual Control Register #1 */
+#define PCIE_PHY_DWC_RX_OS_MVALBBD_2 (0x18047) /* Lane RX Offset Calibration Manual Control Register #2 */
+#define PCIE_PHY_DWC_RX_AEQ_VALBBD_0 (0x18048) /* Lane RX Adaptive Equalizer Control Register #0 */
+#define PCIE_PHY_DWC_RX_AEQ_VALBBD_1 (0x18049) /* Lane RX Adaptive Equalizer Control Register #1 */
+#define PCIE_PHY_DWC_RX_AEQ_VALBBD_2 (0x1804a) /* Lane RX Adaptive Equalizer Control Register #2 */
+#define PCIE_PHY_DWC_RX_MISC_OVRRD (0x1804b) /* Lane RX Miscellaneous Override Controls */
+#define PCIE_PHY_DWC_RX_OVRRD_PHASE_ACCUM_ADJ (0x1804c) /* Lane RX Phase Accumulator Adjust Override */
+#define PCIE_PHY_DWC_RX_AEQ_OUT_0 (0x18050) /* Lane RX Adaptive Equalizer Status Register #0 */
+#define PCIE_PHY_DWC_RX_AEQ_OUT_1 (0x18051) /* Lane RX Adaptive Equalizer Status Register #1 */
+#define PCIE_PHY_DWC_RX_AEQ_OUT_2 (0x18052) /* Lane RX Adaptive Equalizer Status Register #2 */
+#define PCIE_PHY_DWC_RX_OS_OUT_0 (0x18053) /* Lane RX Offset Calibration Status Register #0 */
+#define PCIE_PHY_DWC_RX_OS_OUT_1 (0x18054) /* Lane RX Offset Calibration Status Register #1 */
+#define PCIE_PHY_DWC_RX_OS_OUT_2 (0x18055) /* Lane RX Offset Calibration Status Register #2 */
+#define PCIE_PHY_DWC_RX_OS_OUT_3 (0x18056) /* Lane RX Offset Calibration Status Register #3 */
+#define PCIE_PHY_DWC_RX_VMA_STATUS_0 (0x18057) /* Lane RX CDR Status Register #0 */
+#define PCIE_PHY_DWC_RX_VMA_STATUS_1 (0x18058) /* Lane RX CDR Status Register #1 */
+#define PCIE_PHY_DWC_RX_CDR_STATUS_0 (0x18059) /* Lane RX CDR Status Register #0 */
+#define PCIE_PHY_DWC_RX_CDR_STATUS_1 (0x1805a) /* Lane RX CDR Status Register #1 */
+#define PCIE_PHY_DWC_RX_CDR_STATUS_2 (0x1805b) /* Lane RX CDR Status Register #2 */
+#define PCIE_PHY_DWC_PCS_MISC_CFG_0 (0x38000) /* Lane Miscellaneous Configuration Register #0 */
+#define PCIE_PHY_DWC_PCS_MISC_CFG_1 (0x38001) /* Lane Raw PCS Miscellaneous Configuration Register #1 */
+#define PCIE_PHY_DWC_PCS_LBERT_PAT_CFG (0x38003) /* LBERT Pattern Configuration */
+#define PCIE_PHY_DWC_PCS_LBERT_CFG (0x38004) /* LBERT Configuration */
+#define PCIE_PHY_DWC_PCS_LBERT_ECNT (0x38005) /* LBERT Error Counter */
+#define PCIE_PHY_DWC_PCS_RESET_0 (0x38006) /* Lane Raw PCS Reset Register #0 */
+#define PCIE_PHY_DWC_PCS_RESET_1 (0x38007) /* Lane Raw PCS Reset Register #1 */
+#define PCIE_PHY_DWC_PCS_RESET_2 (0x38008) /* Lane Raw PCS Reset Register #2 */
+#define PCIE_PHY_DWC_PCS_RESET_3 (0x38009) /* Lane Raw PCS Reset Register #3 */
+#define PCIE_PHY_DWC_PCS_CTLIFC_CTRL_0 (0x3800c) /* Lane Raw PCS Control Interface Configuration Register #0 */
+#define PCIE_PHY_DWC_PCS_CTLIFC_CTRL_1 (0x3800d) /* Lane Raw PCS Control Interface Configuration Register #1 */
+#define PCIE_PHY_DWC_PCS_CTLIFC_CTRL_2 (0x3800e) /* Lane Raw PCS Control Interface Configuration Register #2 */
+#define PCIE_PHY_DWC_PCS_MACIFC_MON_0 (0x38021) /* MAC to Raw PCS Interface Monitor Register #0 */
+#define PCIE_PHY_DWC_PCS_MACIFC_MON_2 (0x38023) /* MAC to Raw PCS Interface Monitor Register #1 */
diff --git a/include/linux/mfd/baikal/lcru-pcie.h b/include/linux/mfd/baikal/lcru-pcie.h
new file mode 100644
--- /dev/null
+++ b/include/linux/mfd/baikal/lcru-pcie.h
@@ -0,0 +1,140 @@
+/*
+ * Baikal SoC series Local Clock and Reset Unit (LCRU) register offsets
+ * and bit definitions.
+ *
+ * Copyright (C) 2019 Baikal Electronics JSC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_MFD_SYSCON_BAIKAL_LCRU_H_
+#define _LINUX_MFD_SYSCON_BAIKAL_LCRU_H_
+
+#include <linux/regmap.h>
+
+//#define BAIKAL_CMU_PCIE_STEP 0x30
+
+//#define BAIKAL_CMU_PCIE_MSTRCLK 0x20
+//#define BAIKAL_CMU_PCIE_SLVCLK 0x30
+//#define BAIKAL_CMU_PCIE_CFGCLK 0x40
+
+#define BAIKAL_LCRU_PCIE_RESET_BASE 0x50000 /* GPR0_RW */
+#define BAIKAL_LCRU_PCIE_RESET(x) ((x * 0x20) + BAIKAL_LCRU_PCIE_RESET_BASE)
+#define BAIKAL_PCIE_ADB_PWRDWN (1 << 13)
+#define BAIKAL_PCIE_HOT_RESET (1 << 12)
+#define BAIKAL_PCIE_NONSTICKY_RST (1 << 11)
+#define BAIKAL_PCIE_STICKY_RST (1 << 10)
+#define BAIKAL_PCIE_PWR_RST (1 << 9)
+#define BAIKAL_PCIE_CORE_RST (1 << 8)
+#define BAIKAL_PCIE_PIPE1_RESET (1 << 5) /* x8 controller only */
+#define BAIKAL_PCIE_PIPE0_RESET (1 << 4) /* x8 controller only */
+#define BAIKAL_PCIE_PIPE_RESET (1 << 4) /* x4 controllers only */
+#define BAIKAL_PCIE_PHY_RESET (1 << 0)
+
+#define BAIKAL_LCRU_PCIE_STATUS_BASE 0x50004 /* GPR0_RO */
+#define BAIKAL_LCRU_PCIE_STATUS(x) ((x * 0x20) + BAIKAL_LCRU_PCIE_STATUS_BASE)
+#define BAIKAL_PCIE_TURNOFF_ACK (1 << 31)
+#define BAIKAL_PCIE_ADB_PWRACK (1 << 30)
+#define BAIKAL_PCIE_WAKE_DET (1 << 24)
+#define BAIKAL_PCIE_AUX_PM_EN (1 << 22)
+#define BAIKAL_PCIE_PM_PME_STATUS (1 << 21)
+#define BAIKAL_PCIE_PM_PME_EN (1 << 20)
+#define BAIKAL_PCIE_PM_DSTATE_SHIFT 16
+#define BAIKAL_PCIE_PM_DSTATE_MASK 0x7
+#define BAIKAL_PCIE_PM_DSTATE_D0 0
+#define BAIKAL_PCIE_PM_DSTATE_D1 1
+#define BAIKAL_PCIE_PM_DSTATE_D2 2
+#define BAIKAL_PCIE_PM_DSTATE_D3 3
+#define BAIKAL_PCIE_PM_DSTATE_UNINIT 4
+#define BAIKAL_PCIE_LTSSM_RCVRY_EQ (1 << 15)
+#define BAIKAL_PCIE_PIPE_CLK_REQ (1 << 14)
+#define BAIKAL_PCIE_SMLH_REQ_RST (1 << 13)
+#define BAIKAL_PCIE_LINK_REQ_RST (1 << 12)
+#define BAIKAL_PCIE_PM_LINKSTATE_L2 (1 << 10)
+#define BAIKAL_PCIE_PM_LINKSTATE_L1 (1 << 9)
+#define BAIKAL_PCIE_PM_LINKSTATE_L0S (1 << 8)
+#define BAIKAL_PCIE_RDLH_LINKUP (1 << 7)
+#define BAIKAL_PCIE_SMLH_LINKUP (1 << 6)
+#define BAIKAL_PCIE_LTSSM_STATE_SHIFT 0
+#define BAIKAL_PCIE_LTSSM_STATE_MASK 0x3F
+#define BAIKAL_PCIE_LTSSM_STATE_DETECT_QUIET 0x00
+#define BAIKAL_PCIE_LTSSM_STATE_DETECT_ACT 0x01
+#define BAIKAL_PCIE_LTSSM_STATE_POLLING_ACTIVE 0x02
+#define BAIKAL_PCIE_LTSSM_STATE_POLLING_COMPLIANCE 0x03
+#define BAIKAL_PCIE_LTSSM_STATE_POLLING_CONFIG 0x04
+#define BAIKAL_PCIE_LTSSM_STATE_PRE_DETECT_QUIET 0x05
+#define BAIKAL_PCIE_LTSSM_STATE_DETECT_WAIT 0x06
+#define BAIKAL_PCIE_LTSSM_STATE_CFG_LINK_WD_START 0x07
+#define BAIKAL_PCIE_LTSSM_STATE_CFG_LINK_WD_ACCEPT 0x08
+#define BAIKAL_PCIE_LTSSM_STATE_CFG_LANE_NUM_WAIT 0x09
+#define BAIKAL_PCIE_LTSSM_STATE_CFG_LANE_NUM_ACCEPT 0x0A
+#define BAIKAL_PCIE_LTSSM_STATE_CFG_COMPLETE 0x0B
+#define BAIKAL_PCIE_LTSSM_STATE_CFG_IDLE 0x0C
+#define BAIKAL_PCIE_LTSSM_STATE_RCVRY_LOCK 0x0D
+#define BAIKAL_PCIE_LTSSM_STATE_RCVRY_SPEED 0x0E
+#define BAIKAL_PCIE_LTSSM_STATE_RCVRY_RCVR_CFG 0x0F
+#define BAIKAL_PCIE_LTSSM_STATE_RCVRY_IDLE 0x10
+#define BAIKAL_PCIE_LTSSM_STATE_RCVRY_EQ0 0x20
+#define BAIKAL_PCIE_LTSSM_STATE_RCVRY_EQ1 0x21
+#define BAIKAL_PCIE_LTSSM_STATE_RCVRY_EQ2 0x22
+#define BAIKAL_PCIE_LTSSM_STATE_RCVRY_EQ3 0x23
+#define BAIKAL_PCIE_LTSSM_STATE_L0 0x11
+#define BAIKAL_PCIE_LTSSM_STATE_L0S 0x12
+#define BAIKAL_PCIE_LTSSM_STATE_L123_SEND_IDLE 0x13
+#define BAIKAL_PCIE_LTSSM_STATE_L1_IDLE 0x14
+#define BAIKAL_PCIE_LTSSM_STATE_L2_IDLE 0x15
+#define BAIKAL_PCIE_LTSSM_STATE_L2_WAKE 0x16
+#define BAIKAL_PCIE_LTSSM_STATE_DISABLED_ENTRY 0x17
+#define BAIKAL_PCIE_LTSSM_STATE_DISABLED_IDLE 0x18
+#define BAIKAL_PCIE_LTSSM_STATE_DISABLED 0x19
+#define BAIKAL_PCIE_LTSSM_STATE_LOOPBACK_ENTRY 0x1A
+#define BAIKAL_PCIE_LTSSM_STATE_LOOPBACK_ACTIVE 0x1B
+#define BAIKAL_PCIE_LTSSM_STATE_LOOPBACK_EXIT 0x1C
+#define BAIKAL_PCIE_LTSSM_STATE_LOOPBACK_EXIT_TIMEOUT 0x1D
+#define BAIKAL_PCIE_LTSSM_STATE_HOT_RESET_ENTRY 0x1E
+#define BAIKAL_PCIE_LTSSM_STATE_HOT_RESET 0x1F
+
+#define BAIKAL_LCRU_PCIE_GEN_CTL_BASE 0x50008 /* GPR1_RW*/
+#define BAIKAL_LCRU_PCIE_GEN_CTL(x) ((x * 0x20) + BAIKAL_LCRU_PCIE_GEN_CTL_BASE)
+#define BAIKAL_PCIE_AUX_PWR_DET (1 << 24)
+#define BAIKAL_PCIE_TXLANE_FLIP_EN (1 << 17)
+#define BAIKAL_PCIE_RXLANE_FLIP_EN (1 << 16)
+#define BAIKAL_PCIE_PHY_MGMT_ENABLE (1 << 3)
+#define BAIKAL_PCIE_DBI2_MODE (1 << 2)
+#define BAIKAL_PCIE_LTSSM_ENABLE (1 << 1)
+
+#define BAIKAL_LCRU_PCIE_POWER_CTL_BASE 0x50010 /* GPR2_RW */
+#define BAIKAL_LCRU_PCIE_POWER_CTL(x) ((x * 0x20) + BAIKAL_LCRU_POWER_CTL_BASE)
+#define BAIKAL_PCIE_PHY_CLK_REQ (1 << 27)
+#define BAIKAL_PCIE_APP_CLK_REQ (1 << 26)
+#define BAIKAL_PCIE_PERSTN (1 << 25)
+#define BAIKAL_PCIE_TURNOFF_REQ (1 << 24)
+#define BAIKAL_PCIE_REQ_EXIT_L1 (1 << 17)
+#define BAIKAL_PCIE_L1_PENDING (1 << 16)
+#define BAIKAL_PCIE_MAC_CLK_REQ (1 << 5)
+#define BAIKAL_PCIE_PCS_CLK_REQ (1 << 4)
+
+#define BAIKAL_LCRU_PCIE_MSI_TRANS_CTL0 0x500E8
+#define BAIKAL_PCIE_MSI_AWUSER_SHIFT 0
+#define BAIKAL_PCIE_MSI_AWUSER_MASK 0xF
+
+#define BAIKAL_LCRU_PCIE_MSI_TRANS_CTL2 0x500F8
+#define BAIKAL_PCIE_MSI_TRANS_EN(x) (1 << (9 + (x)))
+#define BAIKAL_PCIE_MSI_RCNUM(x) ((x) << (2 * (x)))
+#define BAIKAL_PCIE_MSI_RCNUM_MASK(x) (0x3 << (2 * (x)))
+
+inline u32 baikal_pcie_lcru_readl(struct regmap *lcru, u32 offset)
+{
+ u32 val;
+ regmap_read(lcru, offset, &val);
+ return val;
+}
+
+inline void baikal_pcie_lcru_writel(struct regmap *lcru, u32 offset, u32 val)
+{
+ regmap_write(lcru, offset, val);
+}
+
+#endif /* _LINUX_MFD_SYSCON_BAIKAL_LCRU_H_ */