From 72b2f9de7609df9b7e7a60e4a9bfca45463cfac5 Mon Sep 17 00:00:00 2001 From: Alexey Sheplyakov Date: Fri, 20 Mar 2020 13:57:57 +0400 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. --- drivers/pci/controller/Kconfig | 12 + drivers/pci/controller/dwc/Makefile | 1 + drivers/pci/controller/dwc/pcie-baikal.c | 722 +++++++++++++++++++++++ drivers/pci/controller/dwc/pcie-baikal.h | 217 +++++++ include/linux/mfd/baikal/lcru-pcie.h | 140 +++++ 5 files changed, 1092 insertions(+) create mode 100644 drivers/pci/controller/dwc/pcie-baikal.c create mode 100644 drivers/pci/controller/dwc/pcie-baikal.h create mode 100644 include/linux/mfd/baikal/lcru-pcie.h diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 64e2f5e379aa..b8a5eb633259 100644 --- 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 @@ -20,6 +20,7 @@ obj-$(CONFIG_PCI_MESON) += pci-meson.o obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.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 index 000000000000..1eb5f0e780c4 --- /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 + * + * 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, ®); + 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 index 000000000000..f59100cf0c6d --- /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 + * + * 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 + * + * 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 index 000000000000..40562d00ab85 --- /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 + +//#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_ */ -- 2.31.1