From patchwork Tue Dec 21 11:20:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 1571598 X-Patchwork-Delegate: sr@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20201202 header.b=oYW8C8vx; dkim-atps=neutral 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=) 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 bilbo.ozlabs.org (Postfix) with ESMTPS id 4JJDZ21Wprz9s0r for ; Tue, 21 Dec 2021 22:22:01 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 60C91834B9; Tue, 21 Dec 2021 12:21:29 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=kernel.org 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=kernel.org header.i=@kernel.org header.b="oYW8C8vx"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 1BAF4834DE; Tue, 21 Dec 2021 12:21:01 +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=-2.3 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.2 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id F0CFA83383 for ; Tue, 21 Dec 2021 12:20:45 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=kernel.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=pali@kernel.org Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 7F78BB8164E; Tue, 21 Dec 2021 11:20:45 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id D6C13C36AE8; Tue, 21 Dec 2021 11:20:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1640085644; bh=6sSwCVZ8DzXNy5nEPfiOOBge6odQnU2jLQNG5NsrMeY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oYW8C8vxa/yUvwIlVTvnwuJPpNWHnASUuT3fPiaUpwRtwTUggVsfcsAIBmgJTrxtO vbjXpjQ3x8uccljpiOjG/mX15RYq9+oo+J8AT4YaDFn/03chYa7KOGjIoExM1mHzcg h2T2aVCEsta+sbhND9CiepnkVGobEbULxiC1m7AjviiCm/ia9T8X9wCb4ToGqebG+H d5QJxwkqxnNT6uhZVh2aZcm1AUV+/ec+dsAolAxqaMM7OTbDoJJe9N07+S+yfdVxeu Zhy6gjJy4PowgYcU1mC+7Oag4/cllXC/Y2s4l10WfiX5ykwqA65uVRA6wJailDTX1p 8uUrSW2risrpA== Received: by pali.im (Postfix) id 8ABFC778; Tue, 21 Dec 2021 12:20:43 +0100 (CET) From: =?utf-8?q?Pali_Roh=C3=A1r?= To: Stefan Roese , Dirk Eibach , Mario Six , =?utf-8?q?Marek_Beh=C3=BAn?= , Chris Packham Cc: u-boot@lists.denx.de Subject: [PATCH u-boot-marvell 6/9] pci: pci_mvebu: Split initialization of PCIe ports into 3 phases Date: Tue, 21 Dec 2021 12:20:16 +0100 Message-Id: <20211221112019.15088-7-pali@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20211221112019.15088-1-pali@kernel.org> References: <20211221112019.15088-1-pali@kernel.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.38 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.103.2 at phobos.denx.de X-Virus-Status: Clean In first phase just parse DT properties and fill struct mvebu_pcie. In second phase setup all PCIe links (without enabling them). And in the last third phase enable all PCIe links and create UCLASS_PCI device for each one. Because parsing of DT is done before UCLASS_PCI is created, we cannot use DM for this action anymore. So remove .of_to_plat callback and replace it by ad-hoc function for parsing DT properties and filling struct mvebu_pcie. Signed-off-by: Pali Rohár --- drivers/pci/pci_mvebu.c | 106 +++++++++++++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 22 deletions(-) diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index ba776217c9e6..504ff501aa2e 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -364,17 +364,30 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) writel(0, pcie->base + PCIE_BAR_HI_OFF(0)); } -static int mvebu_pcie_probe(struct udevice *dev) +/* Only enable PCIe link, do not setup it */ +static int mvebu_pcie_enable_link(struct mvebu_pcie *pcie, ofnode node) +{ + /* PCIe link is currently automatically enabled in SerDes code */ + return 0; +} + +/* Setup PCIe link but do not enable it */ +static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie) { - struct mvebu_pcie *pcie = dev_get_plat(dev); - struct udevice *ctlr = pci_get_controller(dev); - struct pci_controller *hose = dev_get_uclass_priv(ctlr); u32 reg; /* Setup PCIe controller to Root Complex mode */ reg = readl(pcie->base + PCIE_CTRL_OFF); reg |= PCIE_CTRL_RC_MODE; writel(reg, pcie->base + PCIE_CTRL_OFF); +} + +static int mvebu_pcie_probe(struct udevice *dev) +{ + struct mvebu_pcie *pcie = dev_get_plat(dev); + struct udevice *ctlr = pci_get_controller(dev); + struct pci_controller *hose = dev_get_uclass_priv(ctlr); + u32 reg; /* * Change Class Code of PCI Bridge device to PCI Bridge (0x600400) @@ -440,7 +453,8 @@ static int mvebu_pcie_probe(struct udevice *dev) mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr, (phys_addr_t)pcie->mem.start, resource_size(&pcie->mem))) { - printf("PCIe unable to add mbus window for mem at %08x+%08x\n", + printf("%s: unable to add mbus window for mem at %08x+%08x\n", + pcie->name, (u32)pcie->mem.start, (unsigned)resource_size(&pcie->mem)); pcie->mem.start = 0; pcie->mem.end = -1; @@ -450,7 +464,8 @@ static int mvebu_pcie_probe(struct udevice *dev) mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr, (phys_addr_t)pcie->io.start, resource_size(&pcie->io))) { - printf("PCIe unable to add mbus window for IO at %08x+%08x\n", + printf("%s: unable to add mbus window for IO at %08x+%08x\n", + pcie->name, (u32)pcie->io.start, (unsigned)resource_size(&pcie->io)); pcie->io.start = 0; pcie->io.end = -1; @@ -549,33 +564,34 @@ static int mvebu_get_tgt_attr(ofnode node, int devfn, return -ENOENT; } -static int mvebu_pcie_of_to_plat(struct udevice *dev) +static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pcie *pcie) { - struct mvebu_pcie *pcie = dev_get_plat(dev); + struct fdt_pci_addr pci_addr; const u32 *addr; int ret = 0; int len; /* Get port number, lane number and memory target / attr */ - if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port", + if (ofnode_read_u32(node, "marvell,pcie-port", &pcie->port)) { ret = -ENODEV; goto err; } - if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-lane", &pcie->lane)) + if (ofnode_read_u32(node, "marvell,pcie-lane", &pcie->lane)) pcie->lane = 0; sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane); - /* pci_get_devfn() returns devfn in bits 15..8, see PCI_DEV usage */ - pcie->devfn = pci_get_devfn(dev); - if (pcie->devfn < 0) { - ret = -ENODEV; + /* devfn is in bits [15:8], see PCI_DEV usage */ + ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr); + if (ret < 0) { + printf("%s: property \"reg\" is invalid\n", pcie->name); goto err; } + pcie->devfn = pci_addr.phys_hi & 0xff00; - ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn, + ret = mvebu_get_tgt_attr(parent, pcie->devfn, IORESOURCE_MEM, &pcie->mem_target, &pcie->mem_attr); if (ret < 0) { @@ -583,7 +599,7 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev) goto err; } - ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn, + ret = mvebu_get_tgt_attr(parent, pcie->devfn, IORESOURCE_IO, &pcie->io_target, &pcie->io_attr); if (ret < 0) { @@ -592,14 +608,14 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev) } /* Parse PCIe controller register base from DT */ - addr = ofnode_get_property(dev_ofnode(dev), "assigned-addresses", &len); + addr = ofnode_get_property(node, "assigned-addresses", &len); if (!addr) { printf("%s: property \"assigned-addresses\" not found\n", pcie->name); ret = -FDT_ERR_NOTFOUND; goto err; } - pcie->base = (void *)(u32)ofnode_translate_address(dev_ofnode(dev), addr); + pcie->base = (void *)(u32)ofnode_translate_address(node, addr); pcie->intregs = (u32)pcie->base - fdt32_to_cpu(addr[2]); return 0; @@ -618,7 +634,6 @@ static struct driver pcie_mvebu_drv = { .id = UCLASS_PCI, .ops = &mvebu_pcie_ops, .probe = mvebu_pcie_probe, - .of_to_plat = mvebu_pcie_of_to_plat, .plat_auto = sizeof(struct mvebu_pcie), }; @@ -628,11 +643,14 @@ static struct driver pcie_mvebu_drv = { */ static int mvebu_pcie_bind(struct udevice *parent) { + struct mvebu_pcie **ports_pcie; struct mvebu_pcie *pcie; struct uclass_driver *drv; struct udevice *dev; struct resource mem; struct resource io; + int ports_count, i; + ofnode *ports_nodes; ofnode subnode; /* Lookup pci driver */ @@ -642,18 +660,34 @@ static int mvebu_pcie_bind(struct udevice *parent) return -ENOENT; } + ports_count = ofnode_get_child_count(dev_ofnode(parent)); + ports_pcie = calloc(ports_count, sizeof(*ports_pcie)); + ports_nodes = calloc(ports_count, sizeof(*ports_nodes)); + if (!ports_pcie || !ports_nodes) { + free(ports_pcie); + free(ports_nodes); + return -ENOMEM; + } + ports_count = 0; + mem.start = MBUS_PCI_MEM_BASE; mem.end = MBUS_PCI_MEM_BASE + MBUS_PCI_MEM_SIZE - 1; io.start = MBUS_PCI_IO_BASE; io.end = MBUS_PCI_IO_BASE + MBUS_PCI_IO_SIZE - 1; + /* First phase: Fill mvebu_pcie struct for each port */ ofnode_for_each_subnode(subnode, dev_ofnode(parent)) { if (!ofnode_is_available(subnode)) continue; pcie = calloc(1, sizeof(*pcie)); if (!pcie) - return -ENOMEM; + continue; + + if (mvebu_pcie_port_parse_dt(subnode, dev_ofnode(parent), pcie) < 0) { + free(pcie); + continue; + } /* * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped @@ -666,7 +700,7 @@ static int mvebu_pcie_bind(struct udevice *parent) pcie->mem.end = mem.start + SZ_128M - 1; mem.start += SZ_128M; } else { - printf("PCIe unable to assign mbus window for mem\n"); + printf("%s: unable to assign mbus window for mem\n", pcie->name); pcie->mem.start = 0; pcie->mem.end = -1; } @@ -676,16 +710,44 @@ static int mvebu_pcie_bind(struct udevice *parent) pcie->io.end = io.start + SZ_64K - 1; io.start += SZ_64K; } else { - printf("PCIe unable to assign mbus window for io\n"); + printf("%s: unable to assign mbus window for io\n", pcie->name); pcie->io.start = 0; pcie->io.end = -1; } + ports_pcie[ports_count] = pcie; + ports_nodes[ports_count] = subnode; + ports_count++; + } + + /* Second phase: Setup all PCIe links (do not enable them yet) */ + for (i = 0; i < ports_count; i++) + mvebu_pcie_setup_link(ports_pcie[i]); + + /* Third phase: Enable all PCIe links and create for each UCLASS_PCI device */ + for (i = 0; i < ports_count; i++) { + pcie = ports_pcie[i]; + subnode = ports_nodes[i]; + + /* + * PCIe link can be enabled only after all PCIe links were + * properly configured. This is because more PCIe links shares + * one enable bit and some PCIe links cannot be enabled + * individually. + */ + if (mvebu_pcie_enable_link(pcie, subnode) < 0) { + free(pcie); + continue; + } + /* Create child device UCLASS_PCI and bind it */ device_bind(parent, &pcie_mvebu_drv, pcie->name, pcie, subnode, &dev); } + free(ports_pcie); + free(ports_nodes); + return 0; }