On Sun, Apr 26, 2020 at 1:59 AM Mark Kettenis <mark.kettenis@xxxxxxxxx> wrote: > > > From: Jagan Teki <jagan@xxxxxxxxxxxxxxxxxxxx> > > Date: Sun, 26 Apr 2020 01:06:56 +0530 > > > > On Sun, Apr 26, 2020 at 12:23 AM Mark Kettenis <mark.kettenis@xxxxxxxxx> wrote: > > > > > > > From: Jagan Teki <jagan@xxxxxxxxxxxxxxxxxxxx> > > > > Date: Sat, 25 Apr 2020 16:33:51 +0530 > > > > > > > > Add Rockchip PCIe controller driver for rk3399 platform. > > > > > > > > Driver support Gen1 by operating as a Root complex. > > > > > > > > Thanks to Patrick for initial work. > > > > > > Tried to get this to work on my firefly-rk3399 which made me notice > > > some shortcomings: > > > > > > 1. The vpcie1v8 and vpcie0v9 supplies are optional, just like the > > > vpcie3v3 supply. > > > > > > 2. The vpcie3v3 regulator check doesn't quite work. > > > > You mean the regulator check? > > I mean the check wether the regulator is actually there in > rockchip_pcie_set_vpcie(). See my suggested changes below. > > > > > > > See below for suggestions on how to fix this. > > > > > > Sadly the NVME SSD doesn't seem to be happy and shows up as only 1023 MB. > > > But that is probably not caused by this diff. > > > > > > > Signed-off-by: Patrick Wildt <patrick@xxxxxxxxx> > > > > Signed-off-by: Jagan Teki <jagan@xxxxxxxxxxxxxxxxxxxx> > > > > --- > > > > drivers/pci/Kconfig | 8 + > > > > drivers/pci/Makefile | 1 + > > > > drivers/pci/pcie_rockchip.c | 460 ++++++++++++++++++++++++++++++++++++ > > > > drivers/pci/pcie_rockchip.h | 79 +++++++ > > > > 4 files changed, 548 insertions(+) > > > > create mode 100644 drivers/pci/pcie_rockchip.c > > > > create mode 100644 drivers/pci/pcie_rockchip.h > > > > > > > > diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig > > > > index 437cd9a055..3dba84103b 100644 > > > > --- a/drivers/pci/Kconfig > > > > +++ b/drivers/pci/Kconfig > > > > @@ -197,4 +197,12 @@ config PCIE_MEDIATEK > > > > Say Y here if you want to enable Gen2 PCIe controller, > > > > which could be found on MT7623 SoC family. > > > > > > > > +config PCIE_ROCKCHIP > > > > + bool "Enable Rockchip PCIe driver" > > > > + select DM_PCI > > > > + default y if ROCKCHIP_RK3399 > > > > + help > > > > + Say Y here if you want to enable PCIe controller support on > > > > + Rockchip SoCs. > > > > + > > > > endif > > > > diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile > > > > index c051ecc9f3..493e9354dd 100644 > > > > --- a/drivers/pci/Makefile > > > > +++ b/drivers/pci/Makefile > > > > @@ -43,3 +43,4 @@ obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o > > > > obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o > > > > obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o > > > > obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o > > > > +obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o > > > > diff --git a/drivers/pci/pcie_rockchip.c b/drivers/pci/pcie_rockchip.c > > > > new file mode 100644 > > > > index 0000000000..adc64aedf5 > > > > --- /dev/null > > > > +++ b/drivers/pci/pcie_rockchip.c > > > > @@ -0,0 +1,460 @@ > > > > +// SPDX-License-Identifier: GPL-2.0+ > > > > +/* > > > > + * Rockchip AXI PCIe host controller driver > > > > + * > > > > + * Copyright (c) 2016 Rockchip, Inc. > > > > + * Copyright (c) 2020 Amarula Solutions(India) > > > > + * Copyright (c) 2020 Jagan Teki <jagan@xxxxxxxxxxxxxxxxxxxx> > > > > + * Copyright (c) 2019 Patrick Wildt <patrick@xxxxxxxxx> > > > > + * Copyright (c) 2018 Mark Kettenis <kettenis@xxxxxxxxxxx> > > > > + * > > > > + * Bits taken from Linux Rockchip PCIe host controller. > > > > + */ > > > > + > > > > +#include <common.h> > > > > +#include <clk.h> > > > > +#include <dm.h> > > > > +#include <dm/device_compat.h> > > > > +#include <pci.h> > > > > +#include <power-domain.h> > > > > +#include <power/regulator.h> > > > > +#include <reset.h> > > > > +#include <syscon.h> > > > > +#include <asm/io.h> > > > > +#include <asm-generic/gpio.h> > > > > +#include <asm/arch-rockchip/clock.h> > > > > +#include <linux/iopoll.h> > > > > + > > > > +#include "pcie_rockchip.h" > > > > + > > > > +DECLARE_GLOBAL_DATA_PTR; > > > > + > > > > +static int rockchip_pcie_rd_conf(const struct udevice *bus, pci_dev_t bdf, > > > > + uint offset, ulong *valuep, > > > > + enum pci_size_t size) > > > > +{ > > > > + struct rockchip_pcie *priv = dev_get_priv(bus); > > > > + ulong value; > > > > + u32 off; > > > > + > > > > + off = (PCI_BUS(bdf) << 20) | (PCI_DEV(bdf) << 15) | > > > > + (PCI_FUNC(bdf) << 12) | (offset & ~0x3); > > > > + > > > > + if ((PCI_BUS(bdf) == priv->first_busno) && (PCI_DEV(bdf) == 0)) { > > > > + value = readl(priv->apb_base + PCIE_RC_NORMAL_BASE + off); > > > > + *valuep = pci_conv_32_to_size(value, offset, size); > > > > + return 0; > > > > + } > > > > + > > > > + if ((PCI_BUS(bdf) == priv->first_busno + 1) && (PCI_DEV(bdf) == 0)) { > > > > + value = readl(priv->axi_base + off); > > > > + *valuep = pci_conv_32_to_size(value, offset, size); > > > > + return 0; > > > > + } > > > > + > > > > + *valuep = pci_get_ff(size); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int rockchip_pcie_wr_conf(struct udevice *bus, pci_dev_t bdf, > > > > + uint offset, ulong value, > > > > + enum pci_size_t size) > > > > +{ > > > > + struct rockchip_pcie *priv = dev_get_priv(bus); > > > > + ulong old; > > > > + u32 off; > > > > + > > > > + off = (PCI_BUS(bdf) << 20) | (PCI_DEV(bdf) << 15) | > > > > + (PCI_FUNC(bdf) << 12) | (offset & ~0x3); > > > > + > > > > + if ((PCI_BUS(bdf) == priv->first_busno) && (PCI_DEV(bdf) == 0)) { > > > > + old = readl(priv->apb_base + PCIE_RC_NORMAL_BASE + off); > > > > + value = pci_conv_size_to_32(old, value, offset, size); > > > > + writel(value, priv->apb_base + PCIE_RC_NORMAL_BASE + off); > > > > + return 0; > > > > + } > > > > + > > > > + if ((PCI_BUS(bdf) == priv->first_busno + 1) && (PCI_DEV(bdf) == 0)) { > > > > + old = readl(priv->axi_base + off); > > > > + value = pci_conv_size_to_32(old, value, offset, size); > > > > + writel(value, priv->axi_base + off); > > > > + return 0; > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int rockchip_pcie_atr_init(struct rockchip_pcie *priv) > > > > +{ > > > > + struct udevice *ctlr = pci_get_controller(priv->dev); > > > > + struct pci_controller *hose = dev_get_uclass_priv(ctlr); > > > > + u64 addr, size, offset; > > > > + u32 type; > > > > + int i, region; > > > > + > > > > + /* Use region 0 to map PCI configuration space. */ > > > > + writel(25 - 1, priv->apb_base + PCIE_ATR_OB_ADDR0(0)); > > > > + writel(0, priv->apb_base + PCIE_ATR_OB_ADDR1(0)); > > > > + writel(PCIE_ATR_HDR_CFG_TYPE0 | PCIE_ATR_HDR_RID, > > > > + priv->apb_base + PCIE_ATR_OB_DESC0(0)); > > > > + writel(0, priv->apb_base + PCIE_ATR_OB_DESC1(0)); > > > > + > > > > + for (i = 0; i < hose->region_count; i++) { > > > > + if (hose->regions[i].flags == PCI_REGION_SYS_MEMORY) > > > > + continue; > > > > + > > > > + if (hose->regions[i].flags == PCI_REGION_IO) > > > > + type = PCIE_ATR_HDR_IO; > > > > + else > > > > + type = PCIE_ATR_HDR_MEM; > > > > + > > > > + /* Only support identity mappings. */ > > > > + if (hose->regions[i].bus_start != > > > > + hose->regions[i].phys_start) > > > > + return -EINVAL; > > > > + > > > > + /* Only support mappings aligned on a region boundary. */ > > > > + addr = hose->regions[i].bus_start; > > > > + if (addr & (PCIE_ATR_OB_REGION_SIZE - 1)) > > > > + return -EINVAL; > > > > + > > > > + /* Mappings should lie between AXI and APB regions. */ > > > > + size = hose->regions[i].size; > > > > + if (addr < (u64)priv->axi_base + PCIE_ATR_OB_REGION0_SIZE) > > > > + return -EINVAL; > > > > + if (addr + size > (u64)priv->apb_base) > > > > + return -EINVAL; > > > > + > > > > + offset = addr - (u64)priv->axi_base - PCIE_ATR_OB_REGION0_SIZE; > > > > + region = 1 + (offset / PCIE_ATR_OB_REGION_SIZE); > > > > + while (size > 0) { > > > > + writel(32 - 1, > > > > + priv->apb_base + PCIE_ATR_OB_ADDR0(region)); > > > > + writel(0, priv->apb_base + PCIE_ATR_OB_ADDR1(region)); > > > > + writel(type | PCIE_ATR_HDR_RID, > > > > + priv->apb_base + PCIE_ATR_OB_DESC0(region)); > > > > + writel(0, priv->apb_base + PCIE_ATR_OB_DESC1(region)); > > > > + > > > > + addr += PCIE_ATR_OB_REGION_SIZE; > > > > + size -= PCIE_ATR_OB_REGION_SIZE; > > > > + region++; > > > > + } > > > > + } > > > > + > > > > + /* Passthrough inbound translations unmodified. */ > > > > + writel(32 - 1, priv->apb_base + PCIE_ATR_IB_ADDR0(2)); > > > > + writel(0, priv->apb_base + PCIE_ATR_IB_ADDR1(2)); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int rockchip_pcie_init_port(struct udevice *dev) > > > > +{ > > > > + struct rockchip_pcie *priv = dev_get_priv(dev); > > > > + u32 cr, val, status; > > > > + int ret; > > > > + > > > > + if (dm_gpio_is_valid(&priv->ep_gpio)) > > > > + dm_gpio_set_value(&priv->ep_gpio, 0); > > > > + > > > > + ret = reset_assert(&priv->aclk_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to assert aclk reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + ret = reset_assert(&priv->pclk_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to assert pclk reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + ret = reset_assert(&priv->pm_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to assert pm reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + ret = reset_assert(&priv->core_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to assert core reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + ret = reset_assert(&priv->mgmt_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to assert mgmt reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + ret = reset_assert(&priv->mgmt_sticky_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to assert mgmt-sticky reset (ret=%d)\n", > > > > + ret); > > > > + return ret; > > > > + } > > > > + > > > > + ret = reset_assert(&priv->pipe_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to assert pipe reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + udelay(10); > > > > + > > > > + ret = reset_deassert(&priv->pm_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to deassert pm reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + ret = reset_deassert(&priv->aclk_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to deassert aclk reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + ret = reset_deassert(&priv->pclk_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to deassert pclk reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + /* Select GEN1 for now */ > > > > + cr = PCIE_CLIENT_GEN_SEL_1; > > > > + /* Set Root complex mode */ > > > > + cr |= PCIE_CLIENT_CONF_ENABLE | PCIE_CLIENT_MODE_RC; > > > > + writel(cr, priv->apb_base + PCIE_CLIENT_CONFIG); > > > > + > > > > + ret = reset_deassert(&priv->mgmt_sticky_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to deassert mgmt-sticky reset (ret=%d)\n", > > > > + ret); > > > > + return ret; > > > > + } > > > > + > > > > + ret = reset_deassert(&priv->core_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to deassert core reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + ret = reset_deassert(&priv->mgmt_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to deassert mgmt reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + ret = reset_deassert(&priv->pipe_rst); > > > > + if (ret) { > > > > + dev_err(dev, "failed to deassert pipe reset (ret=%d)\n", ret); > > > > + return ret; > > > > + } > > > > + > > > > + /* Enable Gen1 training */ > > > > + writel(PCIE_CLIENT_LINK_TRAIN_ENABLE, > > > > + priv->apb_base + PCIE_CLIENT_CONFIG); > > > > + > > > > + if (dm_gpio_is_valid(&priv->ep_gpio)) > > > > + dm_gpio_set_value(&priv->ep_gpio, 1); > > > > + > > > > + ret = readl_poll_sleep_timeout > > > > + (priv->apb_base + PCIE_CLIENT_BASIC_STATUS1, > > > > + status, PCIE_LINK_UP(status), 20, 500 * 1000); > > > > + if (ret) { > > > > + dev_err(dev, "PCIe link training gen1 timeout!\n"); > > > > + return ret; > > > > + } > > > > + > > > > + /* Initialize Root Complex registers. */ > > > > + writel(PCIE_LM_VENDOR_ROCKCHIP, priv->apb_base + PCIE_LM_VENDOR_ID); > > > > + writel(PCI_CLASS_BRIDGE_PCI << 16, > > > > + priv->apb_base + PCIE_RC_BASE + PCI_CLASS_REVISION); > > > > + writel(PCIE_LM_RCBARPIE | PCIE_LM_RCBARPIS, > > > > + priv->apb_base + PCIE_LM_RCBAR); > > > > + > > > > + if (dev_read_bool(dev, "aspm-no-l0s")) { > > > > + val = readl(priv->apb_base + PCIE_RC_PCIE_LCAP); > > > > + val &= ~PCIE_RC_PCIE_LCAP_APMS_L0S; > > > > + writel(val, priv->apb_base + PCIE_RC_PCIE_LCAP); > > > > + } > > > > + > > > > + /* Configure Address Translation. */ > > > > + ret = rockchip_pcie_atr_init(priv); > > > > + if (ret) { > > > > + dev_err(dev, "PCIE-%d: ATR init failed\n", dev->seq); > > > > + return ret; > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int rockchip_pcie_set_vpcie(struct udevice *dev) > > > > +{ > > > > + struct rockchip_pcie *priv = dev_get_priv(dev); > > > > + int ret; > > > > + > > > > + if (!IS_ERR(priv->vpcie3v3)) { > > > > > > I think this should be: > > > > > > if (priv->vpcie3v3) { > > > > I didn't find any issue with the board I have optional of this, but > > will check it. > > > > > > > > > + ret = regulator_set_enable(priv->vpcie3v3, true); > > > > + if (ret) { > > > > + dev_err(dev, "failed to enable vpcie3v3 (ret=%d)\n", > > > > + ret); > > > > + return ret; > > > > + } > > > > + } > > > > + > > > > > > And to make this regulator optional, it needs an > > > > > > if (priv->vpcie1v8) { > > > > I can see from v5.7-rc1, 12v, 3v3 are optional and rest not If I'm not wrong. > > The devicetree binding is clear about it. See > Documentation/devicetree/bindings/pci/rockchip-pcie-host.txt. > > And rk3399-firefly.dts doesn't add the properties. But, at least I can see these two are supplied from SoC Page 12 [1]? [1] http://download.t-firefly.com/product/RK3399/Docs/Hardware/Schematic%20&%20Components%20Position%20&%20CAD/Firefly-RK3399%20SCH%20&%20POS/Firefly-RK3399_V10_SCH_(2017-2-8).pdf _______________________________________________ Linux-rockchip mailing list Linux-rockchip@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/linux-rockchip