From patchwork Thu Aug 20 13:40:27 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bin Meng X-Patchwork-Id: 509056 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id AC914140297 for ; Thu, 20 Aug 2015 23:51:37 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=wemah0S7; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 491784B62B; Thu, 20 Aug 2015 15:51:36 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZUlvVNQMlDHw; Thu, 20 Aug 2015 15:51:36 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 8667E4B616; Thu, 20 Aug 2015 15:50:07 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 7B8E24B616 for ; Thu, 20 Aug 2015 15:39:48 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jtxd2zjdcVG2 for ; Thu, 20 Aug 2015 15:39:48 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-pa0-f41.google.com (mail-pa0-f41.google.com [209.85.220.41]) by theia.denx.de (Postfix) with ESMTPS id 835564B65A for ; Thu, 20 Aug 2015 15:38:31 +0200 (CEST) Received: by padfo6 with SMTP id fo6so22796628pad.0 for ; Thu, 20 Aug 2015 06:38:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:message-id:in-reply-to:references; bh=ctr6+yyTmWxIOZpOlRW6KS0xDS8dHd+acAXVPQ/Hy6U=; b=wemah0S7ZG2HE6zaJRgUI6PM4RftHE7oXD9ICWoS7mpJ2nFvIzk3l/JU2XNLE/hk5R p4N4LL7SGZv3e8P3c9zYlWTQvdslojMTDp1QVFVREz89EVrIyl9K6eLf+QIdqAPi4OIm +9Sq1ly3Kk1Ef1mr5XxaK8XFU1rRrfRH6wr54m02aPL3TWLPZRzc8yyQs2RN1o1c3aot SEY3W3JrjEOGf8S4yaylIAGne1n5W/7yeaZw2IadKqCGtA5Oyr5+hpvSVAw+nZkTauyL XEL78UJVhu3f5oF8wIVXgwuTN7ZmesDg2NwC/3+pIuObw64+eg9jDe1IP1dxTZIZKAJ9 KOAA== X-Received: by 10.66.233.1 with SMTP id ts1mr6456563pac.128.1440077907230; Thu, 20 Aug 2015 06:38:27 -0700 (PDT) Received: from ala-d2121-lx1.wrs.com (unknown-157-139.windriver.com. [147.11.157.139]) by smtp.gmail.com with ESMTPSA id fe8sm4464075pab.40.2015.08.20.06.38.26 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 20 Aug 2015 06:38:26 -0700 (PDT) From: Bin Meng To: Simon Glass , U-Boot Mailing List Date: Thu, 20 Aug 2015 06:40:27 -0700 Message-Id: <1440078028-29464-12-git-send-email-bmeng.cn@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1440078028-29464-1-git-send-email-bmeng.cn@gmail.com> References: <1440078028-29464-1-git-send-email-bmeng.cn@gmail.com> Subject: [U-Boot] [PATCH v2 11/12] dm: pci: Really support binding pci device in the device tree X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" The dm pci doc says it supports binding pci device which appears in the device tree. However it is not true, at least on Intel Crown Bay. Currently the crownbay.dts defines 4 pci uart devices within the pci bus controller's node. pci_find_and_bind_driver() only scans U_BOOT_PCI_DEVICE defined driver list and if nothing is found, it binds devices to bridge driver or generic driver. Now we change the codes to first scan device tree for any pci devices listed there, if nothing go on with previous logic. With this commit, we can get pci uart work on Intel Crown Bay. The previous 'dm tree' output before this commit is: pci [ + ] | | `-- pci_1:0.0 pci_generic [ ] | | |-- pci_2:0.0 ...... pci_generic [ ] | | |-- pci_2:a.0 pci_generic [ ] | | |-- pci_2:a,1 pci_generic [ ] | | |-- pci_2:a,2 pci_generic [ ] | | |-- pci_2:a,3 pci_generic [ ] | | |-- pci_2:a,4 pci_generic [ ] | | |-- pci_2:c.0 ...... We have device nodes for 2:a,1/2:a,2/2:a,3/2:a,4, now we get: pci [ + ] | | `-- pci_1:0.0 pci_generic [ ] | | |-- pci_2:0.0 ...... pci_generic [ ] | | |-- pci_2:a.0 serial [ ] | | |-- uart@a,1 serial [ ] | | |-- uart@a,2 serial [ ] | | |-- uart@a,3 serial [ ] | | |-- uart@a,4 pci_generic [ ] | | |-- pci_2:c.0 ...... Signed-off-by: Bin Meng --- Changes in v2: None drivers/pci/pci-uclass.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++ include/pci.h | 11 +++++ 2 files changed, 114 insertions(+) diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 4a509a2..1e4d9be 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -450,6 +450,82 @@ static bool pci_match_one_id(const struct pci_device_id *id, return false; } +static int pci_scan_fdt_node(struct udevice *bus, + struct pci_fdt_info **find_info, int *num) +{ + struct pci_root_priv *priv; + struct pci_fdt_info *fdt_info; + const void *fdt = gd->fdt_blob; + int offset, root_offset; + u16 vendor, device; + int i = 0; + + /* get root bus device */ + do { + if (device_get_uclass_id(bus->parent) == UCLASS_ROOT) + break; + bus = bus->parent; + } while (bus); + + priv = bus->priv; + if (!priv) { + priv = calloc(1, sizeof(struct pci_root_priv)); + if (!priv) + return -ENOMEM; + bus->priv = priv; + } + + /* + * Scan device tree from root bus node + * + * We scan device tree to check if any pci device is specified + * in the device tree. The device tree will be scanned twice. + * After the first scan we know how many pci device nodes are + * there. For the second scan we save pci device's vendor id & + * device id as well as its device tree node offset. + */ + if (!priv->fdt_scanned) { + root_offset = bus->of_offset; + + /* first scan */ + for (offset = fdt_next_node(fdt, root_offset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (!fdtdec_get_pci_vendev(fdt, offset, + &vendor, &device)) + priv->fdt_info_entries++; + } + + if (priv->fdt_info_entries) { + fdt_info = calloc(priv->fdt_info_entries, + sizeof(struct pci_fdt_info)); + if (!fdt_info) + return -ENOMEM; + priv->fdt_info = fdt_info; + + /* second scan */ + for (offset = fdt_next_node(fdt, root_offset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (!fdtdec_get_pci_vendev(fdt, offset, + &vendor, &device)) { + fdt_info[i].vendor = vendor; + fdt_info[i].device = device; + fdt_info[i].offset = offset; + i++; + } + } + } + + priv->fdt_scanned = true; + } + + *find_info = priv->fdt_info; + *num = priv->fdt_info_entries; + + return 0; +} + /** * pci_find_and_bind_driver() - Find and bind the right PCI driver * @@ -465,11 +541,33 @@ static int pci_find_and_bind_driver(struct udevice *parent, int ret; char name[30], *str; bool bridge; + struct pci_fdt_info *find_info; + int i, num; *devp = NULL; debug("%s: Searching for driver: vendor=%x, device=%x\n", __func__, find_id->vendor, find_id->device); + + /* Scan device tree to see if any pci device is listed */ + ret = pci_scan_fdt_node(parent, &find_info, &num); + if (ret) + goto error; + if (find_info) { + for (i = 0; i < num; i++) { + if (find_id->vendor == find_info->vendor && + find_id->device == find_info->device) { + ret = lists_bind_fdt(parent, gd->fdt_blob, + find_info->offset, devp); + if (ret) + goto error; + return 0; + } + find_info++; + } + } + + /* Then check U_BOOT_PCI_DEVICE defined driver list */ start = ll_entry_start(struct pci_driver_entry, pci_driver_entry); n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry); for (entry = start; entry != start + n_ents; entry++) { @@ -514,6 +612,11 @@ static int pci_find_and_bind_driver(struct udevice *parent, } } + /* + * If we don't find any match driver above, bind the device to + * predefined driver - "pci_bridge_drv" or "pci_generic_drv". + */ + bridge = (find_id->class >> 8) == PCI_CLASS_BRIDGE_PCI; /* * In the pre-relocation phase, we only bind bridge devices to save diff --git a/include/pci.h b/include/pci.h index 488ff44..a2d4ef2 100644 --- a/include/pci.h +++ b/include/pci.h @@ -512,6 +512,17 @@ struct pci_device_id { unsigned long driver_data; /* Data private to the driver */ }; +struct pci_fdt_info { + unsigned int vendor, device; /* Vendor and device ID*/ + unsigned int offset; /* Device tree offset */ +}; + +struct pci_root_priv { + struct pci_fdt_info *fdt_info; + int fdt_info_entries; + bool fdt_scanned; +}; + struct pci_controller; struct pci_config_table {