From patchwork Thu Mar 25 14:49:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neil Armstrong X-Patchwork-Id: 1458385 X-Patchwork-Delegate: bmeng.cn@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=baylibre-com.20150623.gappssmtp.com header.i=@baylibre-com.20150623.gappssmtp.com header.a=rsa-sha256 header.s=20150623 header.b=nsfn6gI2; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F5p0y0Lnyz9sVt for ; Fri, 26 Mar 2021 01:49:54 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 134228284D; Thu, 25 Mar 2021 15:49:46 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=baylibre-com.20150623.gappssmtp.com header.i=@baylibre-com.20150623.gappssmtp.com header.b="nsfn6gI2"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 316E782857; Thu, 25 Mar 2021 15:49:41 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id D9727805BF for ; Thu, 25 Mar 2021 15:49:36 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=narmstrong@baylibre.com Received: by mail-wr1-x42c.google.com with SMTP id j7so2592376wrd.1 for ; Thu, 25 Mar 2021 07:49:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=UyFL3Et2tGewSYwqZVxvdZ97ADu3vFCD9YHkTH1+L08=; b=nsfn6gI2s5VleEmxtfgIkGL0AL29gspjiHLHSIbjeoqZU6t1WNG+IoXZwSavnoCQO1 T8UhJtg5/4KclefJf9jp43VVOGEKohj7ea7WjWMw3ncIoeJ+s74FPFkiWAzgWECr1O6E JBdQJUKDSzL/kL4xuXpkWEEhi2UswdVxOrH6tNAA4HO2qEJAjGxq32GcZnV4fHaTgNDg e9psUJlWkC6TgR5t5hzBFzHvG8AeZLBadZovXIqU3Q1j1qk+Uit3DNQGbS4XnLeM82dD lCRg2YkraLeE+MBT2G4AlP1sbOmPbgVd9h+BGusIGhEqGVFuOYHqBmHsHLzw25knnyG4 dY+w== 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:mime-version:content-transfer-encoding; bh=UyFL3Et2tGewSYwqZVxvdZ97ADu3vFCD9YHkTH1+L08=; b=OHVL7dcP2ZQGT6CcVK4deISokUItB+DqTCYX6js98i/hyvEqo1+qaZmttyk0mGet9c Ih7C6fD2K/eRLaYMADGufB/NozrH4xS9PWQhu/+bZT3X6Nn3hsInDDLQ7FZmDuWTq0vg oM4wqYnWt/GwgXeBi/DKC6mOQYjt8r4eoqijHQ55KwQpdo0w+ZU/2+o1jGZPA0+KnRpe 9ayPDLN0VdYiymcK3HM2LFa5C9czsBluecOHHlpcIHhUvbtVORJdgq9ZXrR6KZBJ6RE3 5oE7JJwq06tR5xeBqhWaHvS00YJTKpY5CYgfjck3HUOXvHc6EdwDRIcEi1b4kPapIlYz egzA== X-Gm-Message-State: AOAM531bDc0i7PcQnIA6q7j/gqptgmruus/j7KkK0LZxInvz5gj2VyLx OGr42ufJzGc2IRVw98FHKumQug== X-Google-Smtp-Source: ABdhPJzOhsLcC6LLbjRnzP0oBfI5+VL1oFtfYn+CtDDPdhZiLdhfPHCJbUhlxlD24HI6WeBNJLEVIw== X-Received: by 2002:adf:e791:: with SMTP id n17mr9308693wrm.322.1616683776252; Thu, 25 Mar 2021 07:49:36 -0700 (PDT) Received: from localhost.localdomain ([2a01:e0a:90c:e290:b105:9672:b0a:5820]) by smtp.gmail.com with ESMTPSA id w6sm7787727wrl.49.2021.03.25.07.49.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Mar 2021 07:49:35 -0700 (PDT) From: Neil Armstrong To: lokeshvutla@ti.com, nsekhar@ti.com, shawn.lin@rock-chips.com, bmeng.cn@gmail.com, green.wan@sifive.com Cc: u-boot@lists.denx.de, u-boot-amlogic@groups.io, Neil Armstrong Subject: [PATCH RFT v2 1/4] pci: add common Designware PCIe functions Date: Thu, 25 Mar 2021 15:49:18 +0100 Message-Id: <20210325144921.1791892-2-narmstrong@baylibre.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210325144921.1791892-1-narmstrong@baylibre.com> References: <20210325144921.1791892-1-narmstrong@baylibre.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.4 at phobos.denx.de X-Virus-Status: Clean With the introduction of pcie_dw_rockchip, and need to support the DW PCIe in the Amlogic AXG & G12 SoCs, most of the DW PCIe helpers would be duplicated. This introduce a "common" DW PCIe helpers file with common code merged from the dw_ti and dw_rockchip drivers and adapted to fit with the upcoming dw_meson. The following changes will switch the dw_ti and dw_rockchip to use these helpers. Signed-off-by: Neil Armstrong Tested-by: Green Wan --- drivers/pci/Kconfig | 4 + drivers/pci/Makefile | 1 + drivers/pci/pcie_dw_common.c | 366 +++++++++++++++++++++++++++++++++++ drivers/pci/pcie_dw_common.h | 155 +++++++++++++++ 4 files changed, 526 insertions(+) create mode 100644 drivers/pci/pcie_dw_common.c create mode 100644 drivers/pci/pcie_dw_common.h diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index ba41787f64..ab5a5e7ed6 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -258,6 +258,10 @@ config PCI_MVEBU Say Y here if you want to enable PCIe controller support on Armada XP/38x SoCs. +config PCIE_DW_COMMON + bool + select DM_PCI + config PCI_KEYSTONE bool "TI Keystone PCIe controller" depends on DM_PCI diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 5ed94bc95c..e3ca8b27e4 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o +obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.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_dw_common.c b/drivers/pci/pcie_dw_common.c new file mode 100644 index 0000000000..7c92b7b754 --- /dev/null +++ b/drivers/pci/pcie_dw_common.c @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 BayLibre, SAS + * Author: Neil Armstrong + * + * Copyright (c) 2021 Rockchip, Inc. + * + * Copyright (C) 2018 Texas Instruments, Inc + */ + +#include +#include +#include +#include +#include +#include +#include +#include "pcie_dw_common.h" + +int pcie_dw_get_link_speed(struct pcie_dw *pci) +{ + return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) & + PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF; +} + +int pcie_dw_get_link_width(struct pcie_dw *pci) +{ + return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) & + PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF; +} + +static void dw_pcie_writel_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg, + u32 val) +{ + u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); + void __iomem *base = pci->atu_base; + + writel(val, base + offset + reg); +} + +static u32 dw_pcie_readl_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg) +{ + u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); + void __iomem *base = pci->atu_base; + + return readl(base + offset + reg); +} + +/** + * pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses + * + * @pcie: Pointer to the PCI controller state + * @index: ATU region index + * @type: ATU accsess type + * @cpu_addr: the physical address for the translation entry + * @pci_addr: the pcie bus address for the translation entry + * @size: the size of the translation entry + * + * Return: 0 is successful and -1 is failure + */ +int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index, + int type, u64 cpu_addr, + u64 pci_addr, u32 size) +{ + u32 retries, val; + + dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n", + index, type, cpu_addr, pci_addr, size); + + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, + lower_32_bits(cpu_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, + upper_32_bits(cpu_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT, + lower_32_bits(cpu_addr + size - 1)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, + lower_32_bits(pci_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, + upper_32_bits(pci_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, + type); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, + PCIE_ATU_ENABLE); + + /* + * Make sure ATU enable takes effect before any subsequent config + * and I/O accesses. + */ + for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { + val = dw_pcie_readl_ob_unroll(pci, index, + PCIE_ATU_UNR_REGION_CTRL2); + if (val & PCIE_ATU_ENABLE) + return 0; + + udelay(LINK_WAIT_IATU); + } + dev_err(pci->dev, "outbound iATU is not being enabled\n"); + + return -1; +} + +/** + * set_cfg_address() - Configure the PCIe controller config space access + * + * @pcie: Pointer to the PCI controller state + * @d: PCI device to access + * @where: Offset in the configuration space + * + * Configures the PCIe controller to access the configuration space of + * a specific PCIe device and returns the address to use for this + * access. + * + * Return: Address that can be used to access the configation space + * of the requested device / offset + */ +static uintptr_t set_cfg_address(struct pcie_dw *pcie, + pci_dev_t d, uint where) +{ + int bus = PCI_BUS(d) - pcie->first_busno; + uintptr_t va_address; + u32 atu_type; + int ret; + + /* Use dbi_base for own configuration read and write */ + if (!bus) { + va_address = (uintptr_t)pcie->dbi_base; + goto out; + } + + if (bus == 1) + /* + * For local bus whose primary bus number is root bridge, + * change TLP Type field to 4. + */ + atu_type = PCIE_ATU_TYPE_CFG0; + else + /* Otherwise, change TLP Type field to 5. */ + atu_type = PCIE_ATU_TYPE_CFG1; + + /* + * Not accessing root port configuration space? + * Region #0 is used for Outbound CFG space access. + * Direction = Outbound + * Region Index = 0 + */ + d = PCI_MASK_BUS(d); + d = PCI_ADD_BUS(bus, d); + ret = pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1, + atu_type, (u64)pcie->cfg_base, + d << 8, pcie->cfg_size); + if (ret) + return (uintptr_t)ret; + + va_address = (uintptr_t)pcie->cfg_base; + +out: + va_address += where & ~0x3; + + return va_address; +} + +/** + * pcie_dw_addr_valid() - Check for valid bus address + * + * @d: The PCI device to access + * @first_busno: Bus number of the PCIe controller root complex + * + * Return 1 (true) if the PCI device can be accessed by this controller. + * + * Return: 1 on valid, 0 on invalid + */ +static int pcie_dw_addr_valid(pci_dev_t d, int first_busno) +{ + if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0)) + return 0; + if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0)) + return 0; + + return 1; +} + +/** + * pcie_dw_read_config() - Read from configuration space + * + * @bus: Pointer to the PCI bus + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @valuep: A pointer at which to store the read value + * @size: Indicates the size of access to perform + * + * Read a value of size @size from offset @offset within the configuration + * space of the device identified by the bus, device & function numbers in @bdf + * on the PCI bus @bus. + * + * Return: 0 on success + */ +int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + struct pcie_dw *pcie = dev_get_priv(bus); + uintptr_t va_address; + ulong value; + + dev_dbg(pcie->dev, "PCIE CFG read: bdf=%2x:%2x:%2x ", + PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); + + if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) { + debug("- out of range\n"); + *valuep = pci_get_ff(size); + return 0; + } + + va_address = set_cfg_address(pcie, bdf, offset); + + value = readl(va_address); + + debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); + *valuep = pci_conv_32_to_size(value, offset, size); + + return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_IO, pcie->io.phys_start, + pcie->io.bus_start, pcie->io.size); +} + +/** + * pcie_dw_write_config() - Write to configuration space + * + * @bus: Pointer to the PCI bus + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @value: The value to write + * @size: Indicates the size of access to perform + * + * Write the value @value of size @size from offset @offset within the + * configuration space of the device identified by the bus, device & function + * numbers in @bdf on the PCI bus @bus. + * + * Return: 0 on success + */ +int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + struct pcie_dw *pcie = dev_get_priv(bus); + uintptr_t va_address; + ulong old; + + dev_dbg(pcie->dev, "PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ", + PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); + dev_dbg(pcie->dev, "(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); + + if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) { + debug("- out of range\n"); + return 0; + } + + va_address = set_cfg_address(pcie, bdf, offset); + + old = readl(va_address); + value = pci_conv_size_to_32(old, value, offset, size); + writel(value, va_address); + + return pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_IO, pcie->io.phys_start, + pcie->io.bus_start, pcie->io.size); +} + +/** + * pcie_dw_setup_host() - Setup the PCIe controller for RC opertaion + * + * @pcie: Pointer to the PCI controller state + * + * Configure the host BARs of the PCIe controller root port so that + * PCI(e) devices may access the system memory. + */ +void pcie_dw_setup_host(struct pcie_dw *pci) +{ + struct udevice *ctlr = pci_get_controller(pci->dev); + struct pci_controller *hose = dev_get_uclass_priv(ctlr); + u32 ret; + + if (!pci->atu_base) + pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; + + /* setup RC BARs */ + writel(PCI_BASE_ADDRESS_MEM_TYPE_64, + pci->dbi_base + PCI_BASE_ADDRESS_0); + writel(0x0, pci->dbi_base + PCI_BASE_ADDRESS_1); + + /* setup interrupt pins */ + clrsetbits_le32(pci->dbi_base + PCI_INTERRUPT_LINE, + 0xff00, 0x100); + + /* setup bus numbers */ + clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS, + 0xffffff, 0x00ff0100); + + /* setup command register */ + clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS, + 0xffff, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_SERR); + + /* Enable write permission for the DBI read-only register */ + dw_pcie_dbi_write_enable(pci, true); + /* program correct class for RC */ + writew(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE); + /* Better disable write permission right after the update */ + dw_pcie_dbi_write_enable(pci, false); + + setbits_le32(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL, + PORT_LOGIC_SPEED_CHANGE); + + for (ret = 0; ret < hose->region_count; ret++) { + if (hose->regions[ret].flags == PCI_REGION_IO) { + pci->io.phys_start = hose->regions[ret].phys_start; /* IO base */ + pci->io.bus_start = hose->regions[ret].bus_start; /* IO_bus_addr */ + pci->io.size = hose->regions[ret].size; /* IO size */ + } else if (hose->regions[ret].flags == PCI_REGION_MEM) { + pci->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */ + pci->mem.bus_start = hose->regions[ret].bus_start; /* MEM_bus_addr */ + pci->mem.size = hose->regions[ret].size; /* MEM size */ + } else if (hose->regions[ret].flags == PCI_REGION_PREFETCH) { + pci->prefetch.phys_start = hose->regions[ret].phys_start; /* PREFETCH base */ + pci->prefetch.bus_start = hose->regions[ret].bus_start; /* PREFETCH_bus_addr */ + pci->prefetch.size = hose->regions[ret].size; /* PREFETCH size */ + } else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) { + pci->cfg_base = (void *)(pci->io.phys_start - pci->io.size); + pci->cfg_size = pci->io.size; + } else { + dev_err(pci->dev, "invalid flags type!\n"); + } + } + + dev_dbg(pci->dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n", + pci->cfg_base, pci->cfg_base + pci->cfg_size, + pci->cfg_size); + + dev_dbg(pci->dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n", + pci->io.phys_start, pci->io.phys_start + pci->io.size, + pci->io.size); + + dev_dbg(pci->dev, "IO bus: [0x%lx - 0x%lx, size 0x%lx]\n", + pci->io.bus_start, pci->io.bus_start + pci->io.size, + pci->io.size); + + dev_dbg(pci->dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n", + pci->mem.phys_start, pci->mem.phys_start + pci->mem.size, + pci->mem.size); + + dev_dbg(pci->dev, "MEM bus: [0x%lx - 0x%lx, size 0x%lx]\n", + pci->mem.bus_start, pci->mem.bus_start + pci->mem.size, + pci->mem.size); + + if (pci->prefetch.size) { + dev_dbg(pci->dev, "PREFETCH space: [0x%llx - 0x%llx, size 0x%lx]\n", + pci->prefetch.phys_start, pci->prefetch.phys_start + pci->prefetch.size, + pci->prefetch.size); + + dev_dbg(pci->dev, "PREFETCH bus: [0x%lx - 0x%lx, size 0x%lx]\n", + pci->prefetch.bus_start, pci->prefetch.bus_start + pci->prefetch.size, + pci->prefetch.size); + } +} + diff --git a/drivers/pci/pcie_dw_common.h b/drivers/pci/pcie_dw_common.h new file mode 100644 index 0000000000..6b701645af --- /dev/null +++ b/drivers/pci/pcie_dw_common.h @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2021 BayLibre, SAS + * Author: Neil Armstrong + * + * Copyright (c) 2021 Rockchip, Inc. + * + * Copyright (C) 2018 Texas Instruments, Inc + */ + +#ifndef PCIE_DW_COMMON_H +#define PCIE_DW_COMMON_H + +#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20) + +/* PCI DBICS registers */ +#define PCIE_LINK_STATUS_REG 0x80 +#define PCIE_LINK_STATUS_SPEED_OFF 16 +#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF) +#define PCIE_LINK_STATUS_WIDTH_OFF 20 +#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF) + +/* + * iATU Unroll-specific register definitions + * From 4.80 core version the address translation will be made by unroll. + * The registers are offset from atu_base + */ +#define PCIE_ATU_UNR_REGION_CTRL1 0x00 +#define PCIE_ATU_UNR_REGION_CTRL2 0x04 +#define PCIE_ATU_UNR_LOWER_BASE 0x08 +#define PCIE_ATU_UNR_UPPER_BASE 0x0c +#define PCIE_ATU_UNR_LIMIT 0x10 +#define PCIE_ATU_UNR_LOWER_TARGET 0x14 +#define PCIE_ATU_UNR_UPPER_TARGET 0x18 + +#define PCIE_ATU_REGION_INDEX1 (0x1 << 0) +#define PCIE_ATU_REGION_INDEX0 (0x0 << 0) +#define PCIE_ATU_TYPE_MEM (0x0 << 0) +#define PCIE_ATU_TYPE_IO (0x2 << 0) +#define PCIE_ATU_TYPE_CFG0 (0x4 << 0) +#define PCIE_ATU_TYPE_CFG1 (0x5 << 0) +#define PCIE_ATU_ENABLE (0x1 << 31) +#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) +#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24) +#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19) +#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16) + +/* Register address builder */ +#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((region) << 9) + +/* Parameters for the waiting for iATU enabled routine */ +#define LINK_WAIT_MAX_IATU_RETRIES 5 +#define LINK_WAIT_IATU_US 10000 + +/* PCI DBICS registers */ +#define PCIE_LINK_STATUS_REG 0x80 +#define PCIE_LINK_STATUS_SPEED_OFF 16 +#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF) +#define PCIE_LINK_STATUS_WIDTH_OFF 20 +#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF) + +#define PCIE_LINK_CAPABILITY 0x7c +#define PCIE_LINK_CTL_2 0xa0 +#define TARGET_LINK_SPEED_MASK 0xf +#define LINK_SPEED_GEN_1 0x1 +#define LINK_SPEED_GEN_2 0x2 +#define LINK_SPEED_GEN_3 0x3 + +/* Synopsys-specific PCIe configuration registers */ +#define PCIE_PORT_LINK_CONTROL 0x710 +#define PORT_LINK_DLL_LINK_EN BIT(5) +#define PORT_LINK_FAST_LINK_MODE BIT(7) +#define PORT_LINK_MODE_MASK GENMASK(21, 16) +#define PORT_LINK_MODE(n) FIELD_PREP(PORT_LINK_MODE_MASK, n) +#define PORT_LINK_MODE_1_LANES PORT_LINK_MODE(0x1) +#define PORT_LINK_MODE_2_LANES PORT_LINK_MODE(0x3) +#define PORT_LINK_MODE_4_LANES PORT_LINK_MODE(0x7) +#define PORT_LINK_MODE_8_LANES PORT_LINK_MODE(0xf) + +#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C +#define PORT_LOGIC_N_FTS_MASK GENMASK(7, 0) +#define PORT_LOGIC_SPEED_CHANGE BIT(17) +#define PORT_LOGIC_LINK_WIDTH_MASK GENMASK(12, 8) +#define PORT_LOGIC_LINK_WIDTH(n) FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n) +#define PORT_LOGIC_LINK_WIDTH_1_LANES PORT_LOGIC_LINK_WIDTH(0x1) +#define PORT_LOGIC_LINK_WIDTH_2_LANES PORT_LOGIC_LINK_WIDTH(0x2) +#define PORT_LOGIC_LINK_WIDTH_4_LANES PORT_LOGIC_LINK_WIDTH(0x4) +#define PORT_LOGIC_LINK_WIDTH_8_LANES PORT_LOGIC_LINK_WIDTH(0x8) + +#define PCIE_MISC_CONTROL_1_OFF 0x8bc +#define PCIE_DBI_RO_WR_EN BIT(0) + +/* Parameters for the waiting for iATU enabled routine */ +#define LINK_WAIT_MAX_IATU_RETRIES 5 +#define LINK_WAIT_IATU 10000 + +/** + * struct pcie_dw - DW PCIe controller state + * + * @dbi_base: The base address of dbi register space + * @cfg_base: The base address of configuration space + * @atu_base: The base address of ATU space + * @cfg_size: The size of the configuration space which is needed + * as it gets written into the PCIE_ATU_LIMIT register + * @first_busno: This driver supports multiple PCIe controllers. + * first_busno stores the bus number of the PCIe root-port + * number which may vary depending on the PCIe setup + * (PEX switches etc). + * @io: The IO space for EP's BAR + * @mem: The memory space for EP's BAR + * @prefetch: The prefetch space for EP's BAR + */ +struct pcie_dw { + struct udevice *dev; + void __iomem *dbi_base; + void __iomem *cfg_base; + void __iomem *atu_base; + fdt_size_t cfg_size; + + int first_busno; + + /* IO, MEM & PREFETCH PCI regions */ + struct pci_region io; + struct pci_region mem; + struct pci_region prefetch; +}; + +int pcie_dw_get_link_speed(struct pcie_dw *pci); + +int pcie_dw_get_link_width(struct pcie_dw *pci); + +int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index, int type, u64 cpu_addr, + u64 pci_addr, u32 size); + +int pcie_dw_read_config(const struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep, + enum pci_size_t size); + +int pcie_dw_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong value, + enum pci_size_t size); + +static inline void dw_pcie_dbi_write_enable(struct pcie_dw *pci, bool en) +{ + u32 val; + + val = readl(pci->dbi_base + PCIE_MISC_CONTROL_1_OFF); + if (en) + val |= PCIE_DBI_RO_WR_EN; + else + val &= ~PCIE_DBI_RO_WR_EN; + writel(val, pci->dbi_base + PCIE_MISC_CONTROL_1_OFF); +} + +void pcie_dw_setup_host(struct pcie_dw *pci); + +#endif From patchwork Thu Mar 25 14:49:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neil Armstrong X-Patchwork-Id: 1458386 X-Patchwork-Delegate: bmeng.cn@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=baylibre-com.20150623.gappssmtp.com header.i=@baylibre-com.20150623.gappssmtp.com header.a=rsa-sha256 header.s=20150623 header.b=ljIO1Xpy; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F5p1C1xw0z9sVt for ; Fri, 26 Mar 2021 01:50:06 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 89DFD8285C; Thu, 25 Mar 2021 15:49:52 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=baylibre-com.20150623.gappssmtp.com header.i=@baylibre-com.20150623.gappssmtp.com header.b="ljIO1Xpy"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id D2D3C82861; Thu, 25 Mar 2021 15:49:45 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 1F1BF82838 for ; Thu, 25 Mar 2021 15:49:39 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=narmstrong@baylibre.com Received: by mail-wm1-x332.google.com with SMTP id d191so1339646wmd.2 for ; Thu, 25 Mar 2021 07:49:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=PNQKLD2UHDaBhIF47EHs5bq1p/pzDzRHDboy8ij1LX8=; b=ljIO1Xpyzl23Lu2A5gvrcmB5wiH+9PuOTFqGEN1M36Sp9pOhT8qOvfKHGCJM315oa2 T0KxROMTetJnYkpNPbHVqKavM3hVnxs4hx6jZjBa+HdWUYpiwmviVPyMyVAB3unhixem 1kig+AKZCGQ/0rCel8YwKzSBqzaVaCxS6dVS51KxO7nzduzDd0rE0VPjPlPZBP5PNQyX +Tag5/BzN/13l8NLFqXhfOT1ZlWjgXIrl9V60xDrTcxZGmWRB3chFDnBeFKFFQ0ez6gr KQo5aicjbn+UGhs+qkypenGWC9SNkUne9SFBY76ss1mK8SwBGTvv+w4j39WuPKHKQxur RwXw== 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:mime-version:content-transfer-encoding; bh=PNQKLD2UHDaBhIF47EHs5bq1p/pzDzRHDboy8ij1LX8=; b=V2QSZdjtBUDBqX33YqkmbYgNnm04eXznqAwRnk8BaZtNsfDA1QPkuxgE1lZfueWWo1 o22xSLqzAvW9QUFBHABpqMTTLlsn3jviiW/HxHa3YGLfrvkI+U83EcmaIh8cegtZKPEa bADd8hElJZULn4v76MQCzeg3lvTtziJ5jejxZEeq5uoQVi+3e5VP4qS+AUiSI+cqaEuk 2KcsZ7i2egKVeXgkvuvz94ang0IYRqmZuI24aMCqSVJ39EuhyT+op36/zuqprP8N+JMU E1WewMzm3VX9f+CwzcbAzboCVMoVSZht89x825/9sSVRikMvZfr0HKOWGAw6oj2UVjvc ApaA== X-Gm-Message-State: AOAM531lSAP9FEpO8n4K4WZhdegeJtmVsd9yyMC+5gHlF3D/1PhnnSJt 8lC+x4Yl2dSY4UYMoYOb0UM9tA== X-Google-Smtp-Source: ABdhPJwRXBgWokm1FOygz6na6I4R0hJKPrDH75aapzVJBLNK1ZVZtvee5kRnyTMESPu/Dz3BaZOvCQ== X-Received: by 2002:a7b:ce91:: with SMTP id q17mr8627163wmj.28.1616683778438; Thu, 25 Mar 2021 07:49:38 -0700 (PDT) Received: from localhost.localdomain ([2a01:e0a:90c:e290:b105:9672:b0a:5820]) by smtp.gmail.com with ESMTPSA id w6sm7787727wrl.49.2021.03.25.07.49.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Mar 2021 07:49:37 -0700 (PDT) From: Neil Armstrong To: lokeshvutla@ti.com, nsekhar@ti.com, shawn.lin@rock-chips.com, bmeng.cn@gmail.com, green.wan@sifive.com Cc: u-boot@lists.denx.de, u-boot-amlogic@groups.io, Neil Armstrong Subject: [PATCH RFT v2 2/4] pci: pcie_dw_ti: migrate to common Designware PCIe functions Date: Thu, 25 Mar 2021 15:49:19 +0100 Message-Id: <20210325144921.1791892-3-narmstrong@baylibre.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210325144921.1791892-1-narmstrong@baylibre.com> References: <20210325144921.1791892-1-narmstrong@baylibre.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.4 at phobos.denx.de X-Virus-Status: Clean Migrate the dw_ti driver to use the common DW PCIe helpers. Signed-off-by: Neil Armstrong --- drivers/pci/Kconfig | 2 +- drivers/pci/pcie_dw_ti.c | 444 ++++----------------------------------- 2 files changed, 38 insertions(+), 408 deletions(-) diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index ab5a5e7ed6..318d8fa37d 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -264,7 +264,7 @@ config PCIE_DW_COMMON config PCI_KEYSTONE bool "TI Keystone PCIe controller" - depends on DM_PCI + select PCIE_DW_COMMON help Say Y here if you want to enable PCI controller support on AM654 SoC. diff --git a/drivers/pci/pcie_dw_ti.c b/drivers/pci/pcie_dw_ti.c index 33a5c3cc20..4195a02de3 100644 --- a/drivers/pci/pcie_dw_ti.c +++ b/drivers/pci/pcie_dw_ti.c @@ -19,19 +19,13 @@ #include #include +#include "pcie_dw_common.h" + DECLARE_GLOBAL_DATA_PTR; #define PCIE_VENDORID_MASK GENMASK(15, 0) #define PCIE_DEVICEID_SHIFT 16 -/* PCI DBICS registers */ -#define PCIE_CONFIG_BAR0 0x10 -#define PCIE_LINK_STATUS_REG 0x80 -#define PCIE_LINK_STATUS_SPEED_OFF 16 -#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF) -#define PCIE_LINK_STATUS_WIDTH_OFF 20 -#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF) - #define PCIE_LINK_CAPABILITY 0x7c #define PCIE_LINK_CTL_2 0xa0 #define TARGET_LINK_SPEED_MASK 0xf @@ -47,46 +41,12 @@ DECLARE_GLOBAL_DATA_PTR; #define PORT_LOGIC_LTSSM_STATE_MASK 0x1f #define PORT_LOGIC_LTSSM_STATE_L0 0x11 -#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80c -#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17) - #define PCIE_LINK_UP_TIMEOUT_MS 100 -/* - * iATU Unroll-specific register definitions - * From 4.80 core version the address translation will be made by unroll. - * The registers are offset from atu_base - */ -#define PCIE_ATU_UNR_REGION_CTRL1 0x00 -#define PCIE_ATU_UNR_REGION_CTRL2 0x04 -#define PCIE_ATU_UNR_LOWER_BASE 0x08 -#define PCIE_ATU_UNR_UPPER_BASE 0x0c -#define PCIE_ATU_UNR_LIMIT 0x10 -#define PCIE_ATU_UNR_LOWER_TARGET 0x14 -#define PCIE_ATU_UNR_UPPER_TARGET 0x18 - -#define PCIE_ATU_REGION_INDEX1 (0x1 << 0) -#define PCIE_ATU_REGION_INDEX0 (0x0 << 0) -#define PCIE_ATU_TYPE_MEM (0x0 << 0) -#define PCIE_ATU_TYPE_IO (0x2 << 0) -#define PCIE_ATU_TYPE_CFG0 (0x4 << 0) -#define PCIE_ATU_TYPE_CFG1 (0x5 << 0) -#define PCIE_ATU_ENABLE (0x1 << 31) -#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) -#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24) -#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19) -#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16) - -/* Register address builder */ -#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((region) << 9) - /* Offsets from App base */ #define PCIE_CMD_STATUS 0x04 #define LTSSM_EN_VAL BIT(0) -/* Parameters for the waiting for iATU enabled routine */ -#define LINK_WAIT_MAX_IATU_RETRIES 5 -#define LINK_WAIT_IATU 10000 #define AM654_PCIE_DEV_TYPE_MASK 0x3 #define EP 0x0 @@ -96,29 +56,13 @@ DECLARE_GLOBAL_DATA_PTR; /** * struct pcie_dw_ti - TI DW PCIe controller state * + * @pci: The common PCIe DW structure * @app_base: The base address of application register space - * @dbics_base: The base address of dbics register space - * @cfg_base: The base address of configuration space - * @atu_base: The base address of ATU space - * @cfg_size: The size of the configuration space which is needed - * as it gets written into the PCIE_ATU_LIMIT register - * @first_busno: This driver supports multiple PCIe controllers. - * first_busno stores the bus number of the PCIe root-port - * number which may vary depending on the PCIe setup - * (PEX switches etc). */ struct pcie_dw_ti { + /* Must be first member of the struct */ + struct pcie_dw dw; void *app_base; - void *dbi_base; - void *cfg_base; - void *atu_base; - fdt_size_t cfg_size; - int first_busno; - struct udevice *dev; - - /* IO and MEM PCI regions */ - struct pci_region io; - struct pci_region mem; }; enum dw_pcie_device_mode { @@ -128,261 +72,6 @@ enum dw_pcie_device_mode { DW_PCIE_RC_TYPE, }; -static int pcie_dw_get_link_speed(struct pcie_dw_ti *pci) -{ - return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) & - PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF; -} - -static int pcie_dw_get_link_width(struct pcie_dw_ti *pci) -{ - return (readl(pci->dbi_base + PCIE_LINK_STATUS_REG) & - PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF; -} - -static void dw_pcie_writel_ob_unroll(struct pcie_dw_ti *pci, u32 index, u32 reg, - u32 val) -{ - u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); - void __iomem *base = pci->atu_base; - - writel(val, base + offset + reg); -} - -static u32 dw_pcie_readl_ob_unroll(struct pcie_dw_ti *pci, u32 index, u32 reg) -{ - u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); - void __iomem *base = pci->atu_base; - - return readl(base + offset + reg); -} - -/** - * pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses - * - * @pcie: Pointer to the PCI controller state - * @index: ATU region index - * @type: ATU accsess type - * @cpu_addr: the physical address for the translation entry - * @pci_addr: the pcie bus address for the translation entry - * @size: the size of the translation entry - */ -static void pcie_dw_prog_outbound_atu_unroll(struct pcie_dw_ti *pci, int index, - int type, u64 cpu_addr, - u64 pci_addr, u32 size) -{ - u32 retries, val; - - debug("ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n", - index, type, cpu_addr, pci_addr, size); - - dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, - lower_32_bits(cpu_addr)); - dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, - upper_32_bits(cpu_addr)); - dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT, - lower_32_bits(cpu_addr + size - 1)); - dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, - lower_32_bits(pci_addr)); - dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, - upper_32_bits(pci_addr)); - dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, - type); - dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, - PCIE_ATU_ENABLE); - - /* - * Make sure ATU enable takes effect before any subsequent config - * and I/O accesses. - */ - for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { - val = dw_pcie_readl_ob_unroll(pci, index, - PCIE_ATU_UNR_REGION_CTRL2); - if (val & PCIE_ATU_ENABLE) - return; - - udelay(LINK_WAIT_IATU); - } - dev_err(pci->dev, "outbound iATU is not being enabled\n"); -} - -/** - * set_cfg_address() - Configure the PCIe controller config space access - * - * @pcie: Pointer to the PCI controller state - * @d: PCI device to access - * @where: Offset in the configuration space - * - * Configures the PCIe controller to access the configuration space of - * a specific PCIe device and returns the address to use for this - * access. - * - * Return: Address that can be used to access the configation space - * of the requested device / offset - */ -static uintptr_t set_cfg_address(struct pcie_dw_ti *pcie, - pci_dev_t d, uint where) -{ - int bus = PCI_BUS(d) - pcie->first_busno; - uintptr_t va_address; - u32 atu_type; - - /* Use dbi_base for own configuration read and write */ - if (!bus) { - va_address = (uintptr_t)pcie->dbi_base; - goto out; - } - - if (bus == 1) - /* For local bus, change TLP Type field to 4. */ - atu_type = PCIE_ATU_TYPE_CFG0; - else - /* Otherwise, change TLP Type field to 5. */ - atu_type = PCIE_ATU_TYPE_CFG1; - - /* - * Not accessing root port configuration space? - * Region #0 is used for Outbound CFG space access. - * Direction = Outbound - * Region Index = 0 - */ - d = PCI_MASK_BUS(d); - d = PCI_ADD_BUS(bus, d); - pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1, - atu_type, (u64)pcie->cfg_base, - d << 8, pcie->cfg_size); - - va_address = (uintptr_t)pcie->cfg_base; - -out: - va_address += where & ~0x3; - - return va_address; -} - -/** - * pcie_dw_addr_valid() - Check for valid bus address - * - * @d: The PCI device to access - * @first_busno: Bus number of the PCIe controller root complex - * - * Return 1 (true) if the PCI device can be accessed by this controller. - * - * Return: 1 on valid, 0 on invalid - */ -static int pcie_dw_addr_valid(pci_dev_t d, int first_busno) -{ - if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0)) - return 0; - if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0)) - return 0; - - return 1; -} - -/** - * pcie_dw_ti_read_config() - Read from configuration space - * - * @bus: Pointer to the PCI bus - * @bdf: Identifies the PCIe device to access - * @offset: The offset into the device's configuration space - * @valuep: A pointer at which to store the read value - * @size: Indicates the size of access to perform - * - * Read a value of size @size from offset @offset within the configuration - * space of the device identified by the bus, device & function numbers in @bdf - * on the PCI bus @bus. - * - * Return: 0 on success - */ -static int pcie_dw_ti_read_config(const struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - struct pcie_dw_ti *pcie = dev_get_priv(bus); - uintptr_t va_address; - ulong value; - - debug("PCIE CFG read: bdf=%2x:%2x:%2x ", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - - if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) { - debug("- out of range\n"); - *valuep = pci_get_ff(size); - return 0; - } - - va_address = set_cfg_address(pcie, bdf, offset); - - value = readl(va_address); - - debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); - *valuep = pci_conv_32_to_size(value, offset, size); - - pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1, - PCIE_ATU_TYPE_IO, pcie->io.phys_start, - pcie->io.bus_start, pcie->io.size); - - return 0; -} - -/** - * pcie_dw_ti_write_config() - Write to configuration space - * - * @bus: Pointer to the PCI bus - * @bdf: Identifies the PCIe device to access - * @offset: The offset into the device's configuration space - * @value: The value to write - * @size: Indicates the size of access to perform - * - * Write the value @value of size @size from offset @offset within the - * configuration space of the device identified by the bus, device & function - * numbers in @bdf on the PCI bus @bus. - * - * Return: 0 on success - */ -static int pcie_dw_ti_write_config(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - struct pcie_dw_ti *pcie = dev_get_priv(bus); - uintptr_t va_address; - ulong old; - - debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); - - if (!pcie_dw_addr_valid(bdf, pcie->first_busno)) { - debug("- out of range\n"); - return 0; - } - - va_address = set_cfg_address(pcie, bdf, offset); - - old = readl(va_address); - value = pci_conv_size_to_32(old, value, offset, size); - writel(value, va_address); - - pcie_dw_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1, - PCIE_ATU_TYPE_IO, pcie->io.phys_start, - pcie->io.bus_start, pcie->io.size); - - return 0; -} - -static inline void dw_pcie_dbi_write_enable(struct pcie_dw_ti *pci, bool en) -{ - u32 val; - - val = readl(pci->dbi_base + PCIE_MISC_CONTROL_1_OFF); - if (en) - val |= PCIE_DBI_RO_WR_EN; - else - val &= ~PCIE_DBI_RO_WR_EN; - writel(val, pci->dbi_base + PCIE_MISC_CONTROL_1_OFF); -} - /** * pcie_dw_configure() - Configure link capabilities and speed * @@ -395,19 +84,19 @@ static void pcie_dw_configure(struct pcie_dw_ti *pci, u32 cap_speed) { u32 val; - dw_pcie_dbi_write_enable(pci, true); + dw_pcie_dbi_write_enable(&pci->dw, true); - val = readl(pci->dbi_base + PCIE_LINK_CAPABILITY); + val = readl(pci->dw.dbi_base + PCIE_LINK_CAPABILITY); val &= ~TARGET_LINK_SPEED_MASK; val |= cap_speed; - writel(val, pci->dbi_base + PCIE_LINK_CAPABILITY); + writel(val, pci->dw.dbi_base + PCIE_LINK_CAPABILITY); - val = readl(pci->dbi_base + PCIE_LINK_CTL_2); + val = readl(pci->dw.dbi_base + PCIE_LINK_CTL_2); val &= ~TARGET_LINK_SPEED_MASK; val |= cap_speed; - writel(val, pci->dbi_base + PCIE_LINK_CTL_2); + writel(val, pci->dw.dbi_base + PCIE_LINK_CTL_2); - dw_pcie_dbi_write_enable(pci, false); + dw_pcie_dbi_write_enable(&pci->dw, false); } /** @@ -421,7 +110,7 @@ static int is_link_up(struct pcie_dw_ti *pci) { u32 val; - val = readl(pci->dbi_base + PCIE_PORT_DEBUG0); + val = readl(pci->dw.dbi_base + PCIE_PORT_DEBUG0); val &= PORT_LOGIC_LTSSM_STATE_MASK; return (val == PORT_LOGIC_LTSSM_STATE_L0); @@ -477,56 +166,6 @@ static int pcie_dw_ti_pcie_link_up(struct pcie_dw_ti *pci, u32 cap_speed) return 1; } -/** - * pcie_dw_setup_host() - Setup the PCIe controller for RC opertaion - * - * @pcie: Pointer to the PCI controller state - * - * Configure the host BARs of the PCIe controller root port so that - * PCI(e) devices may access the system memory. - */ -static void pcie_dw_setup_host(struct pcie_dw_ti *pci) -{ - u32 val; - - /* setup RC BARs */ - writel(PCI_BASE_ADDRESS_MEM_TYPE_64, - pci->dbi_base + PCI_BASE_ADDRESS_0); - writel(0x0, pci->dbi_base + PCI_BASE_ADDRESS_1); - - /* setup interrupt pins */ - dw_pcie_dbi_write_enable(pci, true); - val = readl(pci->dbi_base + PCI_INTERRUPT_LINE); - val &= 0xffff00ff; - val |= 0x00000100; - writel(val, pci->dbi_base + PCI_INTERRUPT_LINE); - dw_pcie_dbi_write_enable(pci, false); - - /* setup bus numbers */ - val = readl(pci->dbi_base + PCI_PRIMARY_BUS); - val &= 0xff000000; - val |= 0x00ff0100; - writel(val, pci->dbi_base + PCI_PRIMARY_BUS); - - /* setup command register */ - val = readl(pci->dbi_base + PCI_COMMAND); - val &= 0xffff0000; - val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_SERR; - writel(val, pci->dbi_base + PCI_COMMAND); - - /* Enable write permission for the DBI read-only register */ - dw_pcie_dbi_write_enable(pci, true); - /* program correct class for RC */ - writew(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE); - /* Better disable write permission right after the update */ - dw_pcie_dbi_write_enable(pci, false); - - val = readl(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); - val |= PORT_LOGIC_SPEED_CHANGE; - writel(val, pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); -} - static int pcie_am654_set_mode(struct pcie_dw_ti *pci, enum dw_pcie_device_mode mode) { @@ -535,7 +174,7 @@ static int pcie_am654_set_mode(struct pcie_dw_ti *pci, u32 mask; int ret; - syscon = syscon_regmap_lookup_by_phandle(pci->dev, + syscon = syscon_regmap_lookup_by_phandle(pci->dw.dev, "ti,syscon-pcie-mode"); if (IS_ERR(syscon)) return 0; @@ -550,13 +189,13 @@ static int pcie_am654_set_mode(struct pcie_dw_ti *pci, val = EP; break; default: - dev_err(pci->dev, "INVALID device type %d\n", mode); + dev_err(pci->dw.dev, "INVALID device type %d\n", mode); return -EINVAL; } ret = regmap_update_bits(syscon, 0, mask, val); if (ret) { - dev_err(pci->dev, "failed to set pcie mode\n"); + dev_err(pci->dw.dev, "failed to set pcie mode\n"); return ret; } @@ -569,7 +208,7 @@ static int pcie_dw_init_id(struct pcie_dw_ti *pci) unsigned int id; int ret; - devctrl_regs = syscon_regmap_lookup_by_phandle(pci->dev, + devctrl_regs = syscon_regmap_lookup_by_phandle(pci->dw.dev, "ti,syscon-pcie-id"); if (IS_ERR(devctrl_regs)) return PTR_ERR(devctrl_regs); @@ -578,10 +217,10 @@ static int pcie_dw_init_id(struct pcie_dw_ti *pci) if (ret) return ret; - dw_pcie_dbi_write_enable(pci, true); - writew(id & PCIE_VENDORID_MASK, pci->dbi_base + PCI_VENDOR_ID); - writew(id >> PCIE_DEVICEID_SHIFT, pci->dbi_base + PCI_DEVICE_ID); - dw_pcie_dbi_write_enable(pci, false); + dw_pcie_dbi_write_enable(&pci->dw, true); + writew(id & PCIE_VENDORID_MASK, pci->dw.dbi_base + PCI_VENDOR_ID); + writew(id >> PCIE_DEVICEID_SHIFT, pci->dw.dbi_base + PCI_DEVICE_ID); + dw_pcie_dbi_write_enable(&pci->dw, false); return 0; } @@ -635,10 +274,10 @@ static int pcie_dw_ti_probe(struct udevice *dev) generic_phy_init(&phy1); generic_phy_power_on(&phy1); - pci->first_busno = dev_seq(dev); - pci->dev = dev; + pci->dw.first_busno = dev_seq(dev); + pci->dw.dev = dev; - pcie_dw_setup_host(pci); + pcie_dw_setup_host(&pci->dw); pcie_dw_init_id(pci); if (device_is_compatible(dev, "ti,am654-pcie-rc")) @@ -650,23 +289,14 @@ static int pcie_dw_ti_probe(struct udevice *dev) } printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev_seq(dev), - pcie_dw_get_link_speed(pci), - pcie_dw_get_link_width(pci), + pcie_dw_get_link_speed(&pci->dw), + pcie_dw_get_link_width(&pci->dw), hose->first_busno); - /* Store the IO and MEM windows settings for future use by the ATU */ - pci->io.phys_start = hose->regions[0].phys_start; /* IO base */ - pci->io.bus_start = hose->regions[0].bus_start; /* IO_bus_addr */ - pci->io.size = hose->regions[0].size; /* IO size */ - - pci->mem.phys_start = hose->regions[1].phys_start; /* MEM base */ - pci->mem.bus_start = hose->regions[1].bus_start; /* MEM_bus_addr */ - pci->mem.size = hose->regions[1].size; /* MEM size */ - - pcie_dw_prog_outbound_atu_unroll(pci, PCIE_ATU_REGION_INDEX0, + pcie_dw_prog_outbound_atu_unroll(&pci->dw, PCIE_ATU_REGION_INDEX0, PCIE_ATU_TYPE_MEM, - pci->mem.phys_start, - pci->mem.bus_start, pci->mem.size); + pci->dw.mem.phys_start, + pci->dw.mem.bus_start, pci->dw.mem.size); return 0; } @@ -687,19 +317,19 @@ static int pcie_dw_ti_of_to_plat(struct udevice *dev) struct pcie_dw_ti *pcie = dev_get_priv(dev); /* Get the controller base address */ - pcie->dbi_base = (void *)dev_read_addr_name(dev, "dbics"); - if ((fdt_addr_t)pcie->dbi_base == FDT_ADDR_T_NONE) + pcie->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbics"); + if ((fdt_addr_t)pcie->dw.dbi_base == FDT_ADDR_T_NONE) return -EINVAL; /* Get the config space base address and size */ - pcie->cfg_base = (void *)dev_read_addr_size_name(dev, "config", - &pcie->cfg_size); - if ((fdt_addr_t)pcie->cfg_base == FDT_ADDR_T_NONE) + pcie->dw.cfg_base = (void *)dev_read_addr_size_name(dev, "config", + &pcie->dw.cfg_size); + if ((fdt_addr_t)pcie->dw.cfg_base == FDT_ADDR_T_NONE) return -EINVAL; /* Get the iATU base address and size */ - pcie->atu_base = (void *)dev_read_addr_name(dev, "atu"); - if ((fdt_addr_t)pcie->atu_base == FDT_ADDR_T_NONE) + pcie->dw.atu_base = (void *)dev_read_addr_name(dev, "atu"); + if ((fdt_addr_t)pcie->dw.atu_base == FDT_ADDR_T_NONE) return -EINVAL; /* Get the app base address and size */ @@ -711,8 +341,8 @@ static int pcie_dw_ti_of_to_plat(struct udevice *dev) } static const struct dm_pci_ops pcie_dw_ti_ops = { - .read_config = pcie_dw_ti_read_config, - .write_config = pcie_dw_ti_write_config, + .read_config = pcie_dw_read_config, + .write_config = pcie_dw_write_config, }; static const struct udevice_id pcie_dw_ti_ids[] = { From patchwork Thu Mar 25 14:49:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neil Armstrong X-Patchwork-Id: 1458387 X-Patchwork-Delegate: bmeng.cn@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=baylibre-com.20150623.gappssmtp.com header.i=@baylibre-com.20150623.gappssmtp.com header.a=rsa-sha256 header.s=20150623 header.b=WZBT56ax; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F5p1R2TBJz9sVm for ; Fri, 26 Mar 2021 01:50:19 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 796B28289F; Thu, 25 Mar 2021 15:49:55 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=baylibre-com.20150623.gappssmtp.com header.i=@baylibre-com.20150623.gappssmtp.com header.b="WZBT56ax"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 2628C8285C; Thu, 25 Mar 2021 15:49:50 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id D8A43805BF for ; Thu, 25 Mar 2021 15:49:42 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=narmstrong@baylibre.com Received: by mail-wm1-x329.google.com with SMTP id p19so1344288wmq.1 for ; Thu, 25 Mar 2021 07:49:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=vpxBpwqyHRcNf0UwfTAv7YWybWU+QUuq14KpZj5P7to=; b=WZBT56ax42ltRzlk1VjKxO4pFA9ZL7dnSxYWtHdim/XRZ2/t6Lom7/nlO5zbKONhv7 aa15Ixhf+IapKU6yq4SK/pW9V4EFMeYl0hi8KW6VgoIeQJVzxeGR2x7EagEcttBrHZfF tA26qprFJABGe13+wjPd77BTlMTdhtLUGXWx286/I5Spz935A3yCC956CTN5m2FqfDav NFT3V6y1vTzY0XbHKRygdEjwb1yVRasfskeVrSUD3Q/tLs2Vjxbq2HGclNoZe5fca/0c q3yiWRD88vK3NUAP/nSk6kSiKR+bKtaF3ZeiMKr2EYn37bt5ZGMrotzmMWKZTWO6IxpR bLeQ== 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:mime-version:content-transfer-encoding; bh=vpxBpwqyHRcNf0UwfTAv7YWybWU+QUuq14KpZj5P7to=; b=X14k5X7HQ3x7njtejMqPVP3+7LSPNUkgC1ARkp5aKHCNgvr9aCrayUsRnDbxUaYNH5 /oh4lVDZMwU5M93MCYP0t68jnbKg686stJPhYv9b3FofUE1PoTGV9ldKlnLSuQGgbqeT I36LdueyEtBThlFXH9II4dTx0nYvXnkyKB4jU+TKUxhPEP5lUHeuUHvUMjaAp8wmih5n up2WTz5G7J+Jfj5C0I0tsnB4/9NOREKMFoDwj4PmXg0ypqanRfEcAM8+jnqlc/a0POiY eI9jY8ypL3K14e5ir1OG1xDUSQ4wo82OdYeDNVMmA4/SDGfSYY+1BfC092FDsxdiHxrn xXGg== X-Gm-Message-State: AOAM532HrYeHcsYzx2wMNom/1Rkx7Ndmk9zJJ0Se3pEFBhUZQbTp8vp2 mEqHa0VTmRCCpIVa153uXVTWDsr8VO+oRMa/ X-Google-Smtp-Source: ABdhPJwxU5xDdUSdQ3AzqY4p1QuMdqtyaaznu6Kl/dBhAsrmQBFW07mmqWGL70odjXRXG0aBtCYvXg== X-Received: by 2002:a1c:bb89:: with SMTP id l131mr8632784wmf.47.1616683782188; Thu, 25 Mar 2021 07:49:42 -0700 (PDT) Received: from localhost.localdomain ([2a01:e0a:90c:e290:b105:9672:b0a:5820]) by smtp.gmail.com with ESMTPSA id w6sm7787727wrl.49.2021.03.25.07.49.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Mar 2021 07:49:40 -0700 (PDT) From: Neil Armstrong To: lokeshvutla@ti.com, nsekhar@ti.com, shawn.lin@rock-chips.com, bmeng.cn@gmail.com, green.wan@sifive.com Cc: u-boot@lists.denx.de, u-boot-amlogic@groups.io, Neil Armstrong Subject: [PATCH RFT v2 3/4] pci: pcie_dw_rockchip: migrate to common Designware PCIe functions Date: Thu, 25 Mar 2021 15:49:20 +0100 Message-Id: <20210325144921.1791892-4-narmstrong@baylibre.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210325144921.1791892-1-narmstrong@baylibre.com> References: <20210325144921.1791892-1-narmstrong@baylibre.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.4 at phobos.denx.de X-Virus-Status: Clean Migrate the dw_rockchip driver to use the common DW PCIe helpers. Signed-off-by: Neil Armstrong --- drivers/pci/Kconfig | 2 +- drivers/pci/pcie_dw_rockchip.c | 472 ++------------------------------- 2 files changed, 30 insertions(+), 444 deletions(-) diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 318d8fa37d..cacfc4bd25 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -289,7 +289,7 @@ config PCIE_ROCKCHIP config PCIE_DW_ROCKCHIP bool "Rockchip DesignWare based PCIe controller" depends on ARCH_ROCKCHIP - select DM_PCI + select PCIE_DW_COMMON select PHY_ROCKCHIP_SNPS_PCIE3 help Say Y here if you want to enable DW PCIe controller support on diff --git a/drivers/pci/pcie_dw_rockchip.c b/drivers/pci/pcie_dw_rockchip.c index 77f1a1b48f..bc22af4230 100644 --- a/drivers/pci/pcie_dw_rockchip.c +++ b/drivers/pci/pcie_dw_rockchip.c @@ -22,39 +22,26 @@ #include #include +#include "pcie_dw_common.h" + DECLARE_GLOBAL_DATA_PTR; /** * struct rk_pcie - RK DW PCIe controller state * * @vpcie3v3: The 3.3v power supply for slot - * @dbi_base: The base address of dwc core regs * @apb_base: The base address of vendor regs - * @cfg_base: The base address of config header space - * @cfg_size: The size of the configuration space which is needed - * as it gets written into the PCIE_ATU_LIMIT register - * @first_busno: This driver supports multiple PCIe controllers. - * first_busno stores the bus number of the PCIe root-port - * number which may vary depending on the PCIe setup - * (PEX switches etc). * @rst_gpio: The #PERST signal for slot - * @io: The IO space for EP's BAR - * @mem: The memory space for EP's BAR */ struct rk_pcie { - struct udevice *dev; + /* Must be first member of the struct */ + struct pcie_dw dw; struct udevice *vpcie3v3; - void *dbi_base; void *apb_base; - void *cfg_base; - fdt_size_t cfg_size; struct phy phy; struct clk_bulk clks; - int first_busno; struct reset_ctl_bulk rsts; struct gpio_desc rst_gpio; - struct pci_region io; - struct pci_region mem; }; /* Parameters for the waiting for iATU enabled routine */ @@ -73,59 +60,6 @@ struct rk_pcie { #define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000 #define PCIE_CLIENT_DBF_EN 0xffff0003 -/* PCI DBICS registers */ -#define PCIE_LINK_STATUS_REG 0x80 -#define PCIE_LINK_STATUS_SPEED_OFF 16 -#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF) -#define PCIE_LINK_STATUS_WIDTH_OFF 20 -#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF) - -#define PCIE_LINK_CAPABILITY 0x7c -#define PCIE_LINK_CTL_2 0xa0 -#define TARGET_LINK_SPEED_MASK 0xf -#define LINK_SPEED_GEN_1 0x1 -#define LINK_SPEED_GEN_2 0x2 -#define LINK_SPEED_GEN_3 0x3 - -#define PCIE_MISC_CONTROL_1_OFF 0x8bc -#define PCIE_DBI_RO_WR_EN BIT(0) - -#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80c -#define PORT_LOGIC_SPEED_CHANGE BIT(17) - -/* - * iATU Unroll-specific register definitions - * From 4.80 core version the address translation will be made by unroll. - * The registers are offset from atu_base - */ -#define PCIE_ATU_UNR_REGION_CTRL1 0x00 -#define PCIE_ATU_UNR_REGION_CTRL2 0x04 -#define PCIE_ATU_UNR_LOWER_BASE 0x08 -#define PCIE_ATU_UNR_UPPER_BASE 0x0c -#define PCIE_ATU_UNR_LIMIT 0x10 -#define PCIE_ATU_UNR_LOWER_TARGET 0x14 -#define PCIE_ATU_UNR_UPPER_TARGET 0x18 - -#define PCIE_ATU_REGION_INDEX1 (0x1 << 0) -#define PCIE_ATU_REGION_INDEX0 (0x0 << 0) -#define PCIE_ATU_TYPE_MEM (0x0 << 0) -#define PCIE_ATU_TYPE_IO (0x2 << 0) -#define PCIE_ATU_TYPE_CFG0 (0x4 << 0) -#define PCIE_ATU_TYPE_CFG1 (0x5 << 0) -#define PCIE_ATU_ENABLE (0x1 << 31) -#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) -#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24) -#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19) -#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16) - -/* Register address builder */ -#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \ - ((0x3 << 20) | ((region) << 9)) - -/* Parameters for the waiting for iATU enabled routine */ -#define LINK_WAIT_MAX_IATU_RETRIES 5 -#define LINK_WAIT_IATU_US 10000 - /* Parameters for the waiting for #perst signal */ #define PERST_WAIT_MS 1000 @@ -175,7 +109,7 @@ static u32 __rk_pcie_read_apb(struct rk_pcie *rk_pcie, void __iomem *base, ret = rk_pcie_read(base + reg, size, &val); if (ret) - dev_err(rk_pcie->dev, "Read APB address failed\n"); + dev_err(rk_pcie->dw.dev, "Read APB address failed\n"); return val; } @@ -187,7 +121,7 @@ static void __rk_pcie_write_apb(struct rk_pcie *rk_pcie, void __iomem *base, ret = rk_pcie_write(base + reg, size, val); if (ret) - dev_err(rk_pcie->dev, "Write APB address failed\n"); + dev_err(rk_pcie->dw.dev, "Write APB address failed\n"); } /** @@ -214,91 +148,6 @@ static inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, u32 reg, __rk_pcie_write_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4, val); } -static int rk_pcie_get_link_speed(struct rk_pcie *rk_pcie) -{ - return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) & - PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF; -} - -static int rk_pcie_get_link_width(struct rk_pcie *rk_pcie) -{ - return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) & - PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF; -} - -static void rk_pcie_writel_ob_unroll(struct rk_pcie *rk_pcie, u32 index, - u32 reg, u32 val) -{ - u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); - void __iomem *base = rk_pcie->dbi_base; - - writel(val, base + offset + reg); -} - -static u32 rk_pcie_readl_ob_unroll(struct rk_pcie *rk_pcie, u32 index, u32 reg) -{ - u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); - void __iomem *base = rk_pcie->dbi_base; - - return readl(base + offset + reg); -} - -static inline void rk_pcie_dbi_write_enable(struct rk_pcie *rk_pcie, bool en) -{ - u32 val; - - val = readl(rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF); - - if (en) - val |= PCIE_DBI_RO_WR_EN; - else - val &= ~PCIE_DBI_RO_WR_EN; - writel(val, rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF); -} - -/** - * rockchip_pcie_setup_host() - Setup the PCIe controller for RC opertaion - * - * @rk_pcie: Pointer to the PCI controller state - * - * Configure the host BARs of the PCIe controller root port so that - * PCI(e) devices may access the system memory. - */ -static void rk_pcie_setup_host(struct rk_pcie *rk_pcie) -{ - u32 val; - - rk_pcie_dbi_write_enable(rk_pcie, true); - - /* setup RC BARs */ - writel(PCI_BASE_ADDRESS_MEM_TYPE_64, - rk_pcie->dbi_base + PCI_BASE_ADDRESS_0); - writel(0x0, rk_pcie->dbi_base + PCI_BASE_ADDRESS_1); - - /* setup interrupt pins */ - clrsetbits_le32(rk_pcie->dbi_base + PCI_INTERRUPT_LINE, - 0xff00, 0x100); - - /* setup bus numbers */ - clrsetbits_le32(rk_pcie->dbi_base + PCI_PRIMARY_BUS, - 0xffffff, 0x00ff0100); - - /* setup command register */ - clrsetbits_le32(rk_pcie->dbi_base + PCI_PRIMARY_BUS, - 0xffff, - PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_SERR); - - /* program correct class for RC */ - writew(PCI_CLASS_BRIDGE_PCI, rk_pcie->dbi_base + PCI_CLASS_DEVICE); - /* Better disable write permission right after the update */ - - setbits_le32(rk_pcie->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL, - PORT_LOGIC_SPEED_CHANGE) - - rk_pcie_dbi_write_enable(rk_pcie, false); -} - /** * rk_pcie_configure() - Configure link capabilities and speed * @@ -311,242 +160,15 @@ static void rk_pcie_configure(struct rk_pcie *pci, u32 cap_speed) { u32 val; - rk_pcie_dbi_write_enable(pci, true); + dw_pcie_dbi_write_enable(&pci->dw, true); - clrsetbits_le32(pci->dbi_base + PCIE_LINK_CAPABILITY, + clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CAPABILITY, TARGET_LINK_SPEED_MASK, cap_speed); - clrsetbits_le32(pci->dbi_base + PCIE_LINK_CTL_2, + clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CTL_2, TARGET_LINK_SPEED_MASK, cap_speed); - rk_pcie_dbi_write_enable(pci, false); -} - -/** - * rk_pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses - * - * @rk_pcie: Pointer to the PCI controller state - * @index: ATU region index - * @type: ATU accsess type - * @cpu_addr: the physical address for the translation entry - * @pci_addr: the pcie bus address for the translation entry - * @size: the size of the translation entry - * - * Return: 0 is successful and -1 is failure - */ -static int rk_pcie_prog_outbound_atu_unroll(struct rk_pcie *pci, int index, - int type, u64 cpu_addr, - u64 pci_addr, u32 size) -{ - u32 retries, val; - - dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n", - index, type, cpu_addr, pci_addr, size); - - rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, - lower_32_bits(cpu_addr)); - rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, - upper_32_bits(cpu_addr)); - rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT, - lower_32_bits(cpu_addr + size - 1)); - rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, - lower_32_bits(pci_addr)); - rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, - upper_32_bits(pci_addr)); - rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, - type); - rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, - PCIE_ATU_ENABLE); - - /* - * Make sure ATU enable takes effect before any subsequent config - * and I/O accesses. - */ - for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { - val = rk_pcie_readl_ob_unroll(pci, index, - PCIE_ATU_UNR_REGION_CTRL2); - if (val & PCIE_ATU_ENABLE) - return 0; - - udelay(LINK_WAIT_IATU_US); - } - dev_err(pci->dev, "outbound iATU is not being enabled\n"); - - return -1; -} - -/** - * rk_pcie_dw_addr_valid() - Check for valid bus address - * - * @d: The PCI device to access - * @first_busno: Bus number of the PCIe controller root complex - * - * Return 1 (true) if the PCI device can be accessed by this controller. - * - * Return: 1 on valid, 0 on invalid - */ -static int rk_pcie_addr_valid(pci_dev_t d, int first_busno) -{ - if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0)) - return 0; - if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0)) - return 0; - - return 1; -} - -/** - * set_cfg_address() - Configure the PCIe controller config space access - * - * @rk_pcie: Pointer to the PCI controller state - * @d: PCI device to access - * @where: Offset in the configuration space - * - * Configures the PCIe controller to access the configuration space of - * a specific PCIe device and returns the address to use for this - * access. - * - * Return: Address that can be used to access the configation space - * of the requested device / offset - */ -static uintptr_t set_cfg_address(struct rk_pcie *pcie, - pci_dev_t d, uint where) -{ - int rel_bus = PCI_BUS(d) - pcie->first_busno; - uintptr_t va_address; - u32 atu_type; - int ret; - - /* Use dbi_base for own configuration read and write */ - if (!rel_bus) { - va_address = (uintptr_t)pcie->dbi_base; - goto out; - } - - if (rel_bus == 1) - /* - * For local bus whose primary bus number is root bridge, - * change TLP Type field to 4. - */ - atu_type = PCIE_ATU_TYPE_CFG0; - else - /* Otherwise, change TLP Type field to 5. */ - atu_type = PCIE_ATU_TYPE_CFG1; - - /* - * Not accessing root port configuration space? - * Region #0 is used for Outbound CFG space access. - * Direction = Outbound - * Region Index = 0 - */ - d = PCI_MASK_BUS(d); - d = PCI_ADD_BUS(rel_bus, d); - ret = rk_pcie_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1, - atu_type, (u64)pcie->cfg_base, - d << 8, pcie->cfg_size); - if (ret) - return (uintptr_t)ret; - - va_address = (uintptr_t)pcie->cfg_base; - -out: - va_address += where & ~0x3; - - return va_address; -} - -/** - * rockchip_pcie_rd_conf() - Read from configuration space - * - * @bus: Pointer to the PCI bus - * @bdf: Identifies the PCIe device to access - * @offset: The offset into the device's configuration space - * @valuep: A pointer at which to store the read value - * @size: Indicates the size of access to perform - * - * Read a value of size @size from offset @offset within the configuration - * space of the device identified by the bus, device & function numbers in @bdf - * on the PCI bus @bus. - * - * Return: 0 on success - */ -static int rockchip_pcie_rd_conf(const struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - struct rk_pcie *pcie = dev_get_priv(bus); - uintptr_t va_address; - ulong value; - - debug("PCIE CFG read: bdf=%2x:%2x:%2x\n", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - - if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) { - debug("- out of range\n"); - *valuep = pci_get_ff(size); - return 0; - } - - va_address = set_cfg_address(pcie, bdf, offset); - - value = readl(va_address); - - debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); - *valuep = pci_conv_32_to_size(value, offset, size); - - return rk_pcie_prog_outbound_atu_unroll(pcie, - PCIE_ATU_REGION_INDEX1, - PCIE_ATU_TYPE_IO, - pcie->io.phys_start, - pcie->io.bus_start, - pcie->io.size); -} - -/** - * rockchip_pcie_wr_conf() - Write to configuration space - * - * @bus: Pointer to the PCI bus - * @bdf: Identifies the PCIe device to access - * @offset: The offset into the device's configuration space - * @value: The value to write - * @size: Indicates the size of access to perform - * - * Write the value @value of size @size from offset @offset within the - * configuration space of the device identified by the bus, device & function - * numbers in @bdf on the PCI bus @bus. - * - * Return: 0 on success - */ -static int rockchip_pcie_wr_conf(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - struct rk_pcie *pcie = dev_get_priv(bus); - uintptr_t va_address; - ulong old; - - debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d)\n", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); - - if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) { - debug("- out of range\n"); - return 0; - } - - va_address = set_cfg_address(pcie, bdf, offset); - - old = readl(va_address); - value = pci_conv_size_to_32(old, value, offset, size); - writel(value, va_address); - - return rk_pcie_prog_outbound_atu_unroll(pcie, - PCIE_ATU_REGION_INDEX1, - PCIE_ATU_TYPE_IO, - pcie->io.phys_start, - pcie->io.bus_start, - pcie->io.size); - + dw_pcie_dbi_write_enable(&pci->dw, false); } static void rk_pcie_enable_debug(struct rk_pcie *rk_pcie) @@ -642,19 +264,19 @@ static int rk_pcie_link_up(struct rk_pcie *priv, u32 cap_speed) for (retries = 0; retries < 5; retries++) { if (is_link_up(priv)) { - dev_info(priv->dev, "PCIe Link up, LTSSM is 0x%x\n", + dev_info(priv->dw.dev, "PCIe Link up, LTSSM is 0x%x\n", rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS)); rk_pcie_debug_dump(priv); return 0; } - dev_info(priv->dev, "PCIe Linking... LTSSM is 0x%x\n", + dev_info(priv->dw.dev, "PCIe Linking... LTSSM is 0x%x\n", rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS)); rk_pcie_debug_dump(priv); msleep(1000); } - dev_err(priv->dev, "PCIe-%d Link Fail\n", dev_seq(priv->dev)); + dev_err(priv->dw.dev, "PCIe-%d Link Fail\n", dev_seq(priv->dw.dev)); /* Link maybe in Gen switch recovery but we need to wait more 1s */ msleep(1000); return -EIO; @@ -670,7 +292,7 @@ static int rockchip_pcie_init_port(struct udevice *dev) if (priv->vpcie3v3) { ret = regulator_set_value(priv->vpcie3v3, 3300000); if (ret) { - dev_err(priv->dev, "failed to enable vpcie3v3 (ret=%d)\n", + dev_err(priv->dw.dev, "failed to enable vpcie3v3 (ret=%d)\n", ret); return ret; } @@ -709,7 +331,7 @@ static int rockchip_pcie_init_port(struct udevice *dev) /* Set RC mode */ rk_pcie_writel_apb(priv, 0x0, 0xf00040); - rk_pcie_setup_host(priv); + pcie_dw_setup_host(&priv->dw); ret = rk_pcie_link_up(priv, LINK_SPEED_GEN_3); if (ret < 0) @@ -733,11 +355,11 @@ static int rockchip_pcie_parse_dt(struct udevice *dev) struct rk_pcie *priv = dev_get_priv(dev); int ret; - priv->dbi_base = (void *)dev_read_addr_index(dev, 0); - if (!priv->dbi_base) + priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0); + if (!priv->dw.dbi_base) return -ENODEV; - dev_dbg(dev, "DBI address is 0x%p\n", priv->dbi_base); + dev_dbg(dev, "DBI address is 0x%p\n", priv->dw.dbi_base); priv->apb_base = (void *)dev_read_addr_index(dev, 1); if (!priv->apb_base) @@ -795,10 +417,10 @@ static int rockchip_pcie_probe(struct udevice *dev) struct rk_pcie *priv = dev_get_priv(dev); struct udevice *ctlr = pci_get_controller(dev); struct pci_controller *hose = dev_get_uclass_priv(ctlr); - int reti = 0; + int ret = 0; - priv->first_busno = dev_seq(dev); - priv->dev = dev; + priv->dw.first_busno = dev_seq(dev); + priv->dw.dev = dev; ret = rockchip_pcie_parse_dt(dev); if (ret) @@ -809,58 +431,22 @@ static int rockchip_pcie_probe(struct udevice *dev) return ret; dev_info(dev, "PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", - dev_seq(dev), rk_pcie_get_link_speed(priv), - rk_pcie_get_link_width(priv), + dev_seq(dev), pcie_dw_get_link_speed(&priv->dw), + pcie_dw_get_link_width(&priv->dw), hose->first_busno); - for (ret = 0; ret < hose->region_count; ret++) { - if (hose->regions[ret].flags == PCI_REGION_IO) { - priv->io.phys_start = hose->regions[ret].phys_start; /* IO base */ - priv->io.bus_start = hose->regions[ret].bus_start; /* IO_bus_addr */ - priv->io.size = hose->regions[ret].size; /* IO size */ - } else if (hose->regions[ret].flags == PCI_REGION_MEM) { - priv->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */ - priv->mem.bus_start = hose->regions[ret].bus_start; /* MEM_bus_addr */ - priv->mem.size = hose->regions[ret].size; /* MEM size */ - } else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) { - priv->cfg_base = (void *)(priv->io.phys_start - priv->io.size); - priv->cfg_size = priv->io.size; - } else { - dev_err(dev, "invalid flags type!\n"); - } - } - - dev_dbg(dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n", - priv->cfg_base, priv->cfg_base + priv->cfg_size, - priv->cfg_size); - - dev_dbg(dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n", - priv->io.phys_start, priv->io.phys_start + priv->io.size, - priv->io.size); - - dev_dbg(dev, "IO bus: [0x%lx - 0x%lx, size 0x%lx]\n", - priv->io.bus_start, priv->io.bus_start + priv->io.size, - priv->io.size); - - dev_dbg(dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n", - priv->mem.phys_start, priv->mem.phys_start + priv->mem.size, - priv->mem.size); - - dev_dbg(dev, "MEM bus: [0x%lx - 0x%lx, size 0x%lx]\n", - priv->mem.bus_start, priv->mem.bus_start + priv->mem.size, - priv->mem.size); - return rk_pcie_prog_outbound_atu_unroll(priv, + return pcie_dw_prog_outbound_atu_unroll(&priv->dw, PCIE_ATU_REGION_INDEX0, PCIE_ATU_TYPE_MEM, - priv->mem.phys_start, - priv->mem.bus_start, - priv->mem.size); + priv->dw.mem.phys_start, + priv->dw.mem.bus_start, + priv->dw.mem.size); } static const struct dm_pci_ops rockchip_pcie_ops = { - .read_config = rockchip_pcie_rd_conf, - .write_config = rockchip_pcie_wr_conf, + .read_config = pcie_dw_read_config, + .write_config = pcie_dw_write_config, }; static const struct udevice_id rockchip_pcie_ids[] = { From patchwork Thu Mar 25 14:49:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neil Armstrong X-Patchwork-Id: 1458388 X-Patchwork-Delegate: bmeng.cn@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=baylibre-com.20150623.gappssmtp.com header.i=@baylibre-com.20150623.gappssmtp.com header.a=rsa-sha256 header.s=20150623 header.b=i/fPyEWS; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F5p1h4hxJz9sVm for ; Fri, 26 Mar 2021 01:50:32 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 4E0F6828BF; Thu, 25 Mar 2021 15:50:13 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=baylibre-com.20150623.gappssmtp.com header.i=@baylibre-com.20150623.gappssmtp.com header.b="i/fPyEWS"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id E046182873; Thu, 25 Mar 2021 15:49:52 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 1C16A82893 for ; Thu, 25 Mar 2021 15:49:47 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=narmstrong@baylibre.com Received: by mail-wm1-x333.google.com with SMTP id z6-20020a1c4c060000b029010f13694ba2so1322170wmf.5 for ; Thu, 25 Mar 2021 07:49:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=FQXHVPM1bxAFvshoCX1Zdm6Y5rmz9pV3BQQaNu7bPSc=; b=i/fPyEWSSJIzWYAhAZpyS5Sb7zXEsHGvx45nTpG/kPczN+126WQ6m5GIQlclWzEZxU 9nokSVgKPW+/+l7icotKeLd/Q6Htly2DXS8XWz3uf+vkeqLuZ1IWsFsoqpRavQCHJRWt hwklXv+XbxvVc1Cc3F/g6qCQwSsgKwIGNSVX0pSEzyEKpt27IFZAWE0UGzeZsbQowouh Q1BXex3NZzfqNMd1yXY8bQyHJ6QAGv9py5AWUweIbcwu7z+CPFGzZljTb/uZ5oqAyXGU 3JHLhhk2gIm3Y2Gkrh4bH9/gcVf/XhzKkD+IhRA4V9k3fJTNS30owpB+qBl/fTRFfR4D 3PeQ== 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:mime-version:content-transfer-encoding; bh=FQXHVPM1bxAFvshoCX1Zdm6Y5rmz9pV3BQQaNu7bPSc=; b=O4ei5GhnqYqUL4QHweNeCu6BlKVxCLelWmFemgoWMaCIu4VRPECwAmm8ADyheUY9FV x3rHrilsw2xPKUokw2/Lv7lkk7A8u2SpsJx/ccTk8TyocAMq2L0IE8DBCC5X9HghdI6Z z4xeKwSL4G8sVXKtoYh++n11g6Grkw8H73LDpwnxpTtvW0ImRw7gVx9yQOJRH4XkhqdG q/vWIzQJNq3SQbipEo7Apa9YGXqeT4keEXkNkDQuu9Bj1MwzN7CiOjEOBqrG1ohd8r/Y B4PWH2BMzlVdfhNA7thEUUXyOY4NpzYgkPrdHdmbIXHcV/BtVS7Gjllca3xebDtGsuUU sqFg== X-Gm-Message-State: AOAM530c++2hltDkNZWrt+htQB1YZSEcdqS+DJhpLQ8KjwyBJmZMLIwh 8EKHA5rFmwaqL+vf62+yB6IfRA== X-Google-Smtp-Source: ABdhPJyrzEBHevGhju/UtjJ1cjbp/WBEEuzDJTrRilRw1tndZIUXkxToeeE+8h38uai8gmfR2iDa9A== X-Received: by 2002:a7b:c2fa:: with SMTP id e26mr8260701wmk.102.1616683786504; Thu, 25 Mar 2021 07:49:46 -0700 (PDT) Received: from localhost.localdomain ([2a01:e0a:90c:e290:b105:9672:b0a:5820]) by smtp.gmail.com with ESMTPSA id w6sm7787727wrl.49.2021.03.25.07.49.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Mar 2021 07:49:45 -0700 (PDT) From: Neil Armstrong To: lokeshvutla@ti.com, nsekhar@ti.com, shawn.lin@rock-chips.com, bmeng.cn@gmail.com, green.wan@sifive.com Cc: u-boot@lists.denx.de, u-boot-amlogic@groups.io, Neil Armstrong Subject: [PATCH RFT v2 4/4] pci: add Amlogic Meson Designware PCIe controller Date: Thu, 25 Mar 2021 15:49:21 +0100 Message-Id: <20210325144921.1791892-5-narmstrong@baylibre.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210325144921.1791892-1-narmstrong@baylibre.com> References: <20210325144921.1791892-1-narmstrong@baylibre.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.4 at phobos.denx.de X-Virus-Status: Clean Add support for the DW PCIe controller found in the Amlogic Meson AXG and G12 (G12A, G12B, SM1) SoCs. This uses the common DW PCIe helpers introducted previously. Signed-off-by: Neil Armstrong --- drivers/pci/Kconfig | 8 + drivers/pci/Makefile | 1 + drivers/pci/pcie_dw_meson.c | 459 ++++++++++++++++++++++++++++++++++++ 3 files changed, 468 insertions(+) create mode 100644 drivers/pci/pcie_dw_meson.c diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index cacfc4bd25..cdcdd8f456 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -276,6 +276,14 @@ config PCIE_MEDIATEK Say Y here if you want to enable Gen2 PCIe controller, which could be found on MT7623 SoC family. +config PCIE_DW_MESON + bool "Amlogic Meson DesignWare based PCIe controller" + depends on ARCH_MESON + select PCIE_DW_COMMON + help + Say Y here if you want to enable DW PCIe controller support on + Amlogic SoCs. + config PCIE_ROCKCHIP bool "Enable Rockchip PCIe driver" depends on ARCH_ROCKCHIP diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index e3ca8b27e4..96d61821fe 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -50,5 +50,6 @@ obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie_dw_rockchip.o +obj-$(CONFIG_PCIE_DW_MESON) += pcie_dw_meson.o obj-$(CONFIG_PCI_BRCMSTB) += pcie_brcmstb.o obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o diff --git a/drivers/pci/pcie_dw_meson.c b/drivers/pci/pcie_dw_meson.c new file mode 100644 index 0000000000..0525ecbea6 --- /dev/null +++ b/drivers/pci/pcie_dw_meson.c @@ -0,0 +1,459 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Amlogic DesignWare based PCIe host controller driver + * + * Copyright (c) 2021 BayLibre, SAS + * Author: Neil Armstrong + * + * Based on pcie_dw_rockchip.c + * Copyright (c) 2021 Rockchip, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie_dw_common.h" + +DECLARE_GLOBAL_DATA_PTR; + +/** + * struct meson_pcie - Amlogic Meson DW PCIe controller state + * + * @pci: The common PCIe DW structure + * @meson_cfg_base: The base address of vendor regs + * @phy + * @clk_port + * @clk_general + * @clk_pclk + * @rsts + * @rst_gpio: The #PERST signal for slot + */ +struct meson_pcie { + /* Must be first member of the struct */ + struct pcie_dw dw; + void *meson_cfg_base; + struct phy phy; + struct clk clk_port; + struct clk clk_general; + struct clk clk_pclk; + struct reset_ctl_bulk rsts; + struct gpio_desc rst_gpio; +}; + +#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ + +#define PCIE_CAP_MAX_PAYLOAD_SIZE(x) ((x) << 5) +#define PCIE_CAP_MAX_READ_REQ_SIZE(x) ((x) << 12) + +/* PCIe specific config registers */ +#define PCIE_CFG0 0x0 +#define APP_LTSSM_ENABLE BIT(7) + +#define PCIE_CFG_STATUS12 0x30 +#define IS_SMLH_LINK_UP(x) ((x) & (1 << 6)) +#define IS_RDLH_LINK_UP(x) ((x) & (1 << 16)) +#define IS_LTSSM_UP(x) ((((x) >> 10) & 0x1f) == 0x11) + +#define PCIE_CFG_STATUS17 0x44 +#define PM_CURRENT_STATE(x) (((x) >> 7) & 0x1) + +#define WAIT_LINKUP_TIMEOUT 4000 +#define PORT_CLK_RATE 100000000UL +#define MAX_PAYLOAD_SIZE 256 +#define MAX_READ_REQ_SIZE 256 +#define PCIE_RESET_DELAY 500 +#define PCIE_SHARED_RESET 1 +#define PCIE_NORMAL_RESET 0 + +enum pcie_data_rate { + PCIE_GEN1, + PCIE_GEN2, + PCIE_GEN3, + PCIE_GEN4 +}; + +/* Parameters for the waiting for #perst signal */ +#define PERST_WAIT_US 1000000 + +static inline u32 meson_cfg_readl(struct meson_pcie *priv, u32 reg) +{ + return readl(priv->meson_cfg_base + reg); +} + +static inline void meson_cfg_writel(struct meson_pcie *priv, u32 val, u32 reg) +{ + writel(val, priv->meson_cfg_base + reg); +} + +/** + * meson_pcie_configure() - Configure link + * + * @meson_pcie: Pointer to the PCI controller state + * + * Configure the link mode and width + */ +static void meson_pcie_configure(struct meson_pcie *priv) +{ + u32 val; + + dw_pcie_dbi_write_enable(&priv->dw, true); + + val = readl(priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL); + val &= ~PORT_LINK_FAST_LINK_MODE; + val |= PORT_LINK_DLL_LINK_EN; + val &= ~PORT_LINK_MODE_MASK; + val |= PORT_LINK_MODE_1_LANES; + writel(val, priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL); + + val = readl(priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + val &= ~PORT_LOGIC_LINK_WIDTH_MASK; + val |= PORT_LOGIC_LINK_WIDTH_1_LANES; + writel(val, priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + + dw_pcie_dbi_write_enable(&priv->dw, false); +} + +static inline void meson_pcie_enable_ltssm(struct meson_pcie *priv) +{ + u32 val; + + val = meson_cfg_readl(priv, PCIE_CFG0); + val |= APP_LTSSM_ENABLE; + meson_cfg_writel(priv, val, PCIE_CFG0); +} + +static int meson_pcie_wait_link_up(struct meson_pcie *priv) +{ + u32 speed_okay = 0; + u32 cnt = 0; + u32 state12, state17, smlh_up, ltssm_up, rdlh_up; + + do { + state12 = meson_cfg_readl(priv, PCIE_CFG_STATUS12); + state17 = meson_cfg_readl(priv, PCIE_CFG_STATUS17); + smlh_up = IS_SMLH_LINK_UP(state12); + rdlh_up = IS_RDLH_LINK_UP(state12); + ltssm_up = IS_LTSSM_UP(state12); + + if (PM_CURRENT_STATE(state17) < PCIE_GEN3) + speed_okay = 1; + + if (smlh_up) + debug("%s: smlh_link_up is on\n", __func__); + if (rdlh_up) + debug("%s: rdlh_link_up is on\n", __func__); + if (ltssm_up) + debug("%s: ltssm_up is on\n", __func__); + if (speed_okay) + debug("%s: speed_okay\n", __func__); + + if (smlh_up && rdlh_up && ltssm_up && speed_okay) + return 0; + + cnt++; + + udelay(10); + } while (cnt < WAIT_LINKUP_TIMEOUT); + + printf("%s: error: wait linkup timeout\n", __func__); + return -EIO; +} + +/** + * meson_pcie_link_up() - Wait for the link to come up + * + * @meson_pcie: Pointer to the PCI controller state + * @cap_speed: Desired link speed + * + * Return: 1 (true) for active line and negative (false) for no link (timeout) + */ +static int meson_pcie_link_up(struct meson_pcie *priv, u32 cap_speed) +{ + /* DW link configurations */ + meson_pcie_configure(priv); + + /* Reset the device */ + if (dm_gpio_is_valid(&priv->rst_gpio)) { + dm_gpio_set_value(&priv->rst_gpio, 1); + /* + * Minimal is 100ms from spec but we see + * some wired devices need much more, such as 600ms. + * Add a enough delay to cover all cases. + */ + udelay(PERST_WAIT_US); + dm_gpio_set_value(&priv->rst_gpio, 0); + } + + /* Enable LTSSM */ + meson_pcie_enable_ltssm(priv); + + return meson_pcie_wait_link_up(priv); +} + +static int meson_size_to_payload(int size) +{ + /* + * dwc supports 2^(val+7) payload size, which val is 0~5 default to 1. + * So if input size is not 2^order alignment or less than 2^7 or bigger + * than 2^12, just set to default size 2^(1+7). + */ + if (!is_power_of_2(size) || size < 128 || size > 4096) { + debug("%s: payload size %d, set to default 256\n", __func__, size); + return 1; + } + + return fls(size) - 8; +} + +static void meson_set_max_payload(struct meson_pcie *priv, int size) +{ + u32 val; + u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP); + int max_payload_size = meson_size_to_payload(size); + + dw_pcie_dbi_write_enable(&priv->dw, true); + + val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL); + val &= ~PCI_EXP_DEVCTL_PAYLOAD; + writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL); + + val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL); + val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size); + writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL); + + dw_pcie_dbi_write_enable(&priv->dw, false); +} + +static void meson_set_max_rd_req_size(struct meson_pcie *priv, int size) +{ + u32 val; + u16 offset = dm_pci_find_capability(priv->dw.dev, PCI_CAP_ID_EXP); + int max_rd_req_size = meson_size_to_payload(size); + + dw_pcie_dbi_write_enable(&priv->dw, true); + + val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL); + val &= ~PCI_EXP_DEVCTL_PAYLOAD; + writel(val, priv->dw.dbi_base + offset + PCI_EXP_DEVCTL); + + val = readl(priv->dw.dbi_base + offset + PCI_EXP_DEVCTL); + val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size); + writel(val, priv->dw.dbi_base + PCI_EXP_DEVCTL); + + dw_pcie_dbi_write_enable(&priv->dw, false); +} + +static int meson_pcie_init_port(struct udevice *dev) +{ + int ret; + struct meson_pcie *priv = dev_get_priv(dev); + + ret = generic_phy_init(&priv->phy); + if (ret) { + dev_err(dev, "failed to init phy (ret=%d)\n", ret); + return ret; + } + + ret = generic_phy_power_on(&priv->phy); + if (ret) { + dev_err(dev, "failed to power on phy (ret=%d)\n", ret); + goto err_exit_phy; + } + + ret = generic_phy_reset(&priv->phy); + if (ret) { + dev_err(dev, "failed to reset phy (ret=%d)\n", ret); + goto err_exit_phy; + } + + ret = reset_assert_bulk(&priv->rsts); + if (ret) { + dev_err(dev, "failed to assert resets (ret=%d)\n", ret); + goto err_power_off_phy; + } + + udelay(PCIE_RESET_DELAY); + + ret = reset_deassert_bulk(&priv->rsts); + if (ret) { + dev_err(dev, "failed to deassert resets (ret=%d)\n", ret); + goto err_power_off_phy; + } + + udelay(PCIE_RESET_DELAY); + + ret = clk_set_rate(&priv->clk_port, PORT_CLK_RATE); + if (ret) { + dev_err(dev, "failed to set port clk rate (ret=%d)\n", ret); + goto err_deassert_bulk; + } + + ret = clk_enable(&priv->clk_general); + if (ret) { + dev_err(dev, "failed to enable clk general (ret=%d)\n", ret); + goto err_deassert_bulk; + } + + ret = clk_enable(&priv->clk_pclk); + if (ret) { + dev_err(dev, "failed to enable pclk (ret=%d)\n", ret); + goto err_deassert_bulk; + } + + meson_set_max_payload(priv, MAX_PAYLOAD_SIZE); + meson_set_max_rd_req_size(priv, MAX_READ_REQ_SIZE); + + pcie_dw_setup_host(&priv->dw); + + ret = meson_pcie_link_up(priv, LINK_SPEED_GEN_2); + if (ret < 0) + goto err_link_up; + + return 0; +err_link_up: + clk_disable(&priv->clk_port); + clk_disable(&priv->clk_general); + clk_disable(&priv->clk_pclk); +err_deassert_bulk: + reset_assert_bulk(&priv->rsts); +err_power_off_phy: + generic_phy_power_off(&priv->phy); +err_exit_phy: + generic_phy_exit(&priv->phy); + + return ret; +} + +static int meson_pcie_parse_dt(struct udevice *dev) +{ + struct meson_pcie *priv = dev_get_priv(dev); + int ret; + + priv->dw.dbi_base = (void *)dev_read_addr_index(dev, 0); + if (!priv->dw.dbi_base) + return -ENODEV; + + dev_dbg(dev, "ELBI address is 0x%p\n", priv->dw.dbi_base); + + priv->meson_cfg_base = (void *)dev_read_addr_index(dev, 1); + if (!priv->meson_cfg_base) + return -ENODEV; + + dev_dbg(dev, "CFG address is 0x%p\n", priv->meson_cfg_base); + + ret = gpio_request_by_name(dev, "reset-gpios", 0, + &priv->rst_gpio, GPIOD_IS_OUT); + if (ret) { + dev_err(dev, "failed to find reset-gpios property\n"); + return ret; + } + + ret = reset_get_bulk(dev, &priv->rsts); + if (ret) { + dev_err(dev, "Can't get reset: %d\n", ret); + return ret; + } + + ret = clk_get_by_name(dev, "port", &priv->clk_port); + if (ret) { + dev_err(dev, "Can't get port clock: %d\n", ret); + return ret; + } + + ret = clk_get_by_name(dev, "general", &priv->clk_general); + if (ret) { + dev_err(dev, "Can't get port clock: %d\n", ret); + return ret; + } + + ret = clk_get_by_name(dev, "pclk", &priv->clk_pclk); + if (ret) { + dev_err(dev, "Can't get port clock: %d\n", ret); + return ret; + } + + ret = generic_phy_get_by_index(dev, 0, &priv->phy); + if (ret) { + dev_err(dev, "failed to get pcie phy (ret=%d)\n", ret); + return ret; + } + + return 0; +} + +/** + * meson_pcie_probe() - Probe the PCIe bus for active link + * + * @dev: A pointer to the device being operated on + * + * Probe for an active link on the PCIe bus and configure the controller + * to enable this port. + * + * Return: 0 on success, else -ENODEV + */ +static int meson_pcie_probe(struct udevice *dev) +{ + struct meson_pcie *priv = dev_get_priv(dev); + struct udevice *ctlr = pci_get_controller(dev); + struct pci_controller *hose = dev_get_uclass_priv(ctlr); + int ret = 0; + + priv->dw.first_busno = dev_seq(dev); + priv->dw.dev = dev; + + ret = meson_pcie_parse_dt(dev); + if (ret) + return ret; + + ret = meson_pcie_init_port(dev); + if (ret) { + dm_gpio_free(dev, &priv->rst_gpio); + return ret; + } + + printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", + dev_seq(dev), pcie_dw_get_link_speed(&priv->dw), + pcie_dw_get_link_width(&priv->dw), + hose->first_busno); + + return pcie_dw_prog_outbound_atu_unroll(&priv->dw, + PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_MEM, + priv->dw.mem.phys_start, + priv->dw.mem.bus_start, + priv->dw.mem.size); +} + +static const struct dm_pci_ops meson_pcie_ops = { + .read_config = pcie_dw_read_config, + .write_config = pcie_dw_write_config, +}; + +static const struct udevice_id meson_pcie_ids[] = { + { .compatible = "amlogic,axg-pcie" }, + { .compatible = "amlogic,g12a-pcie" }, + { } +}; + +U_BOOT_DRIVER(meson_dw_pcie) = { + .name = "pcie_dw_meson", + .id = UCLASS_PCI, + .of_match = meson_pcie_ids, + .ops = &meson_pcie_ops, + .probe = meson_pcie_probe, + .priv_auto = sizeof(struct meson_pcie), +};