From patchwork Thu Nov 24 10:25:27 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Boyd X-Patchwork-Id: 83852 Delivered-To: patch@linaro.org Received: by 10.140.20.101 with SMTP id 92csp65819qgi; Thu, 24 Nov 2016 02:27:22 -0800 (PST) X-Received: by 10.84.170.195 with SMTP id j61mr3854555plb.13.1479983242328; Thu, 24 Nov 2016 02:27:22 -0800 (PST) Return-Path: Received: from bombadil.infradead.org (bombadil.infradead.org. [2001:1868:205::9]) by mx.google.com with ESMTPS id w67si38676011pfd.222.2016.11.24.02.27.22 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Nov 2016 02:27:22 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org designates 2001:1868:205::9 as permitted sender) client-ip=2001:1868:205::9; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org designates 2001:1868:205::9 as permitted sender) smtp.mailfrom=linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1c9rES-0000px-KQ; Thu, 24 Nov 2016 10:26:20 +0000 Received: from mail-pg0-x233.google.com ([2607:f8b0:400e:c05::233]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1c9rE1-0000gP-PL for linux-arm-kernel@lists.infradead.org; Thu, 24 Nov 2016 10:25:55 +0000 Received: by mail-pg0-x233.google.com with SMTP id x23so17366433pgx.1 for ; Thu, 24 Nov 2016 02:25:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=DHfkQlEMm03ExaIqL0a/g/4okjA2QTgfjrN5Xnsj9y0=; b=kBm3dHlBw6Al1B/GnncOiXcYon1HRMs2r17r9Hg7mVr94kJt3LCDf+cPJi2KT7wLD4 kIeGQyS2siIiUDAIbzyQye60282DE4LIEZ2gLL86OKYs14XKUia4qR3xUo2kxMcLDcIf 13/qb/WMS3mNQiFwoXorkHlQ3bqjo2fIVnRvk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=DHfkQlEMm03ExaIqL0a/g/4okjA2QTgfjrN5Xnsj9y0=; b=M1d8ZyMfViNsvr1NpPb4LY0a/U65JfTJZVZG/HftfPjYiKUEJoH1bJLykQAws1ubOn 9xCm26XRFQ4DFLVU0GMcDzLBggyrbdM/cE/8JY5YfmhRujfpCzuLGdwC4cH7Qm+p/lKX 4lOnOJnaay5vFVYUfXZhl7iPP+8jOlfAvXxGZN1dBKdtvPfr13spCc8s/IA+1CdstoIF wyz2KFiSPnfw3YJV2hHZjOGTvFfX171s1RPNpyiV9H0h/DXLTNO+T6bJ7UWWr5GnF6iq Y53h8g8UOgKxbSqvkItEMJD9VX46f7+I7CfyeKRd1gtmiie8CF8ngSid1brcOSYmGTUb I1pA== X-Gm-Message-State: AKaTC03Q1Yi7HRbMGDh3CGtWF0vRiQqozPLXMyHdCccGWfRHqHXseMdsL7e7+xq9CWCwQ9X0 X-Received: by 10.84.150.231 with SMTP id h94mr3806921plh.3.1479983133137; Thu, 24 Nov 2016 02:25:33 -0800 (PST) Received: from localhost.localdomain (ip68-101-172-78.sd.sd.cox.net. [68.101.172.78]) by smtp.gmail.com with ESMTPSA id x26sm38694248pge.24.2016.11.24.02.25.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 24 Nov 2016 02:25:32 -0800 (PST) From: Stephen Boyd To: Rob Herring , Frank Rowand Subject: [PATCH 1/3] of: Support parsing phandle argument lists through a nexus node Date: Thu, 24 Nov 2016 02:25:27 -0800 Message-Id: <20161124102529.20212-2-stephen.boyd@linaro.org> X-Mailer: git-send-email 2.10.0.297.gf6727b0 In-Reply-To: <20161124102529.20212-1-stephen.boyd@linaro.org> References: <20161124102529.20212-1-stephen.boyd@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161124_022553_958016_690E6A5D X-CRM114-Status: GOOD ( 22.30 ) X-Spam-Score: -2.0 (--) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-2.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [2607:f8b0:400e:c05:0:0:0:233 listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, Linus Walleij , Pantelis Antoniou , linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, Mark Brown , linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org Platforms like 96boards have a standardized connector/expansion slot that exposes signals like GPIOs to expansion boards in an SoC agnostic way. We'd like the DT overlays for the expansion boards to be written once without knowledge of the SoC on the other side of the connector. This avoids the unscalable combinatorial explosion of a different DT overlay for each expansion board and SoC pair. We need a way to describe the GPIOs routed through the connector in an SoC agnostic way. Let's introduce nexus property parsing into the OF core to do this. This is largely based on the interrupt nexus support we already have. This allows us to remap a phandle list in a consumer node (e.g. reset-gpios) through a connector in a generic way (e.g. via gpio-map). Do this in a generic routine so that we can remap any sort of variable length phandle list. Taking GPIOs as an example, the connector would be a GPIO nexus, supporting the remapping of a GPIO specifier space to multiple GPIO providers on the SoC. DT would look as shown below, where 'soc_gpio1' and 'soc_gpio2' are inside the SoC, 'connector' is an expansion port where boards can be plugged in, and 'expansion_device' is a device on the expansion board. soc { soc_gpio1: gpio-controller1 { #gpio-cells = <2>; }; soc_gpio2: gpio-controller2 { #gpio-cells = <2>; }; }; connector: connector { #gpio-cells = <2>; gpio-map = <0 GPIO_ACTIVE_LOW &soc_gpio1 1 GPIO_ACTIVE_LOW>, <1 GPIO_ACTIVE_LOW &soc_gpio2 4 GPIO_ACTIVE_LOW>, <2 GPIO_ACTIVE_LOW &soc_gpio1 3 GPIO_ACTIVE_LOW>, <3 GPIO_ACTIVE_LOW &soc_gpio2 2 GPIO_ACTIVE_LOW>; gpio-map-mask = <0xf 0x1>; }; expansion_device { reset-gpios = <&connector 2 GPIO_ACTIVE_LOW>; }; The GPIO core would use of_parse_phandle_with_args_map() instead of of_parse_phandle_with_args() and arrive at the same type of result, a phandle and argument list. The difference is that the phandle and arguments will be remapped through the nexus node to the underlying SoC GPIO controller node. In the example above, we would remap 'reset-gpios' from <&connector 2 GPIO_ACTIVE_LOW> to <&soc_gpio1 3 GPIO_ACTIVE_LOW>. Cc: Pantelis Antoniou Cc: Linus Walleij Cc: Mark Brown Signed-off-by: Stephen Boyd --- drivers/of/base.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 14 +++++ 2 files changed, 160 insertions(+) -- 2.10.0.297.gf6727b0 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel diff --git a/drivers/of/base.c b/drivers/of/base.c index d687e6de24a0..693b73f33675 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1772,6 +1772,152 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na EXPORT_SYMBOL(of_parse_phandle_with_args); /** + * of_parse_phandle_with_args_map() - Find a node pointed by phandle in a list and remap it + * @np: pointer to a device tree node containing a list + * @list_name: property name that contains a list + * @cells_name: property name that specifies phandles' arguments count + * @index: index of a phandle to parse out + * @out_args: optional pointer to output arguments structure (will be filled) + * + * This function is useful to parse lists of phandles and their arguments. + * Returns 0 on success and fills out_args, on error returns appropriate + * errno value. + * + * Caller is responsible to call of_node_put() on the returned out_args->np + * pointer. + * + * Example: + * + * phandle1: node1 { + * #list-cells = <2>; + * } + * + * phandle2: node2 { + * #list-cells = <1>; + * } + * + * phandle3: node3 { + * #list-cells = <1>; + * list-map = <0 &phandle2 3>, + * <1 &phandle2 2>, + * <2 &phandle1 5 1>; + * list-map-mask = <0x3>; + * }; + * + * node4 { + * list = <&phandle1 1 2 &phandle3 0>; + * } + * + * To get a device_node of the `node2' node you may call this: + * of_parse_phandle_with_args(node4, "list", "#list-cells", "list-map", + * "list-map-mask", 1, &args); + */ +int of_parse_phandle_with_args_map(const struct device_node *np, + const char *list_name, + const char *cells_name, + const char *map_name, + const char *mask_name, + int index, struct of_phandle_args *out_args) +{ + struct device_node *cur, *new = NULL; + const __be32 *map, *mask, *tmp; + const __be32 dummy_mask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 }; + __be32 initial_match_array[MAX_PHANDLE_ARGS]; + const __be32 *match_array = initial_match_array; + int i, ret, map_len, match; + u32 list_size, new_size; + + if (index < 0) + return -EINVAL; + + ret = __of_parse_phandle_with_args(np, list_name, cells_name, 0, index, + out_args); + if (ret) + return ret; + + /* Get the #-cells property */ + cur = out_args->np; + ret = of_property_read_u32(cur, cells_name, &list_size); + if (ret < 0) + goto fail; + + /* Precalculate the match array - this simplifies match loop */ + for (i = 0; i < list_size; i++) + initial_match_array[i] = cpu_to_be32(out_args->args[i]); + + while (cur) { + /* Get the -map property */ + map = of_get_property(cur, map_name, &map_len); + if (!map) + return 0; + map_len /= sizeof(u32); + + /* Get the -map-mask property (optional) */ + mask = of_get_property(cur, mask_name, NULL); + if (!mask) + mask = dummy_mask; + + /* Iterate through -map property */ + match = 0; + while (map_len > (list_size + 1) && !match) { + /* Compare specifiers */ + match = 1; + for (i = 0; i < list_size; i++, map_len--) + match &= !((match_array[i] ^ *map++) & mask[i]); + + of_node_put(new); + new = of_find_node_by_phandle(be32_to_cpup(map)); + map++; + map_len--; + + /* Check if not found */ + if (!new) + goto fail; + + if (!of_device_is_available(new)) + match = 0; + + tmp = of_get_property(new, cells_name, NULL); + if (!tmp) + goto fail; + + new_size = be32_to_cpu(*tmp); + + /* Check for malformed properties */ + if (WARN_ON(new_size > MAX_PHANDLE_ARGS)) + goto fail; + if (map_len < new_size) + goto fail; + + /* Move forward by new node's #-cells amount */ + map += new_size; + map_len -= new_size; + } + if (!match) + goto fail; + + /* + * Successfully parsed a -map translation; copy new + * specifier into the out_args structure. + */ + match_array = map - new_size; + for (i = 0; i < new_size; i++) + out_args->args[i] = be32_to_cpup(map - new_size + i); + out_args->args_count = list_size = new_size; + /* Iterate again with new provider */ + out_args->np = new; + of_node_put(cur); + cur = new; + } +fail: + of_node_put(cur); + of_node_put(new); + + return -EINVAL; +} +EXPORT_SYMBOL(of_parse_phandle_with_args_map); + +/** * of_parse_phandle_with_fixed_args() - Find a node pointed by phandle in a list * @np: pointer to a device tree node containing a list * @list_name: property name that contains a list diff --git a/include/linux/of.h b/include/linux/of.h index d3a9c2e69001..65ff306403a2 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -344,6 +344,9 @@ extern struct device_node *of_parse_phandle(const struct device_node *np, extern int of_parse_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name, int index, struct of_phandle_args *out_args); +extern int of_parse_phandle_with_args_map(const struct device_node *np, + const char *list_name, const char *cells_name, const char *map_name, + const char *mask_name, int index, struct of_phandle_args *out_args); extern int of_parse_phandle_with_fixed_args(const struct device_node *np, const char *list_name, int cells_count, int index, struct of_phandle_args *out_args); @@ -738,6 +741,17 @@ static inline int of_parse_phandle_with_args(const struct device_node *np, return -ENOSYS; } +static inline int of_parse_phandle_with_args_map(const struct device_node *np, + const char *list_name, + const char *cells_name, + const char *map_name, + const char *mask_name, + int index, + struct of_phandle_args *out_args) +{ + return -ENOSYS; +} + static inline int of_parse_phandle_with_fixed_args(const struct device_node *np, const char *list_name, int cells_count, int index, struct of_phandle_args *out_args)