Received: by 2002:a05:6a10:f347:0:0:0:0 with SMTP id d7csp11182986pxu; Thu, 31 Dec 2020 02:21:40 -0800 (PST) X-Google-Smtp-Source: ABdhPJwCqUsRrTf7jcLr3J+BCiDyH8+ntZfsUFW35TIVWP6OjAs7sslusVGcucKuGhowqpCLt9ua X-Received: by 2002:a50:8e19:: with SMTP id 25mr52335382edw.263.1609410100588; Thu, 31 Dec 2020 02:21:40 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1609410100; cv=none; d=google.com; s=arc-20160816; b=RGqQxgKSQqY18kOKC27ZrS3TrwgsQocKTZtTXTxI7RXWjyzNcExH/D1DKZDgNxMzNT yp9/DhPIxS+lEjV2V5fnvAEUAuS8CegTEnB59wxuwzhXFEeqtdwnoFZD3Oymr8LRqq+e oBiQXSIyz86+/BNpWLh6BG8+zTD5T2wrjVGPHLk3piOLO8a5TBksCxxYkDxgOlLE7wLN pNA9YLSJjKdoxAhwGgOEvvWeHALTj47D5Q/8i3jAzFSV2Iuyz3XWirBXBCTmdOeGExaz pCykp+wcmsLnoUoc0F6x5vwbLJsuTmGmeJiO9luas54sTx3XXjLV+ehgBDfHrkd2CkJ1 BE4w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from:dkim-signature; bh=Xw698ctg4Ze5W/87ncdseRGuPD3JOZ7supZFvs8H2cs=; b=d8bQ+F9k0Vcn7YpISZexx1ydMgmyhG30iYBEqVIvkeW8mgQblNdT2rrohEVfJp1+jb 4AaHKDDHrwvs9Lj22obqYoxSRGzgFrZlhizkxk1gL8N6COzbVAe9QoP7CHUOMQwA0HhF c+J1ZdnoSBbrSpcXTbheSchNHoFtbA0JJTABe0qIJcKhRIOnj8YW02I35ykP6OpQtFtb Sp/yajvOEkcEW9SL6R/v9BYoqBmgWQGXQf/conoknBTJBoVMevmM6wLk7czcLfBB8B0S Nk5bJE4SzCbeXdpehE+b1cxedIZFSN0aWyVmbovb3ve828SEg7i4jgmwj3MtcdW03anR pRVQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=GnESWj2j; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id c23si21135760eds.525.2020.12.31.02.21.18; Thu, 31 Dec 2020 02:21:40 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=GnESWj2j; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726539AbgLaKT0 (ORCPT + 99 others); Thu, 31 Dec 2020 05:19:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37840 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726155AbgLaKTZ (ORCPT ); Thu, 31 Dec 2020 05:19:25 -0500 Received: from mail-pf1-x42c.google.com (mail-pf1-x42c.google.com [IPv6:2607:f8b0:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 14F66C061799; Thu, 31 Dec 2020 02:18:45 -0800 (PST) Received: by mail-pf1-x42c.google.com with SMTP id t8so11060488pfg.8; Thu, 31 Dec 2020 02:18:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Xw698ctg4Ze5W/87ncdseRGuPD3JOZ7supZFvs8H2cs=; b=GnESWj2jam8dYagjQrsGx+sfk6YpRaQ5Pk2awXCQY4gXnSdrRzX2hfcmEU+3yuQyGw pjPX1tjVCnxUXNO2gnoht0RiOA4diL3wSiVmpJS/GTNsxzFk9/KtY7yvRHSI0Q7Yk/po NU7DREleeXy1QDrkjGGnvnrTm4YQkUypwtv2gQhDdcnXg73M76IdkLiHboIs6g8anANo QfFvPSVPf2ZyOb0+W4qZoY4QjcwGFhBdTNfIJm4gseruH2/u5+CopfX6TzG3nQzdXyGb IrlrwagjUXhuTSiCqu0TIysi4DV5Z0qL0Rn402iNZ6DS8QoQdUNnJXwsKkrQsp/i0gNc U6uA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Xw698ctg4Ze5W/87ncdseRGuPD3JOZ7supZFvs8H2cs=; b=MD0x8YQi9lr1X3e3HntCqg+9UXlTHLyLjZ+b9ilmsO4sHjiJFrGM4HeenI++i6W++/ tAu1aGUfkljYsK6vKPP0Ta1dC4gKo+JQwa5SnLuW+pX2mwmt0yKM+erKY+jVeQToowhy AMZd27jgLXlzHlTqSUX9zOtZdAH8WQEulzavaa+n9FHatsm0h0UW5L6q1RxbzIrrN+oZ QO4FZyTtDmTdLFElrd3HDM/dRFdmRWf/SKfEGtJhozq3wBVWyIOFLvppwqOw3zUABe9J sQEOHJ8P5ukEoTj8Qv6LJwYQPzyOK5bmlTZVtQFEbmkTQCKff8rH3iLFb4t7KuWHpR23 K/dg== X-Gm-Message-State: AOAM5334sRrRgp9cNdVDSo6AqhYqkmXg3GQ7SitZNlsEx/WUIbhBcBku 88pasl6Ow95MKnbdgANTFZk= X-Received: by 2002:a62:7d90:0:b029:19d:917b:6c65 with SMTP id y138-20020a627d900000b029019d917b6c65mr31766577pfc.28.1609409924556; Thu, 31 Dec 2020 02:18:44 -0800 (PST) Received: from sh05419pcu.spreadtrum.com ([117.18.48.82]) by smtp.gmail.com with ESMTPSA id a141sm45470937pfa.189.2020.12.31.02.18.40 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 31 Dec 2020 02:18:43 -0800 (PST) From: Hongtao Wu To: Lorenzo Pieralisi , Rob Herring Cc: Orson Zhai , Baolin Wang , Chunyan Zhang , linux-pci@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Hongtao Wu Subject: [PATCH v5 2/2] PCI: sprd: Add support for Unisoc SoCs' PCIe controller Date: Thu, 31 Dec 2020 18:18:25 +0800 Message-Id: <1609409905-30721-3-git-send-email-wuht06@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1609409905-30721-1-git-send-email-wuht06@gmail.com> References: <1609409905-30721-1-git-send-email-wuht06@gmail.com> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Hongtao Wu This series adds PCIe controller driver for Unisoc SoCs. This controller is based on DesignWare PCIe IP. Signed-off-by: Hongtao Wu --- drivers/pci/controller/dwc/Kconfig | 12 ++ drivers/pci/controller/dwc/Makefile | 1 + drivers/pci/controller/dwc/pcie-sprd.c | 293 +++++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+) create mode 100644 drivers/pci/controller/dwc/pcie-sprd.c diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 22c5529..61f0b79 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -318,4 +318,16 @@ config PCIE_AL required only for DT-based platforms. ACPI platforms with the Annapurna Labs PCIe controller don't need to enable this. +config PCIE_SPRD + tristate "Unisoc PCIe controller - Host Mode" + depends on ARCH_SPRD || COMPILE_TEST + depends on PCI_MSI_IRQ_DOMAIN + select PCIE_DW_HOST + help + Unisoc PCIe controller uses the DesignWare core. It can be configured + as an Endpoint (EP) or a Root complex (RC). In order to enable host + mode (the controller works as RC), PCIE_SPRD must be selected. + Say Y or M here if you want to PCIe RC controller support on Unisoc + SoCs. + endmenu diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile index a751553..eb546e9 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_PCIE_SPRD) += pcie-sprd.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-sprd.c b/drivers/pci/controller/dwc/pcie-sprd.c new file mode 100644 index 0000000..27d7231 --- /dev/null +++ b/drivers/pci/controller/dwc/pcie-sprd.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCIe host controller driver for Unisoc SoCs + * + * Copyright (C) 2020-2021 Unisoc, Inc. + * + * Author: Hongtao Wu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie-designware.h" + +/* aon apb syscon */ +#define IPA_ACCESS_CFG 0xcd8 +#define AON_ACCESS_PCIE_EN BIT(1) + +/* pmu apb syscon */ +#define SNPS_PCIE3_SLP_CTRL 0xac +#define PERST_N_ASSERT BIT(1) +#define PERST_N_AUTO_EN BIT(0) +#define PD_PCIE_CFG_0 0x3e8 +#define PCIE_FORCE_SHUTDOWN BIT(25) + +#define PCIE_SS_REG_BASE 0xE00 +#define APB_CLKFREQ_TIMEOUT 0x4 +#define BUSERR_EN BIT(12) +#define APB_TIMER_DIS BIT(10) +#define APB_TIMER_LIMIT GENMASK(31, 16) + +#define PE0_GEN_CTRL_3 0x58 +#define LTSSM_EN BIT(0) + +struct sprd_pcie_soc_data { + u32 syscon_offset; +}; + +static const struct sprd_pcie_soc_data ums9520_syscon_data = { + .syscon_offset = 0x1000, /* The offset of set/clear register */ +}; + +struct sprd_pcie { + u32 syscon_offset; + struct device *dev; + struct dw_pcie *pci; + struct regmap *aon_map; + struct regmap *pmu_map; + const struct sprd_pcie_soc_data *socdata; +}; + +enum sprd_pcie_syscon_type { + normal_syscon, /* it's not a set/clear register */ + set_syscon, /* set a set/clear register */ + clr_syscon, /* clear a set/clear register */ +}; + +static void sprd_pcie_buserr_enable(struct dw_pcie *pci) +{ + u32 val; + + val = dw_pcie_readl_dbi(pci, PCIE_SS_REG_BASE + APB_CLKFREQ_TIMEOUT); + val &= ~APB_TIMER_DIS; + val |= BUSERR_EN; + val |= APB_TIMER_LIMIT & (0x1f4 << 16); + dw_pcie_writel_dbi(pci, PCIE_SS_REG_BASE + APB_CLKFREQ_TIMEOUT, val); +} + +static void sprd_pcie_ltssm_enable(struct dw_pcie *pci, bool enable) +{ + u32 val; + + val = dw_pcie_readl_dbi(pci, PCIE_SS_REG_BASE + PE0_GEN_CTRL_3); + if (enable) + dw_pcie_writel_dbi(pci, PCIE_SS_REG_BASE + PE0_GEN_CTRL_3, + val | LTSSM_EN); + else + dw_pcie_writel_dbi(pci, PCIE_SS_REG_BASE + PE0_GEN_CTRL_3, + val & ~LTSSM_EN); +} + +static int sprd_pcie_syscon_set(struct sprd_pcie *ctrl, struct regmap *map, + u32 reg, u32 mask, u32 val, + enum sprd_pcie_syscon_type type) +{ + int ret = 0; + u32 read_val; + u32 offset = ctrl->syscon_offset; + struct device *dev = ctrl->pci->dev; + + /* + * Each set/clear register has three registers: + * reg: base register + * reg + offset: set register + * reg + offset * 2: clear register + */ + switch (type) { + case normal_syscon: + ret = regmap_read(map, reg, &read_val); + if (ret) { + dev_err(dev, "failed to read register 0x%x\n", reg); + return ret; + } + read_val &= ~mask; + read_val |= (val & mask); + ret = regmap_write(map, reg, read_val); + break; + case set_syscon: + reg = reg + offset; + ret = regmap_write(map, reg, val); + break; + case clr_syscon: + reg = reg + offset * 2; + ret = regmap_write(map, reg, val); + break; + default: + break; + } + + if (ret) + dev_err(dev, "failed to write register 0x%x\n", reg); + + return ret; +} + +static int sprd_pcie_perst_assert(struct sprd_pcie *ctrl) +{ + return sprd_pcie_syscon_set(ctrl, ctrl->pmu_map, SNPS_PCIE3_SLP_CTRL, + PERST_N_ASSERT, PERST_N_ASSERT, set_syscon); +} + +static int sprd_pcie_perst_deassert(struct sprd_pcie *ctrl) +{ + int ret; + + ret = sprd_pcie_syscon_set(ctrl, ctrl->pmu_map, SNPS_PCIE3_SLP_CTRL, + PERST_N_ASSERT, 0, clr_syscon); + usleep_range(2000, 3000); + + return ret; +} + +static int sprd_pcie_power_on(struct platform_device *pdev) +{ + int ret; + struct sprd_pcie *ctrl = platform_get_drvdata(pdev); + struct dw_pcie *pci = ctrl->pci; + + ret = sprd_pcie_syscon_set(ctrl, ctrl->aon_map, PD_PCIE_CFG_0, + PCIE_FORCE_SHUTDOWN, 0, clr_syscon); + if (ret) + return ret; + + ret = sprd_pcie_syscon_set(ctrl, ctrl->aon_map, IPA_ACCESS_CFG, + AON_ACCESS_PCIE_EN, AON_ACCESS_PCIE_EN, + set_syscon); + if (ret) + return ret; + + ret = sprd_pcie_perst_deassert(ctrl); + if (ret) + return ret; + + sprd_pcie_buserr_enable(pci); + sprd_pcie_ltssm_enable(pci, true); + + return ret; +} + +static int sprd_pcie_power_off(struct platform_device *pdev) +{ + struct sprd_pcie *ctrl = platform_get_drvdata(pdev); + struct dw_pcie *pci = ctrl->pci; + + sprd_pcie_ltssm_enable(pci, false); + + sprd_pcie_perst_assert(ctrl); + sprd_pcie_syscon_set(ctrl, ctrl->aon_map, PD_PCIE_CFG_0, + PCIE_FORCE_SHUTDOWN, PCIE_FORCE_SHUTDOWN, + set_syscon); + sprd_pcie_syscon_set(ctrl, ctrl->aon_map, IPA_ACCESS_CFG, + AON_ACCESS_PCIE_EN, 0, clr_syscon); + + return 0; +} + +static int sprd_add_pcie_port(struct platform_device *pdev) +{ + struct sprd_pcie *ctrl = platform_get_drvdata(pdev); + struct dw_pcie *pci = ctrl->pci; + struct pcie_port *pp = &pci->pp; + + return dw_pcie_host_init(pp); +} + +static int sprd_pcie_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sprd_pcie *ctrl; + struct dw_pcie *pci; + int ret; + + ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + ctrl->socdata = + (struct sprd_pcie_soc_data *)of_device_get_match_data(dev); + if (!ctrl->socdata) { + dev_warn(dev, + "using the default set/clear register offset address"); + ctrl->syscon_offset = 0x1000; + } + ctrl->syscon_offset = ctrl->socdata->syscon_offset; + + ctrl->aon_map = syscon_regmap_lookup_by_phandle(dev->of_node, + "sprd, regmap-aon"); + if (IS_ERR(ctrl->aon_map)) { + dev_err(dev, "failed to get syscon regmap aon\n"); + ret = PTR_ERR(ctrl->aon_map); + goto err; + } + + ctrl->pmu_map = syscon_regmap_lookup_by_phandle(dev->of_node, + "sprd, regmap-pmu"); + if (IS_ERR(ctrl->pmu_map)) { + dev_err(dev, "failed to get syscon regmap pmu\n"); + ret = PTR_ERR(ctrl->pmu_map); + goto err; + } + + pci = ctrl->pci; + pci->dev = dev; + + platform_set_drvdata(pdev, ctrl); + + ret = sprd_pcie_power_on(pdev); + if (ret < 0) { + dev_err(dev, "failed to power on, return %d\n", + ret); + goto err_power_off; + } + + ret = sprd_add_pcie_port(pdev); + if (ret) { + dev_warn(dev, "failed to initialize RC controller\n"); + return ret; + } + + return 0; + +err_power_off: + sprd_pcie_power_off(pdev); +err: + return ret; +} + +static int sprd_pcie_remove(struct platform_device *pdev) +{ + sprd_pcie_power_off(pdev); + + return 0; +} + +static const struct of_device_id sprd_pcie_of_match[] = { + { + .compatible = "sprd,ums9520-pcie", + .data = &ums9520_syscon_data, + }, + {}, +}; + +static struct platform_driver sprd_pcie_driver = { + .probe = sprd_pcie_probe, + .remove = __exit_p(sprd_pcie_remove), + .driver = { + .name = "sprd-pcie", + .of_match_table = sprd_pcie_of_match, + }, +}; + +module_platform_driver(sprd_pcie_driver); + +MODULE_DESCRIPTION("Unisoc PCIe host controller driver"); +MODULE_LICENSE("GPL v2"); -- 2.7.4