From patchwork Fri Jun 15 11:57:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksij Rempel X-Patchwork-Id: 10466265 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 12E3D60532 for ; Fri, 15 Jun 2018 11:57:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 03BD528D60 for ; Fri, 15 Jun 2018 11:57:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EC50128D71; Fri, 15 Jun 2018 11:57:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3B6A228D6D for ; Fri, 15 Jun 2018 11:57:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755881AbeFOL5i (ORCPT ); Fri, 15 Jun 2018 07:57:38 -0400 Received: from metis.ext.pengutronix.de ([85.220.165.71]:43093 "EHLO metis.ext.pengutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755650AbeFOL5i (ORCPT ); Fri, 15 Jun 2018 07:57:38 -0400 Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]) by metis.ext.pengutronix.de with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1fTnMF-0002dO-AD; Fri, 15 Jun 2018 13:57:35 +0200 Received: from ore by dude.hi.pengutronix.de with local (Exim 4.91) (envelope-from ) id 1fTnMD-0004oV-8m; Fri, 15 Jun 2018 13:57:33 +0200 From: Oleksij Rempel To: Ohad Ben-Cohen , Bjorn Andersson , Rob Herring , Mark Rutland , "A.s. Dong" Cc: Oleksij Rempel , kernel@pengutronix.de, linux-remoteproc@vger.kernel.org, devicetree@vger.kernel.org, dl-linux-imx Subject: [PATCH v1 2/2] remoteproc: imx_rproc: assign other DT nodes to rproc node Date: Fri, 15 Jun 2018 13:57:31 +0200 Message-Id: <20180615115731.18424-2-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180615115731.18424-1-o.rempel@pengutronix.de> References: <20180615115731.18424-1-o.rempel@pengutronix.de> X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-remoteproc@vger.kernel.org Sender: linux-remoteproc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-remoteproc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP At least on i.MX* most of devices are available to all CPUs. In this case the master system should know early enough how system should be split and preconfigured. For example if we start Linux on other part of the system, we will need properly configured clocks for some predefined rates. Pin, reset and power state should be controlled by master system as well. Signed-off-by: Oleksij Rempel --- drivers/remoteproc/imx_rproc.c | 160 +++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 45acc2ce930d..1999e50f5d4c 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -47,6 +47,8 @@ | IMX6SX_SW_M4C_RST) #define IMX7D_RPROC_MEM_MAX 8 +#define IMX7D_RPROC_RNODES_MAX 8 +#define IMX7D_RPROC_RNODE_CLKS_MAX 8 /** * struct imx_rproc_mem - slim internal memory structure @@ -81,6 +83,12 @@ struct imx_rproc_dcfg { size_t att_size; }; +struct imx_rproc_rnode { + struct device_node *node; + struct clk *clk[IMX7D_RPROC_RNODE_CLKS_MAX]; + unsigned int clks; +}; + struct imx_rproc { struct device *dev; struct regmap *regmap; @@ -88,6 +96,8 @@ struct imx_rproc { const struct imx_rproc_dcfg *dcfg; struct imx_rproc_mem mem[IMX7D_RPROC_MEM_MAX]; struct clk *clk; + struct imx_rproc_rnode rnode[IMX7D_RPROC_RNODES_MAX]; + unsigned int rnodes; }; static const struct imx_rproc_att imx_rproc_att_imx7d[] = { @@ -250,6 +260,142 @@ static const struct rproc_ops imx_rproc_ops = { .da_to_va = imx_rproc_da_to_va, }; +static int imx_rproc_set_clk_rates(struct device_node *node, bool clk_supplier) +{ + struct of_phandle_args clkspec; + struct property *prop; + const __be32 *cur; + int rc, index = 0; + struct clk *clk; + u32 rate; + + of_property_for_each_u32(node, "assigned-clock-rates", prop, cur, rate) { + if (rate) { + rc = of_parse_phandle_with_args(node, "clocks", + "#clock-cells", index, &clkspec); + if (rc < 0) { + /* skip empty (null) phandles */ + if (rc == -ENOENT) + continue; + else + return rc; + } + if (clkspec.np == node && !clk_supplier) + return 0; + + clk = of_clk_get_from_provider(&clkspec); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + pr_warn("clk: couldn't get clock %d for %s\n", + index, node->full_name); + return PTR_ERR(clk); + } + + rc = clk_set_rate(clk, rate); + if (rc < 0) + pr_err("clk: couldn't set clk rate to %u (%d), current rate: %lu\n", + rate, rc, + clk_get_rate(clk)); + clk_put(clk); + } + index++; + } + return 0; +} + +static int imx_rproc_set_rclks(struct imx_rproc *priv, struct imx_rproc_rnode *rn) +{ + struct device_node *node = rn->node; + struct device *dev = priv->dev; + struct of_phandle_args clkspec; + int index, rc, ret, num_parents; + struct clk *clk; + + imx_rproc_set_clk_rates(node, 0); + num_parents = of_count_phandle_with_args(node, "clocks", "#clock-cells"); + if (num_parents == -EINVAL) { + dev_err(dev, "clk: invalid value of clocks property at %s\n", + node->full_name); + return -EINVAL; + } + + if (IMX7D_RPROC_RNODE_CLKS_MAX < num_parents) { + dev_err(dev, "unsupported count of remote clocks: %i, max: %i\n", + num_parents, IMX7D_RPROC_RNODE_CLKS_MAX); + return -EINVAL; + } + + for (index = 0; index < num_parents; index++) { + rc = of_parse_phandle_with_args(node, "clocks", + "#clock-cells", index, &clkspec); + if (rc < 0) + goto err; + + if (clkspec.np == node) { + rc = 0; + goto err; + } + + clk = of_clk_get_from_provider(&clkspec); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_warn(dev, "clk: couldn't get assigned clock %d for %s\n", + index, node->full_name); + rc = PTR_ERR(clk); + goto err; + } + + rn->clk[index] = clk; + rn->clks++; + /* + * clk for M4 block including memory. Should be + * enabled before .start for FW transfer. + */ + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(dev, "Failed to enable clock\n"); + return ret; + } + } + return 0; +err: + return rc; +} + +static int imx_rproc_rnodes_init(struct imx_rproc *priv) +{ + struct device *dev = priv->dev; + struct device_node *node = dev->of_node; + int a, err, num_parents; + + num_parents = of_count_phandle_with_args(node, "remote-nodes", NULL); + if (num_parents == -EINVAL) { + dev_err(dev, "rnote: invalid value of remote-node property at %s\n", + node->full_name); + return -EINVAL; + } + + if (IMX7D_RPROC_RNODES_MAX < num_parents) { + dev_err(dev, "unsupported count of remote node: %i, max: %i\n", + num_parents, IMX7D_RPROC_RNODES_MAX); + return -EINVAL; + } + + /* remap optional addresses */ + for (a = 0; a < num_parents; a++) { + struct device_node *rn; + + rn = of_parse_phandle(node, "remote-nodes", a); + priv->rnode[a].node = rn; + priv->rnodes++; + err = imx_rproc_set_rclks(priv, &priv->rnode[a]); + if (err) + break; + } + + return err; +} + static int imx_rproc_addr_init(struct imx_rproc *priv, struct platform_device *pdev) { @@ -374,6 +520,12 @@ static int imx_rproc_probe(struct platform_device *pdev) goto err_put_rproc; } + ret = imx_rproc_rnodes_init(priv); + if (ret) { + dev_err(dev, "filed on imx_rproc_rnodes_init\n"); + goto err_put_rproc; + } + ret = rproc_add(rproc); if (ret) { dev_err(dev, "rproc_add failed\n"); @@ -394,6 +546,14 @@ static int imx_rproc_remove(struct platform_device *pdev) { struct rproc *rproc = platform_get_drvdata(pdev); struct imx_rproc *priv = rproc->priv; + int a, b; + + for (a = 0; a < priv->rnodes; a++) { + struct imx_rproc_rnode *rn = &priv->rnode[a]; + + for (b = 0; b < rn->clks; b++) + clk_disable_unprepare(rn->clk[b]); + } clk_disable_unprepare(priv->clk); rproc_del(rproc);