Received: by 2002:a05:6a10:7420:0:0:0:0 with SMTP id hk32csp4452562pxb; Mon, 21 Feb 2022 22:04:37 -0800 (PST) X-Google-Smtp-Source: ABdhPJwj+qowh/wDNRCrWom7H+J/ly2w+imeRpZOY0DRDBSQkxFfgcvmPySrXJaPVDyB+KdL+sWU X-Received: by 2002:a05:6a00:2341:b0:4e1:5aa4:9aff with SMTP id j1-20020a056a00234100b004e15aa49affmr23541699pfj.8.1645509877800; Mon, 21 Feb 2022 22:04:37 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1645509877; cv=none; d=google.com; s=arc-20160816; b=1FYgaGtKovechkVZyTFT6F8lBlgruF3EJmYv4Y3pbS635lXW7uBh0lBkyBmz20HGvI 0VIHhqVScbfRJLXUOdn4gS4QlLUD4RODatSaixsUvDE+RMW75DE6J6iX+egUh8svhrFT 0MGKtg6aqaxQrzHJ3h2O1sH8vBtgVBWOTR8hT5/ONK1lbMBBBWPTH6GvXGw9qEEtAczJ JR7uVAw4MPi8KSb83bHoQwDJUs/Kk6azwR9qZ/luYjEeGDpVaQKTKp2IumdUBU5tE5W5 rVHWFq8+19tktNbvwoX391+O0HhaOR3ipa9f1DlPMv5h6f2f9EIGv+o+s1XWHpBw/2Ix DTHw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:to:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:from :dkim-signature; bh=1JhQU79LwmjUREbXDgORsqQdFfEo1FUJcH98p5ko4to=; b=lRBsJRFfwxbSbIoJ9tjf8wuVAJtbOslm1JpJ3BpYndzVIS0MMVWawLZdYpOsnUzuz4 /79CRQR0zGzBks+01fOTsd7s6M3C/ywnS//9lPaySc8JmFh9B928zlcMwLvAP4YOzZxG PEQh16UhiHoBJT5kFYoTpj4Yszr8UKQmDwAuDAYiTh5ru3PNQQoiN7mYRqZIzE9xq5+l LLgREKoVrHJzGoDSRGpDOFQ65l5FWfxFCe7iFFwI4pa6d77dFCTlaRqs+KW5WMvW58OH KLaeIw4iUPQPAWWbgBjqlYQ3heWq8lHqmD0wItXxhLuySYjKOyDFHbeWAXTmXMnuCCqP gOZA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@metrotek.ru header.s=mail header.b=HR3dhqWI; spf=softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [23.128.96.19]) by mx.google.com with ESMTPS id f18si33575128plg.79.2022.02.21.22.04.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Feb 2022 22:04:37 -0800 (PST) Received-SPF: softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) client-ip=23.128.96.19; Authentication-Results: mx.google.com; dkim=fail header.i=@metrotek.ru header.s=mail header.b=HR3dhqWI; spf=softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7E8BD9AE69; Mon, 21 Feb 2022 21:39:58 -0800 (PST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229776AbiBVFkQ (ORCPT + 99 others); Tue, 22 Feb 2022 00:40:16 -0500 Received: from gmail-smtp-in.l.google.com ([23.128.96.19]:57134 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229723AbiBVFjw (ORCPT ); Tue, 22 Feb 2022 00:39:52 -0500 Received: from mail.pr-group.ru (mail.pr-group.ru [178.18.215.3]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1A4CD95A37 for ; Mon, 21 Feb 2022 21:39:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=metrotek.ru; s=mail; h=from:subject:date:message-id:to:cc:mime-version:content-transfer-encoding: in-reply-to:references; bh=6bxiRaq+iqtuJ7foBluUPbLSTNYzP7L3/TvXFtYh2HU=; b=HR3dhqWItJgW3mg9TdyxqTvNt0ywZdhKZbEk2zyjajrV9mQo5DQfZ6AKfVaT4gYs2Tw4VcCPJYU9X /xW5Zs9NNTxuA3lZJSA1SoySMZmXnUAmmDcAgTR7O5b3qURVRgrj4xnk1NtOYboY3kkyMV0EkjMFtv eHkaoRax9LOt9UJT2lOLgf/qolUq0RKFcwnNgORUlNbipzgQFg9FmE1kWaVXqAmoHOUMKEGtmHj4Ux M1QO6zH1hSQ1L0rtX7zwc7GItUZbkQ230f5S/exxne+addOFGeStVNjBLI48rfUxRic1ascGER65pH JO+unjA6Ssx0V2jmOkiihle3RlGh8lQ== X-Kerio-Anti-Spam: Build: [Engines: 2.16.2.1403, Stamp: 3], Multi: [Enabled, t: (0.000009,0.028380)], BW: [Enabled, t: (0.000023,0.000002)], RTDA: [Enabled, t: (0.068177), Hit: No, Details: v2.25.0; Id: 15.52k0hi.1fsfv1l2f.62kd; mclb], total: 0(700) X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RDNS_NONE, SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Level: X-Footer: bWV0cm90ZWsucnU= Received: from localhost.localdomain ([178.70.66.234]) (authenticated user i.bornyakov@metrotek.ru) by mail.pr-group.ru with ESMTPSA (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256 bits)); Tue, 22 Feb 2022 08:39:09 +0300 From: Ivan Bornyakov Cc: shawnguo@kernel.org, s.hauer@pengutronix.de, festevam@gmail.com, kernel@pengutronix.de, linux-imx@nxp.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, system@metrotek.ru, Ivan Bornyakov Subject: [PATCH v3] bus: imx-weim: add DT overlay support for WEIM bus Date: Tue, 22 Feb 2022 08:20:59 +0300 Message-Id: <20220222052059.23610-1-i.bornyakov@metrotek.ru> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220205055006.23447-1-i.bornyakov@metrotek.ru> References: <20220205055006.23447-1-i.bornyakov@metrotek.ru> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add OF reconfiguration notifier handler for WEIM bus to setup Chip Select timings on runtime creation of child devices. However, it is not possible to load another DT overlay with conflicting CS timings with previously loaded overlay, even if the first one is unloaded. The reason is that there is no acces to CS timing property of a device node being removed, thus we can't track which of configured CS are available for re-configuration. Signed-off-by: Ivan Bornyakov --- Changelog: v1 -> v2: minor style fixes * rename "priv" -> weim_priv" * remove excessive newline v2 -> v3: minor style fixes * rename "weim_data *weim_priv" -> "weim_priv *priv" drivers/bus/imx-weim.c | 135 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 126 insertions(+), 9 deletions(-) diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index bccb275b65ba..60fbd42041dd 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -64,6 +64,11 @@ struct cs_timing_state { struct cs_timing cs[MAX_CS_COUNT]; }; +struct weim_priv { + void __iomem *base; + struct cs_timing_state timing_state; +}; + static const struct of_device_id weim_id_table[] = { /* i.MX1/21 */ { .compatible = "fsl,imx1-weim", .data = &imx1_weim_devtype, }, @@ -128,21 +133,26 @@ static int imx_weim_gpr_setup(struct platform_device *pdev) } /* Parse and set the timing for this device. */ -static int weim_timing_setup(struct device *dev, - struct device_node *np, void __iomem *base, - const struct imx_weim_devtype *devtype, - struct cs_timing_state *ts) +static int weim_timing_setup(struct device *dev, struct device_node *np, + const struct imx_weim_devtype *devtype) { u32 cs_idx, value[MAX_CS_REGS_COUNT]; int i, ret; int reg_idx, num_regs; struct cs_timing *cst; + struct weim_priv *priv; + struct cs_timing_state *ts; + void __iomem *base; if (WARN_ON(devtype->cs_regs_count > MAX_CS_REGS_COUNT)) return -EINVAL; if (WARN_ON(devtype->cs_count > MAX_CS_COUNT)) return -EINVAL; + priv = dev_get_drvdata(dev); + base = priv->base; + ts = &priv->timing_state; + ret = of_property_read_u32_array(np, "fsl,weim-cs-timing", value, devtype->cs_regs_count); if (ret) @@ -189,14 +199,15 @@ static int weim_timing_setup(struct device *dev, return 0; } -static int weim_parse_dt(struct platform_device *pdev, void __iomem *base) +static int weim_parse_dt(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(weim_id_table, &pdev->dev); const struct imx_weim_devtype *devtype = of_id->data; struct device_node *child; int ret, have_child = 0; - struct cs_timing_state ts = {}; + struct weim_priv *priv; + void __iomem *base; u32 reg; if (devtype == &imx50_weim_devtype) { @@ -205,6 +216,9 @@ static int weim_parse_dt(struct platform_device *pdev, void __iomem *base) return ret; } + priv = dev_get_drvdata(&pdev->dev); + base = priv->base; + if (of_property_read_bool(pdev->dev.of_node, "fsl,burst-clk-enable")) { if (devtype->wcr_bcm) { reg = readl(base + devtype->wcr_offset); @@ -229,7 +243,7 @@ static int weim_parse_dt(struct platform_device *pdev, void __iomem *base) } for_each_available_child_of_node(pdev->dev.of_node, child) { - ret = weim_timing_setup(&pdev->dev, child, base, devtype, &ts); + ret = weim_timing_setup(&pdev->dev, child, devtype); if (ret) dev_warn(&pdev->dev, "%pOF set timing failed.\n", child); @@ -248,17 +262,25 @@ static int weim_parse_dt(struct platform_device *pdev, void __iomem *base) static int weim_probe(struct platform_device *pdev) { + struct weim_priv *priv; struct resource *res; struct clk *clk; void __iomem *base; int ret; + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + /* get the resource */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) return PTR_ERR(base); + priv->base = base; + dev_set_drvdata(&pdev->dev, priv); + /* get the clock */ clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) @@ -269,7 +291,7 @@ static int weim_probe(struct platform_device *pdev) return ret; /* parse the device node */ - ret = weim_parse_dt(pdev, base); + ret = weim_parse_dt(pdev); if (ret) clk_disable_unprepare(clk); else @@ -278,6 +300,81 @@ static int weim_probe(struct platform_device *pdev) return ret; } +#if IS_ENABLED(CONFIG_OF_DYNAMIC) +static int of_weim_notify(struct notifier_block *nb, unsigned long action, + void *arg) +{ + const struct imx_weim_devtype *devtype; + struct of_reconfig_data *rd = arg; + const struct of_device_id *of_id; + struct platform_device *pdev; + int ret = NOTIFY_OK; + + switch (of_reconfig_get_state_change(action, rd)) { + case OF_RECONFIG_CHANGE_ADD: + of_id = of_match_node(weim_id_table, rd->dn->parent); + if (!of_id) + return NOTIFY_OK; /* not for us */ + + devtype = of_id->data; + + pdev = of_find_device_by_node(rd->dn->parent); + if (!pdev) { + pr_err("%s: could not find platform device for '%pOF'\n", + __func__, rd->dn->parent); + + return notifier_from_errno(-EINVAL); + } + + if (weim_timing_setup(&pdev->dev, rd->dn, devtype)) + dev_warn(&pdev->dev, + "Failed to setup timing for '%pOF'\n", rd->dn); + + if (!of_node_check_flag(rd->dn, OF_POPULATED)) { + if (!of_platform_device_create(rd->dn, NULL, &pdev->dev)) { + dev_err(&pdev->dev, + "Failed to create child device '%pOF'\n", + rd->dn); + ret = notifier_from_errno(-EINVAL); + } + } + + platform_device_put(pdev); + + break; + case OF_RECONFIG_CHANGE_REMOVE: + if (!of_node_check_flag(rd->dn, OF_POPULATED)) + return NOTIFY_OK; /* device already destroyed */ + + of_id = of_match_node(weim_id_table, rd->dn->parent); + if (!of_id) + return NOTIFY_OK; /* not for us */ + + pdev = of_find_device_by_node(rd->dn); + if (!pdev) { + dev_err(&pdev->dev, + "Could not find platform device for '%pOF'\n", + rd->dn); + + ret = notifier_from_errno(-EINVAL); + } else { + of_platform_device_destroy(&pdev->dev, NULL); + platform_device_put(pdev); + } + + break; + default: + break; + } + + return ret; +} + +struct notifier_block weim_of_notifier = { + .notifier_call = of_weim_notify, +}; +#endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ + static struct platform_driver weim_driver = { .driver = { .name = "imx-weim", @@ -285,7 +382,27 @@ static struct platform_driver weim_driver = { }, .probe = weim_probe, }; -module_platform_driver(weim_driver); + +static int __init weim_init(void) +{ +#if IS_ENABLED(CONFIG_OF_DYNAMIC) + WARN_ON(of_reconfig_notifier_register(&weim_of_notifier)); +#endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ + + return platform_driver_register(&weim_driver); +} +module_init(weim_init); + +static void __exit weim_exit(void) +{ +#if IS_ENABLED(CONFIG_OF_DYNAMIC) + of_reconfig_notifier_unregister(&weim_of_notifier); +#endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ + + return platform_driver_unregister(&weim_driver); + +} +module_exit(weim_exit); MODULE_AUTHOR("Freescale Semiconductor Inc."); MODULE_DESCRIPTION("i.MX EIM Controller Driver"); -- 2.34.1