From patchwork Thu Apr 30 07:04:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jagan Teki X-Patchwork-Id: 1136 Return-Path: X-Original-To: linux-amarula@patchwork.amarulasolutions.com Delivered-To: linux-amarula@patchwork.amarulasolutions.com Received: from mail-pj1-f69.google.com (mail-pj1-f69.google.com [209.85.216.69]) by ganimede.amarulasolutions.com (Postfix) with ESMTPS id 1664C3F0D3 for ; Thu, 30 Apr 2020 09:04:45 +0200 (CEST) Received: by mail-pj1-f69.google.com with SMTP id r3sf734269pjq.7 for ; Thu, 30 Apr 2020 00:04:45 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1588230284; cv=pass; d=google.com; s=arc-20160816; b=ie+EOLxFiWsQvkuHgS+R8tPLQtOvljzozuDzCA0upn53NL5/9mY7kEjmrX5KHVtRsX 5VJgnw9STN4z2IxfvKzVQUxUGoZMRl80TNoc7SUtEhPnF+GATIHHS+tDtZvZAmLAPkW8 xbqKxgQ79E2UnDcefiNF/sHTGSZJcj83+vvzKdx3jYLqh/CmIPgLJ72GwFK++bb8f1zO FJjk4i0JBxa64zPJfCvseFPjq4H2l8SBCoE4yP7yIlIqNIUPjfiTjuzAqTRoDaSOv05J 8MpEooolfLn2vLerd1W7QZ75tJiCWks1GCEQhDsB91X2xZhrsZ2RV15XXSO8lMYL8Hxm c6gw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-archive:list-help:list-post:list-id :mailing-list:precedence:references:in-reply-to:message-id:date :subject:cc:to:from:mime-version:dkim-signature; bh=E8+NWWDZsjoHgk9v2hQ6wzOU6XfhhwV5fsi3hIUtcoc=; b=nC8MrhPSh7czkuodmx0zYE8w8qbdEuf5QBomV499ShtiBhF5Et0jRn6sUSF3hRtw3s Jx2hZSgV+a2yHuH6841vdxHd/sBFtn99YtGBxtK6TLf+fZ1THWtkMk6eyWFJ/5hDS3ZC rF+W4uossl8klu2E9+o/g2WUewgKvz7c7CIRsscYahIDeVNf5Zhl7H2Ax5awFawxRdIR j1HkleFxkCjwDAX6ZQUWiJfzoBb4VOoMmCi9voNobT/rZxoqGqiF6qdEABg64t/m3uFP EaDS0d68m9W6yaOx6revEh4Cq7EF0lF6pSOYwrRm7jt1tcQW73jjFW4k0VeRHDXowoWs /oAA== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b=H651y+6l; spf=pass (google.com: domain of jagan@amarulasolutions.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=jagan@amarulasolutions.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amarulasolutions.com; s=google; h=mime-version:from:to:cc:subject:date:message-id:in-reply-to :references:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe; bh=E8+NWWDZsjoHgk9v2hQ6wzOU6XfhhwV5fsi3hIUtcoc=; b=Tt7act1y3ZECNQ+dHQojx18qx6NE+6YQaS5jdOHmVuW4c6mW5neSrZ40XQful8kyre XU3v3p+i2hYQxrEDIdw7+y0A83vp8LJPnvbjDTGlipBM9QRWVfZxWgc0ccp/sw/6WsXU jCXn/TbsGE4CIi7NQhkuvEAyQK/1aSbNoi7GM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:to:cc:subject:date:message-id :in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-spam-checked-in-group:list-post:list-help:list-archive :list-unsubscribe; bh=E8+NWWDZsjoHgk9v2hQ6wzOU6XfhhwV5fsi3hIUtcoc=; b=IRRK9mwQznb6FXYhGkNRdSp7+eDNWhN0xepx4dGA59gNl7/CqbgmDmQBv0ldJ4bUvb 4n3QFZ9CsL1IPpuljpzNNkFGP4ZadlcPCQCq8+Gb+brpnUkg0Re5TpBmBgbHpbMgfaSd iWSpNA6QhbF73DnpDj5f/1uEvjBknYo2speA1ayQKrj1gecv1zYriTTTWv1WSJ3sTjYY TYtqCDM8X6NJjaztmBt1aLlAKyjL7DWQc59WrDlehjJ5zDmovlycYFBBdy+G7W7IUl5G nqz5XZdFfmMwNSP4nM1xgKdKZAsO1gQp5ZiDbfvkCbmwy9hPUYHsyVi5tVk3wRCYxbBQ YGoQ== X-Gm-Message-State: AGi0PuYtf5R0OdiPWpC7CuQ7bw4lr1acWJyxrD+9oD5RonOV/27WRg1c E21re0Ny/mEpluiO/gpYeOxie8JH X-Google-Smtp-Source: APiQypLvX9VRnuUlOD+/WBz8fv7QkfthWuLRpfykS9wLQlxDX5R6JxKoAY//vvscFquSyJxh1ZFDRA== X-Received: by 2002:a62:1bc5:: with SMTP id b188mr2112551pfb.113.1588230283744; Thu, 30 Apr 2020 00:04:43 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: linux-amarula@amarulasolutions.com Received: by 2002:a17:902:a701:: with SMTP id w1ls3101403plq.7.gmail; Thu, 30 Apr 2020 00:04:43 -0700 (PDT) X-Received: by 2002:a17:902:8608:: with SMTP id f8mr2330667plo.110.1588230283188; Thu, 30 Apr 2020 00:04:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1588230283; cv=none; d=google.com; s=arc-20160816; b=iJus/8K4qNl18iM+MFVDyfKdMuGzmQg5IZzQAumh20sedCxfTGHJb5tFXGcP0qblmS AH7xaPbax1vuDNs+WLyTDRYkp075Ro0OT/X23M3H7Aq+B3Q4doJ4kEl4VCGWNieYocgn sO9cuzr+pIyxtOR8reIoDJP74tnn0/VbC1DrVbvhKXnf6S75uEZ+GtFjzI45URhpWF8a g1rV8beGRiRviogdO64vCFmpk9Mox98BuTj21l4DFomL3SxaDQ5DurWYKAIsxyBq5vle 6qoe/Xd8C5Fxp0TIHl6pWl4GWdwc0heSqLL33unwAOfo/CpCs1UCckODPsCDwkqaEWmG XGFA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=qZLcgIkw6VsaZbMb9f7Jqm6DueQwtF2lpr91eQGAzIg=; b=F32UNLfnKSp7+QLTVZh0Q4oRW0VNNLQ9HxvLX7ivdcTz5cTyoS8OG5kJegESqBTUEr yjTJLA+xpkZryOQmAy/h+OTKmCvtW/Wx7D6AjSnd9wzInX8sFmWc5uvYBy1YYHrzQ2Mp 4kKoL0TzvcMXATRKZ+FXKhwNWsdHGi3jHgkBgVDfffIhaI4uHaaZhKOaqiwsv7xObJod NnMvqHEwe6OSCoTbd3oLBWQy6F7+VS6C6HQo8pHdZYLipVjLZwVWlsjWVPKMhRkeqGNa kl1xQMGztaNdlA4t0St/1tvjgtB/NhxE3x8Wj5eYUroa3I1G+eD3Bmz1y66TrX4TgW+S 5RhA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b=H651y+6l; spf=pass (google.com: domain of jagan@amarulasolutions.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=jagan@amarulasolutions.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id c3sor4621312pfi.4.2020.04.30.00.04.43 for (Google Transport Security); Thu, 30 Apr 2020 00:04:43 -0700 (PDT) Received-SPF: pass (google.com: domain of jagan@amarulasolutions.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; X-Received: by 2002:a63:fb14:: with SMTP id o20mr1980204pgh.144.1588230282614; Thu, 30 Apr 2020 00:04:42 -0700 (PDT) Received: from localhost.localdomain ([2405:201:c809:c7d5:6514:3619:d1af:85f6]) by smtp.gmail.com with ESMTPSA id p64sm964143pjp.7.2020.04.30.00.04.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Apr 2020 00:04:41 -0700 (PDT) From: Jagan Teki To: Kever Yang , Simon Glass , Philipp Tomsich Cc: patrick@blueri.se, sunil@amarulasolutions.com, u-boot@lists.denx.de, linux-rockchip@lists.infradead.org, linux-amarula@amarulasolutions.com, Jagan Teki Subject: [PATCH v2 5/8] pci: Add Rockchip PCIe controller driver Date: Thu, 30 Apr 2020 12:34:09 +0530 Message-Id: <20200430070412.12499-6-jagan@amarulasolutions.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200430070412.12499-1-jagan@amarulasolutions.com> References: <20200430070412.12499-1-jagan@amarulasolutions.com> X-Original-Sender: jagan@amarulasolutions.com X-Original-Authentication-Results: mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b=H651y+6l; spf=pass (google.com: domain of jagan@amarulasolutions.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=jagan@amarulasolutions.com Content-Type: text/plain; charset="UTF-8" Precedence: list Mailing-list: list linux-amarula@amarulasolutions.com; contact linux-amarula+owners@amarulasolutions.com List-ID: X-Spam-Checked-In-Group: linux-amarula@amarulasolutions.com X-Google-Group-Id: 476853432473 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Add Rockchip PCIe controller driver for rk3399 platform. Driver support Gen1 by operating as a Root complex. Thanks to Patrick for initial work. Signed-off-by: Patrick Wildt Signed-off-by: Jagan Teki Reviewed-by: Kever Yang --- Changes for v2: - simplify bdf in rd_conf, wr_conf - collect kever r-o-b drivers/pci/Kconfig | 8 + drivers/pci/Makefile | 1 + drivers/pci/pcie_rockchip.c | 467 ++++++++++++++++++++++++++++++++++++ drivers/pci/pcie_rockchip.h | 79 ++++++ 4 files changed, 555 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..3f06f783ca --- /dev/null +++ b/drivers/pci/pcie_rockchip.c @@ -0,0 +1,467 @@ +// 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 + * Copyright (c) 2019 Patrick Wildt + * Copyright (c) 2018 Mark Kettenis + * + * Bits taken from Linux Rockchip PCIe host controller. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie_rockchip.h" + +DECLARE_GLOBAL_DATA_PTR; + +static int rockchip_pcie_off_conf(pci_dev_t bdf, uint offset) +{ + unsigned int bus = PCI_BUS(bdf); + unsigned int dev = PCI_DEV(bdf); + unsigned int func = PCI_FUNC(bdf); + + return (bus << 20) | (dev << 15) | (func << 12) | (offset & ~0x3); +} + +static int rockchip_pcie_rd_conf(const struct udevice *udev, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + struct rockchip_pcie *priv = dev_get_priv(udev); + unsigned int bus = PCI_BUS(bdf); + unsigned int dev = PCI_DEV(bdf); + int where = rockchip_pcie_off_conf(bdf, offset); + ulong value; + + if (bus == priv->first_busno && dev == 0) { + value = readl(priv->apb_base + PCIE_RC_NORMAL_BASE + where); + *valuep = pci_conv_32_to_size(value, offset, size); + return 0; + } + + if ((bus == priv->first_busno + 1) && dev == 0) { + value = readl(priv->axi_base + where); + *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 *udev, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + struct rockchip_pcie *priv = dev_get_priv(udev); + unsigned int bus = PCI_BUS(bdf); + unsigned int dev = PCI_DEV(bdf); + int where = rockchip_pcie_off_conf(bdf, offset); + ulong old; + + if (bus == priv->first_busno && dev == 0) { + old = readl(priv->apb_base + PCIE_RC_NORMAL_BASE + where); + value = pci_conv_size_to_32(old, value, offset, size); + writel(value, priv->apb_base + PCIE_RC_NORMAL_BASE + where); + return 0; + } + + if ((bus == priv->first_busno + 1) && dev == 0) { + old = readl(priv->axi_base + where); + value = pci_conv_size_to_32(old, value, offset, size); + writel(value, priv->axi_base + where); + 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)) { + ret = regulator_set_enable(priv->vpcie3v3, true); + if (ret) { + dev_err(dev, "failed to enable vpcie3v3 (ret=%d)\n", + ret); + return ret; + } + } + + ret = regulator_set_enable(priv->vpcie1v8, true); + if (ret) { + dev_err(dev, "failed to enable vpcie1v8 (ret=%d)\n", ret); + goto err_disable_3v3; + } + + ret = regulator_set_enable(priv->vpcie0v9, true); + if (ret) { + dev_err(dev, "failed to enable vpcie0v9 (ret=%d)\n", ret); + goto err_disable_1v8; + } + + return 0; + +err_disable_1v8: + regulator_set_enable(priv->vpcie1v8, false); +err_disable_3v3: + if (!IS_ERR(priv->vpcie3v3)) + regulator_set_enable(priv->vpcie3v3, false); + return ret; +} + +static int rockchip_pcie_parse_dt(struct udevice *dev) +{ + struct rockchip_pcie *priv = dev_get_priv(dev); + int ret; + + priv->axi_base = dev_read_addr_name(dev, "axi-base"); + if (!priv->axi_base) + return -ENODEV; + + priv->apb_base = dev_read_addr_name(dev, "apb-base"); + if (!priv->axi_base) + return -ENODEV; + + ret = gpio_request_by_name(dev, "ep-gpios", 0, + &priv->ep_gpio, GPIOD_IS_OUT); + if (ret) { + dev_err(dev, "failed to find ep-gpios property\n"); + return ret; + } + + ret = reset_get_by_name(dev, "core", &priv->core_rst); + if (ret) { + dev_err(dev, "failed to get core reset (ret=%d)\n", ret); + return ret; + } + + ret = reset_get_by_name(dev, "mgmt", &priv->mgmt_rst); + if (ret) { + dev_err(dev, "failed to get mgmt reset (ret=%d)\n", ret); + return ret; + } + + ret = reset_get_by_name(dev, "mgmt-sticky", &priv->mgmt_sticky_rst); + if (ret) { + dev_err(dev, "failed to get mgmt-sticky reset (ret=%d)\n", ret); + return ret; + } + + ret = reset_get_by_name(dev, "pipe", &priv->pipe_rst); + if (ret) { + dev_err(dev, "failed to get pipe reset (ret=%d)\n", ret); + return ret; + } + + ret = reset_get_by_name(dev, "pm", &priv->pm_rst); + if (ret) { + dev_err(dev, "failed to get pm reset (ret=%d)\n", ret); + return ret; + } + + ret = reset_get_by_name(dev, "pclk", &priv->pclk_rst); + if (ret) { + dev_err(dev, "failed to get pclk reset (ret=%d)\n", ret); + return ret; + } + + ret = reset_get_by_name(dev, "aclk", &priv->aclk_rst); + if (ret) { + dev_err(dev, "failed to get aclk reset (ret=%d)\n", ret); + return ret; + } + + ret = device_get_supply_regulator(dev, "vpcie3v3-supply", + &priv->vpcie3v3); + if (ret && ret != -ENOENT) { + dev_err(dev, "failed to get vpcie3v3 supply (ret=%d)\n", ret); + return ret; + } + + ret = device_get_supply_regulator(dev, "vpcie1v8-supply", + &priv->vpcie1v8); + if (ret) { + dev_err(dev, "failed to get vpcie1v8 supply (ret=%d)\n", ret); + return ret; + } + + ret = device_get_supply_regulator(dev, "vpcie0v9-supply", + &priv->vpcie0v9); + if (ret) { + dev_err(dev, "failed to get vpcie0v9 supply (ret=%d)\n", ret); + return ret; + } + + return 0; +} + +static int rockchip_pcie_probe(struct udevice *dev) +{ + struct rockchip_pcie *priv = dev_get_priv(dev); + struct udevice *ctlr = pci_get_controller(dev); + struct pci_controller *hose = dev_get_uclass_priv(ctlr); + int ret; + + priv->first_busno = dev->seq; + priv->dev = dev; + + ret = rockchip_pcie_parse_dt(dev); + if (ret) + return ret; + + ret = rockchip_pcie_set_vpcie(dev); + if (ret) + return ret; + + ret = rockchip_pcie_init_port(dev); + if (ret) + return ret; + + dev_info(dev, "PCIE-%d: Link up (Bus%d)\n", + dev->seq, hose->first_busno); + + return 0; +} + +static const struct dm_pci_ops rockchip_pcie_ops = { + .read_config = rockchip_pcie_rd_conf, + .write_config = rockchip_pcie_wr_conf, +}; + +static const struct udevice_id rockchip_pcie_ids[] = { + { .compatible = "rockchip,rk3399-pcie" }, + { } +}; + +U_BOOT_DRIVER(rockchip_pcie) = { + .name = "rockchip_pcie", + .id = UCLASS_PCI, + .of_match = rockchip_pcie_ids, + .ops = &rockchip_pcie_ops, + .probe = rockchip_pcie_probe, + .priv_auto_alloc_size = sizeof(struct rockchip_pcie), +}; diff --git a/drivers/pci/pcie_rockchip.h b/drivers/pci/pcie_rockchip.h new file mode 100644 index 0000000000..6ded5c9553 --- /dev/null +++ b/drivers/pci/pcie_rockchip.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Rockchip PCIe Headers + * + * Copyright (c) 2016 Rockchip, Inc. + * Copyright (c) 2020 Amarula Solutions(India) + * Copyright (c) 2020 Jagan Teki + * Copyright (c) 2019 Patrick Wildt + * + */ + +#define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val)) +#define HIWORD_UPDATE_BIT(val) HIWORD_UPDATE(val, val) + +#define ENCODE_LANES(x) ((((x) >> 1) & 3) << 4) +#define PCIE_CLIENT_BASE 0x0 +#define PCIE_CLIENT_CONFIG (PCIE_CLIENT_BASE + 0x00) +#define PCIE_CLIENT_CONF_ENABLE HIWORD_UPDATE_BIT(0x0001) +#define PCIE_CLIENT_LINK_TRAIN_ENABLE HIWORD_UPDATE_BIT(0x0002) +#define PCIE_CLIENT_MODE_RC HIWORD_UPDATE_BIT(0x0040) +#define PCIE_CLIENT_GEN_SEL_1 HIWORD_UPDATE(0x0080, 0) +#define PCIE_CLIENT_BASIC_STATUS1 0x0048 +#define PCIE_CLIENT_LINK_STATUS_UP GENMASK(21, 20) +#define PCIE_CLIENT_LINK_STATUS_MASK GENMASK(21, 20) +#define PCIE_LINK_UP(x) \ + (((x) & PCIE_CLIENT_LINK_STATUS_MASK) == PCIE_CLIENT_LINK_STATUS_UP) +#define PCIE_RC_NORMAL_BASE 0x800000 +#define PCIE_LM_BASE 0x900000 +#define PCIE_LM_VENDOR_ID (PCIE_LM_BASE + 0x44) +#define PCIE_LM_VENDOR_ROCKCHIP 0x1d87 +#define PCIE_LM_RCBAR (PCIE_LM_BASE + 0x300) +#define PCIE_LM_RCBARPIE BIT(19) +#define PCIE_LM_RCBARPIS BIT(20) +#define PCIE_RC_BASE 0xa00000 +#define PCIE_RC_CONFIG_DCR (PCIE_RC_BASE + 0x0c4) +#define PCIE_RC_CONFIG_DCR_CSPL_SHIFT 18 +#define PCIE_RC_CONFIG_DCR_CPLS_SHIFT 26 +#define PCIE_RC_PCIE_LCAP (PCIE_RC_BASE + 0x0cc) +#define PCIE_RC_PCIE_LCAP_APMS_L0S BIT(10) +#define PCIE_ATR_BASE 0xc00000 +#define PCIE_ATR_OB_ADDR0(i) (PCIE_ATR_BASE + 0x000 + (i) * 0x20) +#define PCIE_ATR_OB_ADDR1(i) (PCIE_ATR_BASE + 0x004 + (i) * 0x20) +#define PCIE_ATR_OB_DESC0(i) (PCIE_ATR_BASE + 0x008 + (i) * 0x20) +#define PCIE_ATR_OB_DESC1(i) (PCIE_ATR_BASE + 0x00c + (i) * 0x20) +#define PCIE_ATR_IB_ADDR0(i) (PCIE_ATR_BASE + 0x800 + (i) * 0x8) +#define PCIE_ATR_IB_ADDR1(i) (PCIE_ATR_BASE + 0x804 + (i) * 0x8) +#define PCIE_ATR_HDR_MEM 0x2 +#define PCIE_ATR_HDR_IO 0x6 +#define PCIE_ATR_HDR_CFG_TYPE0 0xa +#define PCIE_ATR_HDR_CFG_TYPE1 0xb +#define PCIE_ATR_HDR_RID BIT(23) + +#define PCIE_ATR_OB_REGION0_SIZE (32 * 1024 * 1024) +#define PCIE_ATR_OB_REGION_SIZE (1 * 1024 * 1024) + +struct rockchip_pcie { + fdt_addr_t axi_base; + fdt_addr_t apb_base; + int first_busno; + struct udevice *dev; + + /* resets */ + struct reset_ctl core_rst; + struct reset_ctl mgmt_rst; + struct reset_ctl mgmt_sticky_rst; + struct reset_ctl pipe_rst; + struct reset_ctl pm_rst; + struct reset_ctl pclk_rst; + struct reset_ctl aclk_rst; + + /* gpio */ + struct gpio_desc ep_gpio; + + /* vpcie regulators */ + struct udevice *vpcie12v; + struct udevice *vpcie3v3; + struct udevice *vpcie1v8; + struct udevice *vpcie0v9; +};