On 18.12.2019 13:06, Chanwoo Choi wrote: > 2019년 12월 18일 (수) 오후 7:14, Leonard Crestez <leonard.crestez@xxxxxxx>님이 작성: >> On 17.12.2019 02:55, Chanwoo Choi wrote: >>> On 12/17/19 12:00 AM, Leonard Crestez wrote: >>>> On 13.12.2019 06:22, Chanwoo Choi wrote: >>>>> On 11/15/19 5:09 AM, Leonard Crestez wrote: >>>>>> There is no single device which can represent the imx interconnect. >>>>>> Instead of adding a virtual one just make the main &noc act as the >>>>>> global interconnect provider. >>>>>> >>>>>> The imx interconnect provider driver will scale the NOC and DDRC based >>>>>> on bandwidth request. More scalable nodes can be added in the future, >>>>>> for example for audio/display/vpu/gpu NICs. >>>>>> >>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@xxxxxxx> >>>>>> --- >>>>>> drivers/devfreq/imx-devfreq.c | 37 +++++++++++++++++++++++++++++++++++ >>>>>> 1 file changed, 37 insertions(+) >>>>>> >>>>>> diff --git a/drivers/devfreq/imx-devfreq.c b/drivers/devfreq/imx-devfreq.c >>>>>> index 620b344e87aa..585d340c0f6e 100644 >>>>>> --- a/drivers/devfreq/imx-devfreq.c >>>>>> +++ b/drivers/devfreq/imx-devfreq.c >>>>>> @@ -15,10 +15,11 @@ >>>>>> struct imx_devfreq { >>>>>> struct devfreq_dev_profile profile; >>>>>> struct devfreq *devfreq; >>>>>> struct clk *clk; >>>>>> struct devfreq_passive_data passive_data; >>>>>> + struct platform_device *icc_pdev; >>>>>> }; >>>>>> >>>>>> static int imx_devfreq_target(struct device *dev, >>>>>> unsigned long *freq, u32 flags) >>>>>> { >>>>>> @@ -60,11 +61,40 @@ static int imx_devfreq_get_dev_status(struct device *dev, >>>>>> return 0; >>>>>> } >>>>>> >>>>>> static void imx_devfreq_exit(struct device *dev) >>>>>> { >>>>>> + struct imx_devfreq *priv = dev_get_drvdata(dev); >>>>>> + >>>>>> dev_pm_opp_of_remove_table(dev); >>>>>> + platform_device_unregister(priv->icc_pdev); >>>>>> +} >>>>>> + >>>>>> +/* imx_devfreq_init_icc() - register matching icc provider if required */ >>>>>> +static int imx_devfreq_init_icc(struct device *dev) >>>>>> +{ >>>>>> + struct imx_devfreq *priv = dev_get_drvdata(dev); >>>>>> + const char *icc_driver_name; >>>>>> + >>>>>> + if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) >>>>>> + return 0; >>>>> >>>>> It is not proper to check the enable state of CONFIG_INTERCONNECT_IMX configuration >>>>> on device driver. Why don't you add the 'select CONFIG_INTERCONNECT_IMX' on Kconfig? >>>> >>>> Because it's optional. >>>> >>>> You can disable interconnect support and just tweak frequencies using >>>> the devfreq sysfs API. But indeed would only really be useful for debugging. >>> >>> Even if it's optional, I don't prefer to use 'IS_ENABLED' macro. >>> >>> Generally, add or delete the property or value at DT file >>> to either enable or disable the some feature provided by device driver >>> instead of checking the configuration. >>> >>> If user adds the property/value related to interconnect >>> and imx-bus.c configuration is enabled, the behavior >>> related to interconnect on imx-bus.c doesn't work. It make some confusion. >> >> Maybe I could print a warning if #interconnect-cells is present but >> CONFIG_INTERCONNECT_IMX is off? > > Actually, user might think that if imx-bus.c is enabled > , CONFIG_INTERCONNECT_MIX is enabled. > Because, the dt binding document of imx-bus.c will > contain the property for interconnect. > > If device driver support the various feature, > the device driver have to enable all configuration > in order to support the features for user. >> An explicit select in Kconfig seems like a pointless limitation but in >> practice it would almost never be useful to build one without the other. > > This patch is for the some CONFIG_INTERCONNECT_IMX driver. > I don't understand why is not meaningful to select CONFIG_INTERCONNECT_IMX > in Kconfig? One issue is that the interconnect graph is described per-soc and there are per-soc config options while imx-bus applies to all. So the "if" condition is not sufficient either; if the per-soc interconnect driver is omitted then the platform device will be added but no driver will be ever be found. There are ways around this: for example all of imx interconnect could be built as a single module. But I think it's reasonable for devices to be partially functional if some config options are missing and heavy config customization sometimes requires a bit of debugging. There are various issues when building the current series as "m" but I can solve them and post a final patch which sets all the relevant options on "m" in arm64 defconfig. The it will all "just work" out of the box. >>> The imx-bus.c have to add the 'select CONFIG_INTERCONNECT_IMX' >>> and hand over the right which use the interconnect feature or not, to user. >>> >>> If there are any requirement to add the additional property >>> to check whether interconnect feature will be used or not, >>> you can add the extra property. But, I think that it is enough >>> to check the '#interconnect-cells'. >>> >>> In result, I think that it is right to decide the usage of feature >>> of device driver by user on Devicetree. >>> >>>> >>>>>> + if (!of_get_property(dev->of_node, "#interconnect-cells", 0)) >>>>>> + return 0; >>>>>> + >>>>>> + icc_driver_name = of_device_get_match_data(dev); >>>>>> + if (!icc_driver_name) >>>>>> + return 0; >>>>>> + >>>>>> + priv->icc_pdev = platform_device_register_data( >>>>>> + dev, icc_driver_name, 0, NULL, 0); >>>>>> + if (IS_ERR(priv->icc_pdev)) { >>>>>> + dev_err(dev, "failed to register icc provider %s: %ld\n", >>>>>> + icc_driver_name, PTR_ERR(priv->devfreq)); >>>>>> + return PTR_ERR(priv->devfreq); >>>>>> + } >>>>>> + >>>>>> + return 0; >>>>>> } >>>>>> >>>>>> static int imx_devfreq_probe(struct platform_device *pdev) >>>>>> { >>>>>> struct device *dev = &pdev->dev; >>>>>> @@ -120,18 +150,25 @@ static int imx_devfreq_probe(struct platform_device *pdev) >>>>>> ret = PTR_ERR(priv->devfreq); >>>>>> dev_err(dev, "failed to add devfreq device: %d\n", ret); >>>>>> goto err; >>>>>> } >>>>>> >>>>>> + ret = imx_devfreq_init_icc(dev); >>>>>> + if (ret) >>>>>> + goto err; >>>>>> + >>>>>> return 0; >>>>>> >>>>>> err: >>>>>> dev_pm_opp_of_remove_table(dev); >>>>>> return ret; >>>>>> } >>>>>> >>>>>> static const struct of_device_id imx_devfreq_of_match[] = { >>>>>> + { .compatible = "fsl,imx8mq-noc", .data = "imx8mq-interconnect", }, >>>>>> + { .compatible = "fsl,imx8mm-noc", .data = "imx8mm-interconnect", }, >>>>>> + { .compatible = "fsl,imx8mn-noc", .data = "imx8mn-interconnect", }, >>>>>> { .compatible = "fsl,imx8m-noc", }, >>>>>> { .compatible = "fsl,imx8m-nic", }, >>>>>> { /* sentinel */ }, >>>>>> }; >>>>>> MODULE_DEVICE_TABLE(of, imx_devfreq_of_match);