linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] Introduce MediaTek CCI devfreq driver
@ 2022-04-25 12:55 Johnson Wang
  2022-04-25 12:55 ` [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings Johnson Wang
  2022-04-25 12:55 ` [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver Johnson Wang
  0 siblings, 2 replies; 27+ messages in thread
From: Johnson Wang @ 2022-04-25 12:55 UTC (permalink / raw)
  To: cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group, Johnson Wang

The Cache Coherent Interconnect (CCI) is the management of cache
coherency by hardware. CCI DEVFREQ is DVFS driver for power saving by
scaling clock frequency and supply voltage of CCI. CCI uses the same
input clock source and power rail as LITTLE CPUs on Mediatek SoCs.

This series depends on:
Chanwoo's repo: kernel/git/chanwoo/linux.git
branch: devfreq-testing
[1]: PM / devfreq: Export devfreq_get_freq_range symbol within devfreq
[2]: PM / devfreq: Add cpu based scaling support to passive governor
[3]: PM / devfreq: passive: Reduce duplicate code when passive_devfreq case
[4]: PM / devfreq: passive: Update frequency when start governor

Changes in v3:
- Move binding document to 'interconnect' and rename it.
- Add COMPILE_TEST dependence symbol.
- Remove need_voltage_tracking variable.
- Move mtk_ccifreq_voltage_tracking() code into mtk_ccifreq_set_voltage().
- Add an interation limit in the while() loop.
- Replace 'cci_dev' with 'dev'
- Replace old_* with pre_*
- Remove of_match_ptr()
- Use module_platform_driver()

Changes in v2:
- Take MT8183 as example in binding document.
- Use dev_err() instead of pr_err().
- Use 'goto' statement to handle error case.
- Clean up driver code.

Johnson Wang (2):
  dt-bindings: devfreq: mediatek: Add mtk cci devfreq dt-bindings
  PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver

 .../devicetree/bindings/devfreq/mtk-cci.yaml  |  72 +++
 drivers/devfreq/Kconfig                       |  10 +
 drivers/devfreq/Makefile                      |   1 +
 drivers/devfreq/mtk-cci-devfreq.c             | 479 ++++++++++++++++++
 4 files changed, 562 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/devfreq/mtk-cci.yaml
 create mode 100644 drivers/devfreq/mtk-cci-devfreq.c

-- 
2.18.0


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  2022-04-25 12:55 [PATCH v3 0/2] Introduce MediaTek CCI devfreq driver Johnson Wang
@ 2022-04-25 12:55 ` Johnson Wang
  2022-04-25 17:56   ` Krzysztof Kozlowski
                     ` (2 more replies)
  2022-04-25 12:55 ` [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver Johnson Wang
  1 sibling, 3 replies; 27+ messages in thread
From: Johnson Wang @ 2022-04-25 12:55 UTC (permalink / raw)
  To: cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group, Johnson Wang

Add devicetree binding of MediaTek CCI on MT8183 and MT8186.

Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
---
 .../bindings/interconnect/mediatek,cci.yaml   | 139 ++++++++++++++++++
 1 file changed, 139 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml

diff --git a/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
new file mode 100644
index 000000000000..e5221e17d11b
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
@@ -0,0 +1,139 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/mediatek,cci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Cache Coherent Interconnect (CCI) frequency and voltage scaling
+
+maintainers:
+  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
+
+description: |
+  MediaTek Cache Coherent Interconnect (CCI) is a hardware engine used by
+  MT8183 and MT8186 SoCs to scale the frequency and adjust the voltage in
+  hardware. It can also optimize the voltage to reduce the power consumption.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt8183-cci
+      - mediatek,mt8186-cci
+
+  clocks:
+    items:
+      - description:
+          The multiplexer for clock input of CPU cluster.
+      - description:
+          A parent of "cpu" clock which is used as an intermediate clock source
+          when the original CPU is under transition and not stable yet.
+
+  clock-names:
+    items:
+      - const: cci
+      - const: intermediate
+
+  operating-points-v2: true
+  opp-table: true
+
+  proc-supply:
+    description:
+      Phandle of the regulator for CCI that provides the supply voltage.
+
+  sram-supply:
+    description:
+      Phandle of the regulator for sram of CCI that provides the supply
+      voltage. When it presents, the cci devfreq driver needs to do
+      "voltage tracking" to step by step scale up/down Vproc and Vsram to fit
+      SoC specific needs. When absent, the voltage scaling flow is handled by
+      hardware, hence no software "voltage tracking" is needed.
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - operating-points-v2
+  - proc-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/mt8183-clk.h>
+    cci: cci {
+        compatible = "mediatek,mt8183-cci";
+        clocks = <&mcucfg CLK_MCU_BUS_SEL>,
+                 <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+        clock-names = "cci", "intermediate";
+        operating-points-v2 = <&cci_opp>;
+        proc-supply = <&mt6358_vproc12_reg>;
+    };
+
+    cci_opp: opp-table-cci {
+        compatible = "operating-points-v2";
+        opp-shared;
+        opp2_00: opp-273000000 {
+            opp-hz = /bits/ 64 <273000000>;
+            opp-microvolt = <650000>;
+        };
+        opp2_01: opp-338000000 {
+            opp-hz = /bits/ 64 <338000000>;
+            opp-microvolt = <687500>;
+        };
+        opp2_02: opp-403000000 {
+            opp-hz = /bits/ 64 <403000000>;
+            opp-microvolt = <718750>;
+        };
+        opp2_03: opp-463000000 {
+            opp-hz = /bits/ 64 <463000000>;
+            opp-microvolt = <756250>;
+        };
+        opp2_04: opp-546000000 {
+            opp-hz = /bits/ 64 <546000000>;
+            opp-microvolt = <800000>;
+        };
+        opp2_05: opp-624000000 {
+            opp-hz = /bits/ 64 <624000000>;
+            opp-microvolt = <818750>;
+        };
+        opp2_06: opp-689000000 {
+            opp-hz = /bits/ 64 <689000000>;
+            opp-microvolt = <850000>;
+        };
+        opp2_07: opp-767000000 {
+            opp-hz = /bits/ 64 <767000000>;
+            opp-microvolt = <868750>;
+        };
+        opp2_08: opp-845000000 {
+            opp-hz = /bits/ 64 <845000000>;
+            opp-microvolt = <893750>;
+        };
+        opp2_09: opp-871000000 {
+            opp-hz = /bits/ 64 <871000000>;
+            opp-microvolt = <906250>;
+        };
+        opp2_10: opp-923000000 {
+            opp-hz = /bits/ 64 <923000000>;
+            opp-microvolt = <931250>;
+        };
+        opp2_11: opp-962000000 {
+            opp-hz = /bits/ 64 <962000000>;
+            opp-microvolt = <943750>;
+        };
+        opp2_12: opp-1027000000 {
+            opp-hz = /bits/ 64 <1027000000>;
+            opp-microvolt = <975000>;
+        };
+        opp2_13: opp-1092000000 {
+            opp-hz = /bits/ 64 <1092000000>;
+            opp-microvolt = <1000000>;
+        };
+        opp2_14: opp-1144000000 {
+            opp-hz = /bits/ 64 <1144000000>;
+            opp-microvolt = <1025000>;
+        };
+        opp2_15: opp-1196000000 {
+            opp-hz = /bits/ 64 <1196000000>;
+            opp-microvolt = <1050000>;
+        };
+    };
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-04-25 12:55 [PATCH v3 0/2] Introduce MediaTek CCI devfreq driver Johnson Wang
  2022-04-25 12:55 ` [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings Johnson Wang
@ 2022-04-25 12:55 ` Johnson Wang
  2022-04-26 12:45   ` kernel test robot
                     ` (4 more replies)
  1 sibling, 5 replies; 27+ messages in thread
From: Johnson Wang @ 2022-04-25 12:55 UTC (permalink / raw)
  To: cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group, Johnson Wang

We introduce a devfreq driver for the MediaTek Cache Coherent Interconnect
(CCI) used by some MediaTek SoCs.

In this driver, we use the passive devfreq driver to get target frequencies
and adjust voltages accordingly. In MT8183 and MT8186, the MediaTek CCI
is supplied by the same regulators with the little core CPUs.

Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
---
This patch depends on "devfreq-testing"[1].
[1]https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing
---
 drivers/devfreq/Kconfig           |  10 +
 drivers/devfreq/Makefile          |   1 +
 drivers/devfreq/mtk-cci-devfreq.c | 474 ++++++++++++++++++++++++++++++
 3 files changed, 485 insertions(+)
 create mode 100644 drivers/devfreq/mtk-cci-devfreq.c

diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 87eb2b837e68..9754d8b31621 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -120,6 +120,16 @@ config ARM_TEGRA_DEVFREQ
 	  It reads ACTMON counters of memory controllers and adjusts the
 	  operating frequencies and voltages with OPP support.
 
+config ARM_MEDIATEK_CCI_DEVFREQ
+	tristate "MEDIATEK CCI DEVFREQ Driver"
+	depends on ARM_MEDIATEK_CPUFREQ || COMPILE_TEST
+	select DEVFREQ_GOV_PASSIVE
+	help
+	  This adds a devfreq driver for MediaTek Cache Coherent Interconnect
+	  which is shared the same regulators with the cpu cluster. It can track
+	  buck voltages and update a proper CCI frequency. Use the notification
+	  to get the regulator status.
+
 config ARM_RK3399_DMC_DEVFREQ
 	tristate "ARM RK3399 DMC DEVFREQ Driver"
 	depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 0b6be92a25d9..bf40d04928d0 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+= governor_passive.o
 obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
 obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o
 obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
+obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ)	+= mtk-cci-devfreq.o
 obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
 obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ)	+= sun8i-a33-mbus.o
 obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-devfreq.o
diff --git a/drivers/devfreq/mtk-cci-devfreq.c b/drivers/devfreq/mtk-cci-devfreq.c
new file mode 100644
index 000000000000..b3e31c45a57c
--- /dev/null
+++ b/drivers/devfreq/mtk-cci-devfreq.c
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/regulator/consumer.h>
+
+struct mtk_ccifreq_platform_data {
+	int min_volt_shift;
+	int max_volt_shift;
+	int proc_max_volt;
+	int sram_min_volt;
+	int sram_max_volt;
+};
+
+struct mtk_ccifreq_drv {
+	struct device *dev;
+	struct devfreq *devfreq;
+	struct regulator *proc_reg;
+	struct regulator *sram_reg;
+	struct clk *cci_clk;
+	struct clk *inter_clk;
+	int inter_voltage;
+	int pre_voltage;
+	unsigned long pre_freq;
+	/* Avoid race condition for regulators between notify and policy */
+	struct mutex reg_lock;
+	struct notifier_block opp_nb;
+	const struct mtk_ccifreq_platform_data *soc_data;
+	int vtrack_max;
+};
+
+static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv, int new_voltage)
+{
+	const struct mtk_ccifreq_platform_data *soc_data = drv->soc_data;
+	struct device *dev = drv->dev;
+	int pre_voltage, pre_vsram, new_vsram, vsram, voltage, ret;
+	int retry_max = drv->vtrack_max;
+
+	if (!drv->sram_reg) {
+		ret = regulator_set_voltage(drv->proc_reg, new_voltage,
+					    drv->soc_data->proc_max_volt);
+		goto out_set_voltage;
+	}
+
+	pre_voltage = regulator_get_voltage(drv->proc_reg);
+	if (pre_voltage < 0) {
+		dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
+		return pre_voltage;
+	}
+
+	pre_vsram = regulator_get_voltage(drv->sram_reg);
+	if (pre_vsram < 0) {
+		dev_err(dev, "invalid vsram value: %d\n", pre_vsram);
+		return pre_vsram;
+	}
+
+	new_vsram = clamp(new_voltage + soc_data->min_volt_shift,
+			  soc_data->sram_min_volt, soc_data->sram_max_volt);
+
+	do {
+		if (pre_voltage <= new_voltage) {
+			vsram = clamp(pre_voltage + soc_data->max_volt_shift,
+				      soc_data->sram_min_volt, new_vsram);
+			ret = regulator_set_voltage(drv->sram_reg, vsram,
+						    soc_data->sram_max_volt);
+			if (ret)
+				return ret;
+
+			if (vsram == soc_data->sram_max_volt ||
+			    new_vsram == soc_data->sram_min_volt)
+				voltage = new_voltage;
+			else
+				voltage = vsram - soc_data->min_volt_shift;
+
+			ret = regulator_set_voltage(drv->proc_reg, voltage,
+						    soc_data->proc_max_volt);
+			if (ret) {
+				regulator_set_voltage(drv->sram_reg, pre_vsram,
+						      soc_data->sram_max_volt);
+				return ret;
+			}
+		} else if (pre_voltage > new_voltage) {
+			voltage = max(new_voltage,
+				      pre_vsram - soc_data->max_volt_shift);
+			ret = regulator_set_voltage(drv->proc_reg, voltage,
+						    soc_data->proc_max_volt);
+			if (ret)
+				return ret;
+
+			if (voltage == new_voltage)
+				vsram = new_vsram;
+			else
+				vsram = max(new_vsram,
+					    voltage + soc_data->min_volt_shift);
+
+			ret = regulator_set_voltage(drv->sram_reg, vsram,
+						    soc_data->sram_max_volt);
+			if (ret) {
+				regulator_set_voltage(drv->proc_reg, pre_voltage,
+						      soc_data->proc_max_volt);
+				return ret;
+			}
+		}
+
+		pre_voltage = voltage;
+		pre_vsram = vsram;
+
+		if (--retry_max < 0) {
+			dev_err(dev,
+				"over loop count, failed to set voltage\n");
+			return -EINVAL;
+		}
+	} while (voltage != new_voltage || vsram != new_vsram);
+
+out_set_voltage:
+	if (!ret)
+		drv->pre_voltage = new_voltage;
+
+	return ret;
+}
+
+static int mtk_ccifreq_target(struct device *dev, unsigned long *freq,
+			      u32 flags)
+{
+	struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev);
+	struct clk *cci_pll = clk_get_parent(drv->cci_clk);
+	struct dev_pm_opp *opp;
+	unsigned long opp_rate;
+	int voltage, pre_voltage, inter_voltage, target_voltage, ret;
+
+	if (!drv)
+		return -EINVAL;
+
+	if (drv->pre_freq == *freq)
+		return 0;
+
+	inter_voltage = drv->inter_voltage;
+
+	opp_rate = *freq;
+	opp = devfreq_recommended_opp(dev, &opp_rate, 1);
+	if (IS_ERR(opp)) {
+		dev_err(dev, "failed to find opp for freq: %ld\n", opp_rate);
+		return PTR_ERR(opp);
+	}
+
+	mutex_lock(&drv->reg_lock);
+
+	voltage = dev_pm_opp_get_voltage(opp);
+	dev_pm_opp_put(opp);
+
+	if (unlikely(drv->pre_voltage <= 0))
+		pre_voltage = regulator_get_voltage(drv->proc_reg);
+	else
+		pre_voltage = drv->pre_voltage;
+
+	if (pre_voltage < 0) {
+		dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
+		return pre_voltage;
+	}
+
+	/* scale up: set voltage first then freq. */
+	target_voltage = max(inter_voltage, voltage);
+	if (pre_voltage <= target_voltage) {
+		ret = mtk_ccifreq_set_voltage(drv, target_voltage);
+		if (ret) {
+			dev_err(dev, "failed to scale up voltage\n");
+			goto out_restore_voltage;
+		}
+	}
+
+	/* switch the cci clock to intermediate clock source. */
+	ret = clk_set_parent(drv->cci_clk, drv->inter_clk);
+	if (ret) {
+		dev_err(dev, "failed to re-parent cci clock\n");
+		goto out_restore_voltage;
+	}
+
+	/* set the original clock to target rate. */
+	ret = clk_set_rate(cci_pll, *freq);
+	if (ret) {
+		dev_err(dev, "failed to set cci pll rate: %d\n", ret);
+		clk_set_parent(drv->cci_clk, cci_pll);
+		goto out_restore_voltage;
+	}
+
+	/* switch the cci clock back to the original clock source. */
+	ret = clk_set_parent(drv->cci_clk, cci_pll);
+	if (ret) {
+		dev_err(dev, "failed to re-parent cci clock\n");
+		mtk_ccifreq_set_voltage(drv, inter_voltage);
+		goto out_unlock;
+	}
+
+	/*
+	 * If the new voltage is lower than the intermediate voltage or the
+	 * original voltage, scale down to the new voltage.
+	 */
+	if (voltage < inter_voltage || voltage < pre_voltage) {
+		ret = mtk_ccifreq_set_voltage(drv, voltage);
+		if (ret) {
+			dev_err(dev, "failed to scale down voltage\n");
+			goto out_unlock;
+		}
+	}
+
+	drv->pre_freq = *freq;
+	mutex_unlock(&drv->reg_lock);
+
+	return 0;
+
+out_restore_voltage:
+	mtk_ccifreq_set_voltage(drv, pre_voltage);
+
+out_unlock:
+	mutex_unlock(&drv->reg_lock);
+	return ret;
+}
+
+static int mtk_ccifreq_opp_notifier(struct notifier_block *nb,
+				    unsigned long event, void *data)
+{
+	struct dev_pm_opp *opp = data;
+	struct mtk_ccifreq_drv *drv;
+	unsigned long freq, volt;
+
+	drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb);
+
+	if (event == OPP_EVENT_ADJUST_VOLTAGE) {
+		freq = dev_pm_opp_get_freq(opp);
+
+		mutex_lock(&drv->reg_lock);
+		/* current opp item is changed */
+		if (freq == drv->pre_freq) {
+			volt = dev_pm_opp_get_voltage(opp);
+			mtk_ccifreq_set_voltage(drv, volt);
+		}
+		mutex_unlock(&drv->reg_lock);
+	}
+
+	return 0;
+}
+
+static struct devfreq_dev_profile mtk_ccifreq_profile = {
+	.target = mtk_ccifreq_target,
+};
+
+static int mtk_ccifreq_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mtk_ccifreq_drv *drv;
+	struct devfreq_passive_data *passive_data;
+	struct dev_pm_opp *opp;
+	unsigned long rate, opp_volt;
+	int ret;
+
+	drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+
+	drv->dev = dev;
+	drv->soc_data = (const struct mtk_ccifreq_platform_data *)
+				of_device_get_match_data(&pdev->dev);
+	mutex_init(&drv->reg_lock);
+	platform_set_drvdata(pdev, drv);
+
+	drv->cci_clk = devm_clk_get(dev, "cci");
+	if (IS_ERR(drv->cci_clk)) {
+		ret = PTR_ERR(drv->cci_clk);
+		return dev_err_probe(dev, ret,
+				     "failed to get cci clk: %d\n", ret);
+	}
+
+	drv->inter_clk = devm_clk_get(dev, "intermediate");
+	if (IS_ERR(drv->inter_clk)) {
+		ret = PTR_ERR(drv->inter_clk);
+		dev_err_probe(dev, ret,
+			      "failed to get intermediate clk: %d\n", ret);
+		goto out_free_resources;
+	}
+
+	drv->proc_reg = devm_regulator_get_optional(dev, "proc");
+	if (IS_ERR(drv->proc_reg)) {
+		ret = PTR_ERR(drv->proc_reg);
+		dev_err_probe(dev, ret,
+			      "failed to get proc regulator: %d\n", ret);
+		goto out_free_resources;
+	}
+
+	ret = regulator_enable(drv->proc_reg);
+	if (ret) {
+		dev_err(dev, "failed to enable proc regulator\n");
+		goto out_free_resources;
+	}
+
+	drv->sram_reg = regulator_get_optional(dev, "sram");
+	if (IS_ERR(drv->sram_reg))
+		drv->sram_reg = NULL;
+	else {
+		ret = regulator_enable(drv->sram_reg);
+		if (ret) {
+			dev_err(dev, "failed to enable sram regulator\n");
+			goto out_free_resources;
+		}
+	}
+
+	/*
+	 * We assume min voltage is 0 and tracking target voltage using
+	 * min_volt_shift for each iteration.
+	 * The retry_max is 3 times of expeted iteration count.
+	 */
+	drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data->sram_max_volt,
+					       drv->soc_data->proc_max_volt),
+					   drv->soc_data->min_volt_shift);
+
+	ret = clk_prepare_enable(drv->cci_clk);
+	if (ret)
+		goto out_free_resources;
+
+	ret = clk_prepare_enable(drv->inter_clk);
+	if (ret)
+		goto out_disable_cci_clk;
+
+	ret = dev_pm_opp_of_add_table(dev);
+	if (ret) {
+		dev_err(dev, "failed to add opp table: %d\n", ret);
+		goto out_disable_inter_clk;
+	}
+
+	rate = clk_get_rate(drv->inter_clk);
+	opp = dev_pm_opp_find_freq_ceil(dev, &rate);
+	if (IS_ERR(opp)) {
+		ret = PTR_ERR(opp);
+		dev_err(dev, "failed to get intermediate opp: %d\n", ret);
+		goto out_remove_opp_table;
+	}
+	drv->inter_voltage = dev_pm_opp_get_voltage(opp);
+	dev_pm_opp_put(opp);
+
+	rate = U32_MAX;
+	opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
+	if (IS_ERR(opp)) {
+		dev_err(dev, "failed to get opp\n");
+		ret = PTR_ERR(opp);
+		goto out_remove_opp_table;
+	}
+
+	opp_volt = dev_pm_opp_get_voltage(opp);
+	dev_pm_opp_put(opp);
+	ret = mtk_ccifreq_set_voltage(drv, opp_volt);
+	if (ret) {
+		dev_err(dev, "failed to scale to highest voltage %lu in proc_reg\n",
+			opp_volt);
+		goto out_remove_opp_table;
+	}
+
+	passive_data = devm_kzalloc(dev, sizeof(struct devfreq_passive_data),
+				    GFP_KERNEL);
+	if (!passive_data) {
+		ret = -ENOMEM;
+		goto out_remove_opp_table;
+	}
+
+	passive_data->parent_type = CPUFREQ_PARENT_DEV;
+	drv->devfreq = devm_devfreq_add_device(dev, &mtk_ccifreq_profile,
+					       DEVFREQ_GOV_PASSIVE,
+					       passive_data);
+	if (IS_ERR(drv->devfreq)) {
+		ret = -EPROBE_DEFER;
+		dev_err(dev, "failed to add devfreq device: %d\n",
+			PTR_ERR(drv->devfreq));
+		goto out_remove_opp_table;
+	}
+
+	drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
+	ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
+	if (ret) {
+		dev_err(dev, "failed to register opp notifier: %d\n", ret);
+		goto out_remove_devfreq_device;
+	}
+	return 0;
+
+out_remove_devfreq_device:
+	devm_devfreq_remove_device(dev, drv->devfreq);
+
+out_remove_opp_table:
+	dev_pm_opp_of_remove_table(dev);
+
+out_disable_inter_clk:
+	clk_disable_unprepare(drv->inter_clk);
+
+out_disable_cci_clk:
+	clk_disable_unprepare(drv->cci_clk);
+
+out_free_resources:
+	if (regulator_is_enabled(drv->proc_reg))
+		regulator_disable(drv->proc_reg);
+	if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
+		regulator_disable(drv->sram_reg);
+
+	if (!IS_ERR(drv->proc_reg))
+		regulator_put(drv->proc_reg);
+	if (!IS_ERR(drv->sram_reg))
+		regulator_put(drv->sram_reg);
+	if (!IS_ERR(drv->cci_clk))
+		clk_put(drv->cci_clk);
+	if (!IS_ERR(drv->inter_clk))
+		clk_put(drv->inter_clk);
+
+	return ret;
+}
+
+static int mtk_ccifreq_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mtk_ccifreq_drv *drv;
+
+	drv = platform_get_drvdata(pdev);
+
+	dev_pm_opp_unregister_notifier(dev, &drv->opp_nb);
+	dev_pm_opp_of_remove_table(dev);
+	clk_disable_unprepare(drv->inter_clk);
+	clk_disable_unprepare(drv->cci_clk);
+	regulator_disable(drv->proc_reg);
+	if (drv->sram_reg)
+		regulator_disable(drv->sram_reg);
+
+	return 0;
+}
+
+static const struct mtk_ccifreq_platform_data mt8183_platform_data = {
+	.min_volt_shift = 100000,
+	.max_volt_shift = 200000,
+	.proc_max_volt = 1150000,
+	.sram_min_volt = 0,
+	.sram_max_volt = 1150000,
+};
+
+static const struct mtk_ccifreq_platform_data mt8186_platform_data = {
+	.min_volt_shift = 100000,
+	.max_volt_shift = 250000,
+	.proc_max_volt = 1118750,
+	.sram_min_volt = 850000,
+	.sram_max_volt = 1118750,
+};
+
+static const struct of_device_id mtk_ccifreq_machines[] = {
+	{ .compatible = "mediatek,mt8183-cci", .data = &mt8183_platform_data },
+	{ .compatible = "mediatek,mt8186-cci", .data = &mt8186_platform_data },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines);
+
+static struct platform_driver mtk_ccifreq_platdrv = {
+	.probe	= mtk_ccifreq_probe,
+	.remove	= mtk_ccifreq_remove,
+	.driver = {
+		.name = "mtk-ccifreq",
+		.of_match_table = mtk_ccifreq_machines,
+	},
+};
+module_platform_driver(mtk_ccifreq_platdrv);
+
+MODULE_DESCRIPTION("MediaTek CCI devfreq driver");
+MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  2022-04-25 12:55 ` [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings Johnson Wang
@ 2022-04-25 17:56   ` Krzysztof Kozlowski
  2022-04-26  3:18   ` Chen-Yu Tsai
  2022-05-09 12:09   ` Chanwoo Choi
  2 siblings, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2022-04-25 17:56 UTC (permalink / raw)
  To: Johnson Wang, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

On 25/04/2022 14:55, Johnson Wang wrote:
> Add devicetree binding of MediaTek CCI on MT8183 and MT8186.
> 
> Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> ---


Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  2022-04-25 12:55 ` [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings Johnson Wang
  2022-04-25 17:56   ` Krzysztof Kozlowski
@ 2022-04-26  3:18   ` Chen-Yu Tsai
  2022-05-09 12:14     ` Johnson Wang
  2022-05-09 12:09   ` Chanwoo Choi
  2 siblings, 1 reply; 27+ messages in thread
From: Chen-Yu Tsai @ 2022-04-26  3:18 UTC (permalink / raw)
  To: Johnson Wang, krzk+dt
  Cc: cw00.choi, robh+dt, kyungmin.park, khilman, linux-pm,
	linux-kernel, devicetree, linux-arm-kernel, linux-mediatek,
	jia-wei.chang, Project_Global_Chrome_Upstream_Group

On Mon, Apr 25, 2022 at 8:56 PM Johnson Wang <johnson.wang@mediatek.com> wrote:
>
> Add devicetree binding of MediaTek CCI on MT8183 and MT8186.
>
> Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> ---
>  .../bindings/interconnect/mediatek,cci.yaml   | 139 ++++++++++++++++++
>  1 file changed, 139 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
>
> diff --git a/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> new file mode 100644
> index 000000000000..e5221e17d11b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> @@ -0,0 +1,139 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/interconnect/mediatek,cci.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek Cache Coherent Interconnect (CCI) frequency and voltage scaling
> +
> +maintainers:
> +  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
> +
> +description: |
> +  MediaTek Cache Coherent Interconnect (CCI) is a hardware engine used by
> +  MT8183 and MT8186 SoCs to scale the frequency and adjust the voltage in
> +  hardware. It can also optimize the voltage to reduce the power consumption.
> +
> +properties:
> +  compatible:
> +    enum:
> +      - mediatek,mt8183-cci
> +      - mediatek,mt8186-cci
> +
> +  clocks:
> +    items:
> +      - description:
> +          The multiplexer for clock input of CPU cluster.

of the bus, not CPU cluster.

> +      - description:
> +          A parent of "cpu" clock which is used as an intermediate clock source
> +          when the original CPU is under transition and not stable yet.

This really should be handled in the clk controller, and not by every device
that happens to take a clock from a mux with upstream PLLs that can change
in clock rate. The end device hardware only takes one clock input. That's it.

> +
> +  clock-names:
> +    items:
> +      - const: cci
> +      - const: intermediate
> +
> +  operating-points-v2: true
> +  opp-table: true
> +
> +  proc-supply:
> +    description:
> +      Phandle of the regulator for CCI that provides the supply voltage.
> +
> +  sram-supply:
> +    description:
> +      Phandle of the regulator for sram of CCI that provides the supply
> +      voltage. When it presents, the cci devfreq driver needs to do

When it is present, the implementation needs to ...

ChenYu

> +      "voltage tracking" to step by step scale up/down Vproc and Vsram to fit
> +      SoC specific needs. When absent, the voltage scaling flow is handled by
> +      hardware, hence no software "voltage tracking" is needed.
> +
> +required:
> +  - compatible
> +  - clocks
> +  - clock-names
> +  - operating-points-v2
> +  - proc-supply
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/mt8183-clk.h>
> +    cci: cci {
> +        compatible = "mediatek,mt8183-cci";
> +        clocks = <&mcucfg CLK_MCU_BUS_SEL>,
> +                 <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
> +        clock-names = "cci", "intermediate";
> +        operating-points-v2 = <&cci_opp>;
> +        proc-supply = <&mt6358_vproc12_reg>;
> +    };
> +
> +    cci_opp: opp-table-cci {
> +        compatible = "operating-points-v2";
> +        opp-shared;
> +        opp2_00: opp-273000000 {
> +            opp-hz = /bits/ 64 <273000000>;
> +            opp-microvolt = <650000>;
> +        };
> +        opp2_01: opp-338000000 {
> +            opp-hz = /bits/ 64 <338000000>;
> +            opp-microvolt = <687500>;
> +        };
> +        opp2_02: opp-403000000 {
> +            opp-hz = /bits/ 64 <403000000>;
> +            opp-microvolt = <718750>;
> +        };
> +        opp2_03: opp-463000000 {
> +            opp-hz = /bits/ 64 <463000000>;
> +            opp-microvolt = <756250>;
> +        };
> +        opp2_04: opp-546000000 {
> +            opp-hz = /bits/ 64 <546000000>;
> +            opp-microvolt = <800000>;
> +        };
> +        opp2_05: opp-624000000 {
> +            opp-hz = /bits/ 64 <624000000>;
> +            opp-microvolt = <818750>;
> +        };
> +        opp2_06: opp-689000000 {
> +            opp-hz = /bits/ 64 <689000000>;
> +            opp-microvolt = <850000>;
> +        };
> +        opp2_07: opp-767000000 {
> +            opp-hz = /bits/ 64 <767000000>;
> +            opp-microvolt = <868750>;
> +        };
> +        opp2_08: opp-845000000 {
> +            opp-hz = /bits/ 64 <845000000>;
> +            opp-microvolt = <893750>;
> +        };
> +        opp2_09: opp-871000000 {
> +            opp-hz = /bits/ 64 <871000000>;
> +            opp-microvolt = <906250>;
> +        };
> +        opp2_10: opp-923000000 {
> +            opp-hz = /bits/ 64 <923000000>;
> +            opp-microvolt = <931250>;
> +        };
> +        opp2_11: opp-962000000 {
> +            opp-hz = /bits/ 64 <962000000>;
> +            opp-microvolt = <943750>;
> +        };
> +        opp2_12: opp-1027000000 {
> +            opp-hz = /bits/ 64 <1027000000>;
> +            opp-microvolt = <975000>;
> +        };
> +        opp2_13: opp-1092000000 {
> +            opp-hz = /bits/ 64 <1092000000>;
> +            opp-microvolt = <1000000>;
> +        };
> +        opp2_14: opp-1144000000 {
> +            opp-hz = /bits/ 64 <1144000000>;
> +            opp-microvolt = <1025000>;
> +        };
> +        opp2_15: opp-1196000000 {
> +            opp-hz = /bits/ 64 <1196000000>;
> +            opp-microvolt = <1050000>;
> +        };
> +    };
> --
> 2.18.0
>
>
> _______________________________________________
> Linux-mediatek mailing list
> Linux-mediatek@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-04-25 12:55 ` [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver Johnson Wang
@ 2022-04-26 12:45   ` kernel test robot
  2022-04-27  7:09   ` kernel test robot
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 27+ messages in thread
From: kernel test robot @ 2022-04-26 12:45 UTC (permalink / raw)
  To: Johnson Wang, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: kbuild-all, khilman, linux-pm, linux-kernel, devicetree,
	linux-arm-kernel, linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group, Johnson Wang

Hi Johnson,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v5.18-rc4 next-20220422]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Johnson-Wang/Introduce-MediaTek-CCI-devfreq-driver/20220425-205820
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arc-allyesconfig (https://download.01.org/0day-ci/archive/20220426/202204262037.g8ZK9iOF-lkp@intel.com/config)
compiler: arceb-elf-gcc (GCC) 11.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/98b34c0587837b0e5b880b11a52433f8f0eee19f
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Johnson-Wang/Introduce-MediaTek-CCI-devfreq-driver/20220425-205820
        git checkout 98b34c0587837b0e5b880b11a52433f8f0eee19f
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.3.0 make.cross W=1 O=build_dir ARCH=arc SHELL=/bin/bash drivers/devfreq/ sound/core/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/devfreq/mtk-cci-devfreq.c: In function 'mtk_ccifreq_probe':
   drivers/devfreq/mtk-cci-devfreq.c:372:21: error: 'struct devfreq_passive_data' has no member named 'parent_type'
     372 |         passive_data->parent_type = CPUFREQ_PARENT_DEV;
         |                     ^~
   drivers/devfreq/mtk-cci-devfreq.c:372:37: error: 'CPUFREQ_PARENT_DEV' undeclared (first use in this function)
     372 |         passive_data->parent_type = CPUFREQ_PARENT_DEV;
         |                                     ^~~~~~~~~~~~~~~~~~
   drivers/devfreq/mtk-cci-devfreq.c:372:37: note: each undeclared identifier is reported only once for each function it appears in
   In file included from include/linux/device.h:15,
                    from include/linux/devfreq.h:13,
                    from drivers/devfreq/mtk-cci-devfreq.c:7:
>> drivers/devfreq/mtk-cci-devfreq.c:378:30: warning: format '%d' expects argument of type 'int', but argument 3 has type 'long int' [-Wformat=]
     378 |                 dev_err(dev, "failed to add devfreq device: %d\n",
         |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:144:56: note: in expansion of macro 'dev_fmt'
     144 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/devfreq/mtk-cci-devfreq.c:378:17: note: in expansion of macro 'dev_err'
     378 |                 dev_err(dev, "failed to add devfreq device: %d\n",
         |                 ^~~~~~~
   drivers/devfreq/mtk-cci-devfreq.c:378:62: note: format string is defined here
     378 |                 dev_err(dev, "failed to add devfreq device: %d\n",
         |                                                             ~^
         |                                                              |
         |                                                              int
         |                                                             %ld


vim +378 drivers/devfreq/mtk-cci-devfreq.c

   255	
   256	static int mtk_ccifreq_probe(struct platform_device *pdev)
   257	{
   258		struct device *dev = &pdev->dev;
   259		struct mtk_ccifreq_drv *drv;
   260		struct devfreq_passive_data *passive_data;
   261		struct dev_pm_opp *opp;
   262		unsigned long rate, opp_volt;
   263		int ret;
   264	
   265		drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
   266		if (!drv)
   267			return -ENOMEM;
   268	
   269		drv->dev = dev;
   270		drv->soc_data = (const struct mtk_ccifreq_platform_data *)
   271					of_device_get_match_data(&pdev->dev);
   272		mutex_init(&drv->reg_lock);
   273		platform_set_drvdata(pdev, drv);
   274	
   275		drv->cci_clk = devm_clk_get(dev, "cci");
   276		if (IS_ERR(drv->cci_clk)) {
   277			ret = PTR_ERR(drv->cci_clk);
   278			return dev_err_probe(dev, ret,
   279					     "failed to get cci clk: %d\n", ret);
   280		}
   281	
   282		drv->inter_clk = devm_clk_get(dev, "intermediate");
   283		if (IS_ERR(drv->inter_clk)) {
   284			ret = PTR_ERR(drv->inter_clk);
   285			dev_err_probe(dev, ret,
   286				      "failed to get intermediate clk: %d\n", ret);
   287			goto out_free_resources;
   288		}
   289	
   290		drv->proc_reg = devm_regulator_get_optional(dev, "proc");
   291		if (IS_ERR(drv->proc_reg)) {
   292			ret = PTR_ERR(drv->proc_reg);
   293			dev_err_probe(dev, ret,
   294				      "failed to get proc regulator: %d\n", ret);
   295			goto out_free_resources;
   296		}
   297	
   298		ret = regulator_enable(drv->proc_reg);
   299		if (ret) {
   300			dev_err(dev, "failed to enable proc regulator\n");
   301			goto out_free_resources;
   302		}
   303	
   304		drv->sram_reg = regulator_get_optional(dev, "sram");
   305		if (IS_ERR(drv->sram_reg))
   306			drv->sram_reg = NULL;
   307		else {
   308			ret = regulator_enable(drv->sram_reg);
   309			if (ret) {
   310				dev_err(dev, "failed to enable sram regulator\n");
   311				goto out_free_resources;
   312			}
   313		}
   314	
   315		/*
   316		 * We assume min voltage is 0 and tracking target voltage using
   317		 * min_volt_shift for each iteration.
   318		 * The retry_max is 3 times of expeted iteration count.
   319		 */
   320		drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data->sram_max_volt,
   321						       drv->soc_data->proc_max_volt),
   322						   drv->soc_data->min_volt_shift);
   323	
   324		ret = clk_prepare_enable(drv->cci_clk);
   325		if (ret)
   326			goto out_free_resources;
   327	
   328		ret = clk_prepare_enable(drv->inter_clk);
   329		if (ret)
   330			goto out_disable_cci_clk;
   331	
   332		ret = dev_pm_opp_of_add_table(dev);
   333		if (ret) {
   334			dev_err(dev, "failed to add opp table: %d\n", ret);
   335			goto out_disable_inter_clk;
   336		}
   337	
   338		rate = clk_get_rate(drv->inter_clk);
   339		opp = dev_pm_opp_find_freq_ceil(dev, &rate);
   340		if (IS_ERR(opp)) {
   341			ret = PTR_ERR(opp);
   342			dev_err(dev, "failed to get intermediate opp: %d\n", ret);
   343			goto out_remove_opp_table;
   344		}
   345		drv->inter_voltage = dev_pm_opp_get_voltage(opp);
   346		dev_pm_opp_put(opp);
   347	
   348		rate = U32_MAX;
   349		opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
   350		if (IS_ERR(opp)) {
   351			dev_err(dev, "failed to get opp\n");
   352			ret = PTR_ERR(opp);
   353			goto out_remove_opp_table;
   354		}
   355	
   356		opp_volt = dev_pm_opp_get_voltage(opp);
   357		dev_pm_opp_put(opp);
   358		ret = mtk_ccifreq_set_voltage(drv, opp_volt);
   359		if (ret) {
   360			dev_err(dev, "failed to scale to highest voltage %lu in proc_reg\n",
   361				opp_volt);
   362			goto out_remove_opp_table;
   363		}
   364	
   365		passive_data = devm_kzalloc(dev, sizeof(struct devfreq_passive_data),
   366					    GFP_KERNEL);
   367		if (!passive_data) {
   368			ret = -ENOMEM;
   369			goto out_remove_opp_table;
   370		}
   371	
   372		passive_data->parent_type = CPUFREQ_PARENT_DEV;
   373		drv->devfreq = devm_devfreq_add_device(dev, &mtk_ccifreq_profile,
   374						       DEVFREQ_GOV_PASSIVE,
   375						       passive_data);
   376		if (IS_ERR(drv->devfreq)) {
   377			ret = -EPROBE_DEFER;
 > 378			dev_err(dev, "failed to add devfreq device: %d\n",
   379				PTR_ERR(drv->devfreq));
   380			goto out_remove_opp_table;
   381		}
   382	
   383		drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
   384		ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
   385		if (ret) {
   386			dev_err(dev, "failed to register opp notifier: %d\n", ret);
   387			goto out_remove_devfreq_device;
   388		}
   389		return 0;
   390	
   391	out_remove_devfreq_device:
   392		devm_devfreq_remove_device(dev, drv->devfreq);
   393	
   394	out_remove_opp_table:
   395		dev_pm_opp_of_remove_table(dev);
   396	
   397	out_disable_inter_clk:
   398		clk_disable_unprepare(drv->inter_clk);
   399	
   400	out_disable_cci_clk:
   401		clk_disable_unprepare(drv->cci_clk);
   402	
   403	out_free_resources:
   404		if (regulator_is_enabled(drv->proc_reg))
   405			regulator_disable(drv->proc_reg);
   406		if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
   407			regulator_disable(drv->sram_reg);
   408	
   409		if (!IS_ERR(drv->proc_reg))
   410			regulator_put(drv->proc_reg);
   411		if (!IS_ERR(drv->sram_reg))
   412			regulator_put(drv->sram_reg);
   413		if (!IS_ERR(drv->cci_clk))
   414			clk_put(drv->cci_clk);
   415		if (!IS_ERR(drv->inter_clk))
   416			clk_put(drv->inter_clk);
   417	
   418		return ret;
   419	}
   420	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-04-25 12:55 ` [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver Johnson Wang
  2022-04-26 12:45   ` kernel test robot
@ 2022-04-27  7:09   ` kernel test robot
  2022-04-27  9:25   ` kernel test robot
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 27+ messages in thread
From: kernel test robot @ 2022-04-27  7:09 UTC (permalink / raw)
  To: Johnson Wang, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: kbuild-all, khilman, linux-pm, linux-kernel, devicetree,
	linux-arm-kernel, linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group, Johnson Wang

Hi Johnson,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on linus/master v5.18-rc4 next-20220426]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Johnson-Wang/Introduce-MediaTek-CCI-devfreq-driver/20220425-205820
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arc-allyesconfig (https://download.01.org/0day-ci/archive/20220427/202204271534.xh4s4n5E-lkp@intel.com/config)
compiler: arceb-elf-gcc (GCC) 11.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/98b34c0587837b0e5b880b11a52433f8f0eee19f
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Johnson-Wang/Introduce-MediaTek-CCI-devfreq-driver/20220425-205820
        git checkout 98b34c0587837b0e5b880b11a52433f8f0eee19f
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.3.0 make.cross W=1 O=build_dir ARCH=arc SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/devfreq/mtk-cci-devfreq.c: In function 'mtk_ccifreq_probe':
>> drivers/devfreq/mtk-cci-devfreq.c:372:21: error: 'struct devfreq_passive_data' has no member named 'parent_type'
     372 |         passive_data->parent_type = CPUFREQ_PARENT_DEV;
         |                     ^~
>> drivers/devfreq/mtk-cci-devfreq.c:372:37: error: 'CPUFREQ_PARENT_DEV' undeclared (first use in this function)
     372 |         passive_data->parent_type = CPUFREQ_PARENT_DEV;
         |                                     ^~~~~~~~~~~~~~~~~~
   drivers/devfreq/mtk-cci-devfreq.c:372:37: note: each undeclared identifier is reported only once for each function it appears in
   In file included from include/linux/device.h:15,
                    from include/linux/devfreq.h:13,
                    from drivers/devfreq/mtk-cci-devfreq.c:7:
   drivers/devfreq/mtk-cci-devfreq.c:378:30: warning: format '%d' expects argument of type 'int', but argument 3 has type 'long int' [-Wformat=]
     378 |                 dev_err(dev, "failed to add devfreq device: %d\n",
         |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:144:56: note: in expansion of macro 'dev_fmt'
     144 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/devfreq/mtk-cci-devfreq.c:378:17: note: in expansion of macro 'dev_err'
     378 |                 dev_err(dev, "failed to add devfreq device: %d\n",
         |                 ^~~~~~~
   drivers/devfreq/mtk-cci-devfreq.c:378:62: note: format string is defined here
     378 |                 dev_err(dev, "failed to add devfreq device: %d\n",
         |                                                             ~^
         |                                                              |
         |                                                              int
         |                                                             %ld


vim +372 drivers/devfreq/mtk-cci-devfreq.c

   255	
   256	static int mtk_ccifreq_probe(struct platform_device *pdev)
   257	{
   258		struct device *dev = &pdev->dev;
   259		struct mtk_ccifreq_drv *drv;
   260		struct devfreq_passive_data *passive_data;
   261		struct dev_pm_opp *opp;
   262		unsigned long rate, opp_volt;
   263		int ret;
   264	
   265		drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
   266		if (!drv)
   267			return -ENOMEM;
   268	
   269		drv->dev = dev;
   270		drv->soc_data = (const struct mtk_ccifreq_platform_data *)
   271					of_device_get_match_data(&pdev->dev);
   272		mutex_init(&drv->reg_lock);
   273		platform_set_drvdata(pdev, drv);
   274	
   275		drv->cci_clk = devm_clk_get(dev, "cci");
   276		if (IS_ERR(drv->cci_clk)) {
   277			ret = PTR_ERR(drv->cci_clk);
   278			return dev_err_probe(dev, ret,
   279					     "failed to get cci clk: %d\n", ret);
   280		}
   281	
   282		drv->inter_clk = devm_clk_get(dev, "intermediate");
   283		if (IS_ERR(drv->inter_clk)) {
   284			ret = PTR_ERR(drv->inter_clk);
   285			dev_err_probe(dev, ret,
   286				      "failed to get intermediate clk: %d\n", ret);
   287			goto out_free_resources;
   288		}
   289	
   290		drv->proc_reg = devm_regulator_get_optional(dev, "proc");
   291		if (IS_ERR(drv->proc_reg)) {
   292			ret = PTR_ERR(drv->proc_reg);
   293			dev_err_probe(dev, ret,
   294				      "failed to get proc regulator: %d\n", ret);
   295			goto out_free_resources;
   296		}
   297	
   298		ret = regulator_enable(drv->proc_reg);
   299		if (ret) {
   300			dev_err(dev, "failed to enable proc regulator\n");
   301			goto out_free_resources;
   302		}
   303	
   304		drv->sram_reg = regulator_get_optional(dev, "sram");
   305		if (IS_ERR(drv->sram_reg))
   306			drv->sram_reg = NULL;
   307		else {
   308			ret = regulator_enable(drv->sram_reg);
   309			if (ret) {
   310				dev_err(dev, "failed to enable sram regulator\n");
   311				goto out_free_resources;
   312			}
   313		}
   314	
   315		/*
   316		 * We assume min voltage is 0 and tracking target voltage using
   317		 * min_volt_shift for each iteration.
   318		 * The retry_max is 3 times of expeted iteration count.
   319		 */
   320		drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data->sram_max_volt,
   321						       drv->soc_data->proc_max_volt),
   322						   drv->soc_data->min_volt_shift);
   323	
   324		ret = clk_prepare_enable(drv->cci_clk);
   325		if (ret)
   326			goto out_free_resources;
   327	
   328		ret = clk_prepare_enable(drv->inter_clk);
   329		if (ret)
   330			goto out_disable_cci_clk;
   331	
   332		ret = dev_pm_opp_of_add_table(dev);
   333		if (ret) {
   334			dev_err(dev, "failed to add opp table: %d\n", ret);
   335			goto out_disable_inter_clk;
   336		}
   337	
   338		rate = clk_get_rate(drv->inter_clk);
   339		opp = dev_pm_opp_find_freq_ceil(dev, &rate);
   340		if (IS_ERR(opp)) {
   341			ret = PTR_ERR(opp);
   342			dev_err(dev, "failed to get intermediate opp: %d\n", ret);
   343			goto out_remove_opp_table;
   344		}
   345		drv->inter_voltage = dev_pm_opp_get_voltage(opp);
   346		dev_pm_opp_put(opp);
   347	
   348		rate = U32_MAX;
   349		opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
   350		if (IS_ERR(opp)) {
   351			dev_err(dev, "failed to get opp\n");
   352			ret = PTR_ERR(opp);
   353			goto out_remove_opp_table;
   354		}
   355	
   356		opp_volt = dev_pm_opp_get_voltage(opp);
   357		dev_pm_opp_put(opp);
   358		ret = mtk_ccifreq_set_voltage(drv, opp_volt);
   359		if (ret) {
   360			dev_err(dev, "failed to scale to highest voltage %lu in proc_reg\n",
   361				opp_volt);
   362			goto out_remove_opp_table;
   363		}
   364	
   365		passive_data = devm_kzalloc(dev, sizeof(struct devfreq_passive_data),
   366					    GFP_KERNEL);
   367		if (!passive_data) {
   368			ret = -ENOMEM;
   369			goto out_remove_opp_table;
   370		}
   371	
 > 372		passive_data->parent_type = CPUFREQ_PARENT_DEV;
   373		drv->devfreq = devm_devfreq_add_device(dev, &mtk_ccifreq_profile,
   374						       DEVFREQ_GOV_PASSIVE,
   375						       passive_data);
   376		if (IS_ERR(drv->devfreq)) {
   377			ret = -EPROBE_DEFER;
   378			dev_err(dev, "failed to add devfreq device: %d\n",
   379				PTR_ERR(drv->devfreq));
   380			goto out_remove_opp_table;
   381		}
   382	
   383		drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
   384		ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
   385		if (ret) {
   386			dev_err(dev, "failed to register opp notifier: %d\n", ret);
   387			goto out_remove_devfreq_device;
   388		}
   389		return 0;
   390	
   391	out_remove_devfreq_device:
   392		devm_devfreq_remove_device(dev, drv->devfreq);
   393	
   394	out_remove_opp_table:
   395		dev_pm_opp_of_remove_table(dev);
   396	
   397	out_disable_inter_clk:
   398		clk_disable_unprepare(drv->inter_clk);
   399	
   400	out_disable_cci_clk:
   401		clk_disable_unprepare(drv->cci_clk);
   402	
   403	out_free_resources:
   404		if (regulator_is_enabled(drv->proc_reg))
   405			regulator_disable(drv->proc_reg);
   406		if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
   407			regulator_disable(drv->sram_reg);
   408	
   409		if (!IS_ERR(drv->proc_reg))
   410			regulator_put(drv->proc_reg);
   411		if (!IS_ERR(drv->sram_reg))
   412			regulator_put(drv->sram_reg);
   413		if (!IS_ERR(drv->cci_clk))
   414			clk_put(drv->cci_clk);
   415		if (!IS_ERR(drv->inter_clk))
   416			clk_put(drv->inter_clk);
   417	
   418		return ret;
   419	}
   420	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-04-25 12:55 ` [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver Johnson Wang
  2022-04-26 12:45   ` kernel test robot
  2022-04-27  7:09   ` kernel test robot
@ 2022-04-27  9:25   ` kernel test robot
  2022-04-27 10:11     ` Johnson Wang
  2022-05-06 11:38   ` Johnson Wang
  2022-05-06 18:57   ` Chanwoo Choi
  4 siblings, 1 reply; 27+ messages in thread
From: kernel test robot @ 2022-04-27  9:25 UTC (permalink / raw)
  To: Johnson Wang, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: llvm, kbuild-all, khilman, linux-pm, linux-kernel, devicetree,
	linux-arm-kernel, linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group, Johnson Wang

Hi Johnson,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v5.18-rc4 next-20220427]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Johnson-Wang/Introduce-MediaTek-CCI-devfreq-driver/20220425-205820
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: hexagon-allyesconfig (https://download.01.org/0day-ci/archive/20220427/202204271737.oAuTwqZH-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 1cddcfdc3c683b393df1a5c9063252eb60e52818)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/98b34c0587837b0e5b880b11a52433f8f0eee19f
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Johnson-Wang/Introduce-MediaTek-CCI-devfreq-driver/20220425-205820
        git checkout 98b34c0587837b0e5b880b11a52433f8f0eee19f
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash block/partitions/ drivers/devfreq/ drivers/iio/imu/ drivers/misc/lkdtm/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/devfreq/mtk-cci-devfreq.c:372:16: error: no member named 'parent_type' in 'struct devfreq_passive_data'
           passive_data->parent_type = CPUFREQ_PARENT_DEV;
           ~~~~~~~~~~~~  ^
   drivers/devfreq/mtk-cci-devfreq.c:372:30: error: use of undeclared identifier 'CPUFREQ_PARENT_DEV'
           passive_data->parent_type = CPUFREQ_PARENT_DEV;
                                       ^
>> drivers/devfreq/mtk-cci-devfreq.c:379:4: warning: format specifies type 'int' but the argument has type 'long' [-Wformat]
                           PTR_ERR(drv->devfreq));
                           ^~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:144:65: note: expanded from macro 'dev_err'
           dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
                                                                  ~~~     ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
                   _p_func(dev, fmt, ##__VA_ARGS__);                       \
                                ~~~    ^~~~~~~~~~~
   1 warning and 2 errors generated.


vim +379 drivers/devfreq/mtk-cci-devfreq.c

   255	
   256	static int mtk_ccifreq_probe(struct platform_device *pdev)
   257	{
   258		struct device *dev = &pdev->dev;
   259		struct mtk_ccifreq_drv *drv;
   260		struct devfreq_passive_data *passive_data;
   261		struct dev_pm_opp *opp;
   262		unsigned long rate, opp_volt;
   263		int ret;
   264	
   265		drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
   266		if (!drv)
   267			return -ENOMEM;
   268	
   269		drv->dev = dev;
   270		drv->soc_data = (const struct mtk_ccifreq_platform_data *)
   271					of_device_get_match_data(&pdev->dev);
   272		mutex_init(&drv->reg_lock);
   273		platform_set_drvdata(pdev, drv);
   274	
   275		drv->cci_clk = devm_clk_get(dev, "cci");
   276		if (IS_ERR(drv->cci_clk)) {
   277			ret = PTR_ERR(drv->cci_clk);
   278			return dev_err_probe(dev, ret,
   279					     "failed to get cci clk: %d\n", ret);
   280		}
   281	
   282		drv->inter_clk = devm_clk_get(dev, "intermediate");
   283		if (IS_ERR(drv->inter_clk)) {
   284			ret = PTR_ERR(drv->inter_clk);
   285			dev_err_probe(dev, ret,
   286				      "failed to get intermediate clk: %d\n", ret);
   287			goto out_free_resources;
   288		}
   289	
   290		drv->proc_reg = devm_regulator_get_optional(dev, "proc");
   291		if (IS_ERR(drv->proc_reg)) {
   292			ret = PTR_ERR(drv->proc_reg);
   293			dev_err_probe(dev, ret,
   294				      "failed to get proc regulator: %d\n", ret);
   295			goto out_free_resources;
   296		}
   297	
   298		ret = regulator_enable(drv->proc_reg);
   299		if (ret) {
   300			dev_err(dev, "failed to enable proc regulator\n");
   301			goto out_free_resources;
   302		}
   303	
   304		drv->sram_reg = regulator_get_optional(dev, "sram");
   305		if (IS_ERR(drv->sram_reg))
   306			drv->sram_reg = NULL;
   307		else {
   308			ret = regulator_enable(drv->sram_reg);
   309			if (ret) {
   310				dev_err(dev, "failed to enable sram regulator\n");
   311				goto out_free_resources;
   312			}
   313		}
   314	
   315		/*
   316		 * We assume min voltage is 0 and tracking target voltage using
   317		 * min_volt_shift for each iteration.
   318		 * The retry_max is 3 times of expeted iteration count.
   319		 */
   320		drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data->sram_max_volt,
   321						       drv->soc_data->proc_max_volt),
   322						   drv->soc_data->min_volt_shift);
   323	
   324		ret = clk_prepare_enable(drv->cci_clk);
   325		if (ret)
   326			goto out_free_resources;
   327	
   328		ret = clk_prepare_enable(drv->inter_clk);
   329		if (ret)
   330			goto out_disable_cci_clk;
   331	
   332		ret = dev_pm_opp_of_add_table(dev);
   333		if (ret) {
   334			dev_err(dev, "failed to add opp table: %d\n", ret);
   335			goto out_disable_inter_clk;
   336		}
   337	
   338		rate = clk_get_rate(drv->inter_clk);
   339		opp = dev_pm_opp_find_freq_ceil(dev, &rate);
   340		if (IS_ERR(opp)) {
   341			ret = PTR_ERR(opp);
   342			dev_err(dev, "failed to get intermediate opp: %d\n", ret);
   343			goto out_remove_opp_table;
   344		}
   345		drv->inter_voltage = dev_pm_opp_get_voltage(opp);
   346		dev_pm_opp_put(opp);
   347	
   348		rate = U32_MAX;
   349		opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
   350		if (IS_ERR(opp)) {
   351			dev_err(dev, "failed to get opp\n");
   352			ret = PTR_ERR(opp);
   353			goto out_remove_opp_table;
   354		}
   355	
   356		opp_volt = dev_pm_opp_get_voltage(opp);
   357		dev_pm_opp_put(opp);
   358		ret = mtk_ccifreq_set_voltage(drv, opp_volt);
   359		if (ret) {
   360			dev_err(dev, "failed to scale to highest voltage %lu in proc_reg\n",
   361				opp_volt);
   362			goto out_remove_opp_table;
   363		}
   364	
   365		passive_data = devm_kzalloc(dev, sizeof(struct devfreq_passive_data),
   366					    GFP_KERNEL);
   367		if (!passive_data) {
   368			ret = -ENOMEM;
   369			goto out_remove_opp_table;
   370		}
   371	
   372		passive_data->parent_type = CPUFREQ_PARENT_DEV;
   373		drv->devfreq = devm_devfreq_add_device(dev, &mtk_ccifreq_profile,
   374						       DEVFREQ_GOV_PASSIVE,
   375						       passive_data);
   376		if (IS_ERR(drv->devfreq)) {
   377			ret = -EPROBE_DEFER;
   378			dev_err(dev, "failed to add devfreq device: %d\n",
 > 379				PTR_ERR(drv->devfreq));
   380			goto out_remove_opp_table;
   381		}
   382	
   383		drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
   384		ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
   385		if (ret) {
   386			dev_err(dev, "failed to register opp notifier: %d\n", ret);
   387			goto out_remove_devfreq_device;
   388		}
   389		return 0;
   390	
   391	out_remove_devfreq_device:
   392		devm_devfreq_remove_device(dev, drv->devfreq);
   393	
   394	out_remove_opp_table:
   395		dev_pm_opp_of_remove_table(dev);
   396	
   397	out_disable_inter_clk:
   398		clk_disable_unprepare(drv->inter_clk);
   399	
   400	out_disable_cci_clk:
   401		clk_disable_unprepare(drv->cci_clk);
   402	
   403	out_free_resources:
   404		if (regulator_is_enabled(drv->proc_reg))
   405			regulator_disable(drv->proc_reg);
   406		if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
   407			regulator_disable(drv->sram_reg);
   408	
   409		if (!IS_ERR(drv->proc_reg))
   410			regulator_put(drv->proc_reg);
   411		if (!IS_ERR(drv->sram_reg))
   412			regulator_put(drv->sram_reg);
   413		if (!IS_ERR(drv->cci_clk))
   414			clk_put(drv->cci_clk);
   415		if (!IS_ERR(drv->inter_clk))
   416			clk_put(drv->inter_clk);
   417	
   418		return ret;
   419	}
   420	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-04-27  9:25   ` kernel test robot
@ 2022-04-27 10:11     ` Johnson Wang
  2022-04-28 11:39       ` [kbuild-all] " Chen, Rong A
  0 siblings, 1 reply; 27+ messages in thread
From: Johnson Wang @ 2022-04-27 10:11 UTC (permalink / raw)
  To: kernel test robot, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: llvm, kbuild-all, khilman, linux-pm, linux-kernel, devicetree,
	linux-arm-kernel, linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

On Wed, 2022-04-27 at 17:25 +0800, kernel test robot wrote:
> Hi Johnson,
> 
> Thank you for the patch! Perhaps something to improve:
> 
> [auto build test WARNING on robh/for-next]
> [also build test WARNING on linus/master v5.18-rc4 next-20220427]
> [If your patch is applied to the wrong git tree, kindly drop us a
> note.
> And when submitting patch, we suggest to use '--base' as documented
> in
> 
https://urldefense.com/v3/__https://git-scm.com/docs/git-format-patch__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMS_s9zEZ$
>  ]
> 
> url:    
> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux/commits/Johnson-Wang/Introduce-MediaTek-CCI-devfreq-driver/20220425-205820__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMc1U_tqz$
>  
> base:   
> https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMUzTprof$
>   for-next
> config: hexagon-allyesconfig (
> https://urldefense.com/v3/__https://download.01.org/0day-ci/archive/20220427/202204271737.oAuTwqZH-lkp@intel.com/config__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMaVRzbSL$
>  )
> compiler: clang version 15.0.0 (
> https://urldefense.com/v3/__https://github.com/llvm/llvm-project__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMRqw5IY-$
> $  1cddcfdc3c683b393df1a5c9063252eb60e52818)
> reproduce (this is a W=1 build):
>         wget 
> https://urldefense.com/v3/__https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMQLiD-i9$
>   -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # 
> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux/commit/98b34c0587837b0e5b880b11a52433f8f0eee19f__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMU5yd7Y2$
>  
>         git remote add linux-review 
> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMW4ldtnH$
>  
>         git fetch --no-tags linux-review Johnson-Wang/Introduce-
> MediaTek-CCI-devfreq-driver/20220425-205820
>         git checkout 98b34c0587837b0e5b880b11a52433f8f0eee19f
>         # save the config file
>         mkdir build_dir && cp config build_dir/.config
>         COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross
> W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash block/partitions/
> drivers/devfreq/ drivers/iio/imu/ drivers/misc/lkdtm/
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
> 
> All warnings (new ones prefixed by >>):
> 
>    drivers/devfreq/mtk-cci-devfreq.c:372:16: error: no member named
> 'parent_type' in 'struct devfreq_passive_data'
>            passive_data->parent_type = CPUFREQ_PARENT_DEV;
>            ~~~~~~~~~~~~  ^
>    drivers/devfreq/mtk-cci-devfreq.c:372:30: error: use of undeclared
> identifier 'CPUFREQ_PARENT_DEV'
>            passive_data->parent_type = CPUFREQ_PARENT_DEV;
>                                        ^
> > > drivers/devfreq/mtk-cci-devfreq.c:379:4: warning: format
> > > specifies type 'int' but the argument has type 'long' [-Wformat]
> 
>                            PTR_ERR(drv->devfreq));
>                            ^~~~~~~~~~~~~~~~~~~~~
>    include/linux/dev_printk.h:144:65: note: expanded from macro
> 'dev_err'
>            dev_printk_index_wrap(_dev_err, KERN_ERR, dev,
> dev_fmt(fmt), ##__VA_ARGS__)
>                                                                   ~~~
>      ^~~~~~~~~~~
>    include/linux/dev_printk.h:110:23: note: expanded from macro
> 'dev_printk_index_wrap'
>                    _p_func(dev, fmt,
> ##__VA_ARGS__);                       \
>                                 ~~~    ^~~~~~~~~~~
>    1 warning and 2 errors generated.
> 
> 
> vim +379 drivers/devfreq/mtk-cci-devfreq.c
> 
>    255	
>    256	static int mtk_ccifreq_probe(struct platform_device
> *pdev)
>    257	{
>    258		struct device *dev = &pdev->dev;
>    259		struct mtk_ccifreq_drv *drv;
>    260		struct devfreq_passive_data *passive_data;
>    261		struct dev_pm_opp *opp;
>    262		unsigned long rate, opp_volt;
>    263		int ret;
>    264	
>    265		drv = devm_kzalloc(dev, sizeof(*drv),
> GFP_KERNEL);
>    266		if (!drv)
>    267			return -ENOMEM;
>    268	
>    269		drv->dev = dev;
>    270		drv->soc_data = (const struct
> mtk_ccifreq_platform_data *)
>    271					of_device_get_match_dat
> a(&pdev->dev);
>    272		mutex_init(&drv->reg_lock);
>    273		platform_set_drvdata(pdev, drv);
>    274	
>    275		drv->cci_clk = devm_clk_get(dev, "cci");
>    276		if (IS_ERR(drv->cci_clk)) {
>    277			ret = PTR_ERR(drv->cci_clk);
>    278			return dev_err_probe(dev, ret,
>    279					     "failed to get cci
> clk: %d\n", ret);
>    280		}
>    281	
>    282		drv->inter_clk = devm_clk_get(dev,
> "intermediate");
>    283		if (IS_ERR(drv->inter_clk)) {
>    284			ret = PTR_ERR(drv->inter_clk);
>    285			dev_err_probe(dev, ret,
>    286				      "failed to get
> intermediate clk: %d\n", ret);
>    287			goto out_free_resources;
>    288		}
>    289	
>    290		drv->proc_reg =
> devm_regulator_get_optional(dev, "proc");
>    291		if (IS_ERR(drv->proc_reg)) {
>    292			ret = PTR_ERR(drv->proc_reg);
>    293			dev_err_probe(dev, ret,
>    294				      "failed to get proc
> regulator: %d\n", ret);
>    295			goto out_free_resources;
>    296		}
>    297	
>    298		ret = regulator_enable(drv->proc_reg);
>    299		if (ret) {
>    300			dev_err(dev, "failed to enable proc
> regulator\n");
>    301			goto out_free_resources;
>    302		}
>    303	
>    304		drv->sram_reg = regulator_get_optional(dev,
> "sram");
>    305		if (IS_ERR(drv->sram_reg))
>    306			drv->sram_reg = NULL;
>    307		else {
>    308			ret = regulator_enable(drv->sram_reg);
>    309			if (ret) {
>    310				dev_err(dev, "failed to enable
> sram regulator\n");
>    311				goto out_free_resources;
>    312			}
>    313		}
>    314	
>    315		/*
>    316		 * We assume min voltage is 0 and tracking
> target voltage using
>    317		 * min_volt_shift for each iteration.
>    318		 * The retry_max is 3 times of expeted
> iteration count.
>    319		 */
>    320		drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv-
> >soc_data->sram_max_volt,
>    321						       drv-
> >soc_data->proc_max_volt),
>    322						   drv-
> >soc_data->min_volt_shift);
>    323	
>    324		ret = clk_prepare_enable(drv->cci_clk);
>    325		if (ret)
>    326			goto out_free_resources;
>    327	
>    328		ret = clk_prepare_enable(drv->inter_clk);
>    329		if (ret)
>    330			goto out_disable_cci_clk;
>    331	
>    332		ret = dev_pm_opp_of_add_table(dev);
>    333		if (ret) {
>    334			dev_err(dev, "failed to add opp table:
> %d\n", ret);
>    335			goto out_disable_inter_clk;
>    336		}
>    337	
>    338		rate = clk_get_rate(drv->inter_clk);
>    339		opp = dev_pm_opp_find_freq_ceil(dev, &rate);
>    340		if (IS_ERR(opp)) {
>    341			ret = PTR_ERR(opp);
>    342			dev_err(dev, "failed to get
> intermediate opp: %d\n", ret);
>    343			goto out_remove_opp_table;
>    344		}
>    345		drv->inter_voltage =
> dev_pm_opp_get_voltage(opp);
>    346		dev_pm_opp_put(opp);
>    347	
>    348		rate = U32_MAX;
>    349		opp = dev_pm_opp_find_freq_floor(drv->dev,
> &rate);
>    350		if (IS_ERR(opp)) {
>    351			dev_err(dev, "failed to get opp\n");
>    352			ret = PTR_ERR(opp);
>    353			goto out_remove_opp_table;
>    354		}
>    355	
>    356		opp_volt = dev_pm_opp_get_voltage(opp);
>    357		dev_pm_opp_put(opp);
>    358		ret = mtk_ccifreq_set_voltage(drv, opp_volt);
>    359		if (ret) {
>    360			dev_err(dev, "failed to scale to
> highest voltage %lu in proc_reg\n",
>    361				opp_volt);
>    362			goto out_remove_opp_table;
>    363		}
>    364	
>    365		passive_data = devm_kzalloc(dev, sizeof(struct
> devfreq_passive_data),
>    366					    GFP_KERNEL);
>    367		if (!passive_data) {
>    368			ret = -ENOMEM;
>    369			goto out_remove_opp_table;
>    370		}
>    371	
>    372		passive_data->parent_type = CPUFREQ_PARENT_DEV;
>    373		drv->devfreq = devm_devfreq_add_device(dev,
> &mtk_ccifreq_profile,
>    374						       DEVFREQ_
> GOV_PASSIVE,
>    375						       passive_
> data);
>    376		if (IS_ERR(drv->devfreq)) {
>    377			ret = -EPROBE_DEFER;
>    378			dev_err(dev, "failed to add devfreq
> device: %d\n",
>  > 379				PTR_ERR(drv->devfreq));
>    380			goto out_remove_opp_table;
>    381		}
>    382	
>    383		drv->opp_nb.notifier_call =
> mtk_ccifreq_opp_notifier;
>    384		ret = dev_pm_opp_register_notifier(dev, &drv-
> >opp_nb);
>    385		if (ret) {
>    386			dev_err(dev, "failed to register opp
> notifier: %d\n", ret);
>    387			goto out_remove_devfreq_device;
>    388		}
>    389		return 0;
>    390	
>    391	out_remove_devfreq_device:
>    392		devm_devfreq_remove_device(dev, drv->devfreq);
>    393	
>    394	out_remove_opp_table:
>    395		dev_pm_opp_of_remove_table(dev);
>    396	
>    397	out_disable_inter_clk:
>    398		clk_disable_unprepare(drv->inter_clk);
>    399	
>    400	out_disable_cci_clk:
>    401		clk_disable_unprepare(drv->cci_clk);
>    402	
>    403	out_free_resources:
>    404		if (regulator_is_enabled(drv->proc_reg))
>    405			regulator_disable(drv->proc_reg);
>    406		if (drv->sram_reg && regulator_is_enabled(drv-
> >sram_reg))
>    407			regulator_disable(drv->sram_reg);
>    408	
>    409		if (!IS_ERR(drv->proc_reg))
>    410			regulator_put(drv->proc_reg);
>    411		if (!IS_ERR(drv->sram_reg))
>    412			regulator_put(drv->sram_reg);
>    413		if (!IS_ERR(drv->cci_clk))
>    414			clk_put(drv->cci_clk);
>    415		if (!IS_ERR(drv->inter_clk))
>    416			clk_put(drv->inter_clk);
>    417	
>    418		return ret;
>    419	}
>    420	
> 

Hi "kernel test robot",

Thanks for your review.

This patch is based on chanwoo/devfreq-testing[1]
[1]
https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing

I will follow your suggestion to use '--base' in the next version.

BRs,
Johnson Wang


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [kbuild-all] Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-04-27 10:11     ` Johnson Wang
@ 2022-04-28 11:39       ` Chen, Rong A
  2022-05-06 12:03         ` Chen-Yu Tsai
  0 siblings, 1 reply; 27+ messages in thread
From: Chen, Rong A @ 2022-04-28 11:39 UTC (permalink / raw)
  To: Johnson Wang, kernel test robot, cw00.choi, krzk+dt, robh+dt,
	kyungmin.park
  Cc: llvm, kbuild-all, linux-pm, linux-kernel, devicetree,
	linux-arm-kernel, linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group



On 4/27/2022 6:11 PM, Johnson Wang wrote:
> On Wed, 2022-04-27 at 17:25 +0800, kernel test robot wrote:
>> Hi Johnson,
>>
>> Thank you for the patch! Perhaps something to improve:
>>
>> [auto build test WARNING on robh/for-next]
>> [also build test WARNING on linus/master v5.18-rc4 next-20220427]
>> [If your patch is applied to the wrong git tree, kindly drop us a
>> note.
>> And when submitting patch, we suggest to use '--base' as documented
>> in
>>
> https://urldefense.com/v3/__https://git-scm.com/docs/git-format-patch__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMS_s9zEZ$
>>   ]
>>
>> url:
>> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux/commits/Johnson-Wang/Introduce-MediaTek-CCI-devfreq-driver/20220425-205820__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMc1U_tqz$
>>   
>> base:
>> https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMUzTprof$
>>    for-next
>> config: hexagon-allyesconfig (
>> https://urldefense.com/v3/__https://download.01.org/0day-ci/archive/20220427/202204271737.oAuTwqZH-lkp@intel.com/config__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMaVRzbSL$
>>   )
>> compiler: clang version 15.0.0 (
>> https://urldefense.com/v3/__https://github.com/llvm/llvm-project__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMRqw5IY-$
>> $  1cddcfdc3c683b393df1a5c9063252eb60e52818)
>> reproduce (this is a W=1 build):
>>          wget
>> https://urldefense.com/v3/__https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMQLiD-i9$
>>    -O ~/bin/make.cross
>>          chmod +x ~/bin/make.cross
>>          #
>> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux/commit/98b34c0587837b0e5b880b11a52433f8f0eee19f__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMU5yd7Y2$
>>   
>>          git remote add linux-review
>> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMW4ldtnH$
>>   
>>          git fetch --no-tags linux-review Johnson-Wang/Introduce-
>> MediaTek-CCI-devfreq-driver/20220425-205820
>>          git checkout 98b34c0587837b0e5b880b11a52433f8f0eee19f
>>          # save the config file
>>          mkdir build_dir && cp config build_dir/.config
>>          COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross
>> W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash block/partitions/
>> drivers/devfreq/ drivers/iio/imu/ drivers/misc/lkdtm/
>>
>> If you fix the issue, kindly add following tag as appropriate
>> Reported-by: kernel test robot <lkp@intel.com>
>>
>> All warnings (new ones prefixed by >>):
>>
>>     drivers/devfreq/mtk-cci-devfreq.c:372:16: error: no member named
>> 'parent_type' in 'struct devfreq_passive_data'
>>             passive_data->parent_type = CPUFREQ_PARENT_DEV;
>>             ~~~~~~~~~~~~  ^
>>     drivers/devfreq/mtk-cci-devfreq.c:372:30: error: use of undeclared
>> identifier 'CPUFREQ_PARENT_DEV'
>>             passive_data->parent_type = CPUFREQ_PARENT_DEV;
>>                                         ^
>>>> drivers/devfreq/mtk-cci-devfreq.c:379:4: warning: format
>>>> specifies type 'int' but the argument has type 'long' [-Wformat]
>>
>>                             PTR_ERR(drv->devfreq));
>>                             ^~~~~~~~~~~~~~~~~~~~~
>>     include/linux/dev_printk.h:144:65: note: expanded from macro
>> 'dev_err'
>>             dev_printk_index_wrap(_dev_err, KERN_ERR, dev,
>> dev_fmt(fmt), ##__VA_ARGS__)
>>                                                                    ~~~
>>       ^~~~~~~~~~~
>>     include/linux/dev_printk.h:110:23: note: expanded from macro
>> 'dev_printk_index_wrap'
>>                     _p_func(dev, fmt,
>> ##__VA_ARGS__);                       \
>>                                  ~~~    ^~~~~~~~~~~
>>     1 warning and 2 errors generated.
>>
>>
>> vim +379 drivers/devfreq/mtk-cci-devfreq.c
>>
>>     255	
>>     256	static int mtk_ccifreq_probe(struct platform_device
>> *pdev)
>>     257	{
>>     258		struct device *dev = &pdev->dev;
>>     259		struct mtk_ccifreq_drv *drv;
>>     260		struct devfreq_passive_data *passive_data;
>>     261		struct dev_pm_opp *opp;
>>     262		unsigned long rate, opp_volt;
>>     263		int ret;
>>     264	
>>     265		drv = devm_kzalloc(dev, sizeof(*drv),
>> GFP_KERNEL);
>>     266		if (!drv)
>>     267			return -ENOMEM;
>>     268	
>>     269		drv->dev = dev;
>>     270		drv->soc_data = (const struct
>> mtk_ccifreq_platform_data *)
>>     271					of_device_get_match_dat
>> a(&pdev->dev);
>>     272		mutex_init(&drv->reg_lock);
>>     273		platform_set_drvdata(pdev, drv);
>>     274	
>>     275		drv->cci_clk = devm_clk_get(dev, "cci");
>>     276		if (IS_ERR(drv->cci_clk)) {
>>     277			ret = PTR_ERR(drv->cci_clk);
>>     278			return dev_err_probe(dev, ret,
>>     279					     "failed to get cci
>> clk: %d\n", ret);
>>     280		}
>>     281	
>>     282		drv->inter_clk = devm_clk_get(dev,
>> "intermediate");
>>     283		if (IS_ERR(drv->inter_clk)) {
>>     284			ret = PTR_ERR(drv->inter_clk);
>>     285			dev_err_probe(dev, ret,
>>     286				      "failed to get
>> intermediate clk: %d\n", ret);
>>     287			goto out_free_resources;
>>     288		}
>>     289	
>>     290		drv->proc_reg =
>> devm_regulator_get_optional(dev, "proc");
>>     291		if (IS_ERR(drv->proc_reg)) {
>>     292			ret = PTR_ERR(drv->proc_reg);
>>     293			dev_err_probe(dev, ret,
>>     294				      "failed to get proc
>> regulator: %d\n", ret);
>>     295			goto out_free_resources;
>>     296		}
>>     297	
>>     298		ret = regulator_enable(drv->proc_reg);
>>     299		if (ret) {
>>     300			dev_err(dev, "failed to enable proc
>> regulator\n");
>>     301			goto out_free_resources;
>>     302		}
>>     303	
>>     304		drv->sram_reg = regulator_get_optional(dev,
>> "sram");
>>     305		if (IS_ERR(drv->sram_reg))
>>     306			drv->sram_reg = NULL;
>>     307		else {
>>     308			ret = regulator_enable(drv->sram_reg);
>>     309			if (ret) {
>>     310				dev_err(dev, "failed to enable
>> sram regulator\n");
>>     311				goto out_free_resources;
>>     312			}
>>     313		}
>>     314	
>>     315		/*
>>     316		 * We assume min voltage is 0 and tracking
>> target voltage using
>>     317		 * min_volt_shift for each iteration.
>>     318		 * The retry_max is 3 times of expeted
>> iteration count.
>>     319		 */
>>     320		drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv-
>>> soc_data->sram_max_volt,
>>     321						       drv-
>>> soc_data->proc_max_volt),
>>     322						   drv-
>>> soc_data->min_volt_shift);
>>     323	
>>     324		ret = clk_prepare_enable(drv->cci_clk);
>>     325		if (ret)
>>     326			goto out_free_resources;
>>     327	
>>     328		ret = clk_prepare_enable(drv->inter_clk);
>>     329		if (ret)
>>     330			goto out_disable_cci_clk;
>>     331	
>>     332		ret = dev_pm_opp_of_add_table(dev);
>>     333		if (ret) {
>>     334			dev_err(dev, "failed to add opp table:
>> %d\n", ret);
>>     335			goto out_disable_inter_clk;
>>     336		}
>>     337	
>>     338		rate = clk_get_rate(drv->inter_clk);
>>     339		opp = dev_pm_opp_find_freq_ceil(dev, &rate);
>>     340		if (IS_ERR(opp)) {
>>     341			ret = PTR_ERR(opp);
>>     342			dev_err(dev, "failed to get
>> intermediate opp: %d\n", ret);
>>     343			goto out_remove_opp_table;
>>     344		}
>>     345		drv->inter_voltage =
>> dev_pm_opp_get_voltage(opp);
>>     346		dev_pm_opp_put(opp);
>>     347	
>>     348		rate = U32_MAX;
>>     349		opp = dev_pm_opp_find_freq_floor(drv->dev,
>> &rate);
>>     350		if (IS_ERR(opp)) {
>>     351			dev_err(dev, "failed to get opp\n");
>>     352			ret = PTR_ERR(opp);
>>     353			goto out_remove_opp_table;
>>     354		}
>>     355	
>>     356		opp_volt = dev_pm_opp_get_voltage(opp);
>>     357		dev_pm_opp_put(opp);
>>     358		ret = mtk_ccifreq_set_voltage(drv, opp_volt);
>>     359		if (ret) {
>>     360			dev_err(dev, "failed to scale to
>> highest voltage %lu in proc_reg\n",
>>     361				opp_volt);
>>     362			goto out_remove_opp_table;
>>     363		}
>>     364	
>>     365		passive_data = devm_kzalloc(dev, sizeof(struct
>> devfreq_passive_data),
>>     366					    GFP_KERNEL);
>>     367		if (!passive_data) {
>>     368			ret = -ENOMEM;
>>     369			goto out_remove_opp_table;
>>     370		}
>>     371	
>>     372		passive_data->parent_type = CPUFREQ_PARENT_DEV;
>>     373		drv->devfreq = devm_devfreq_add_device(dev,
>> &mtk_ccifreq_profile,
>>     374						       DEVFREQ_
>> GOV_PASSIVE,
>>     375						       passive_
>> data);
>>     376		if (IS_ERR(drv->devfreq)) {
>>     377			ret = -EPROBE_DEFER;
>>     378			dev_err(dev, "failed to add devfreq
>> device: %d\n",
>>   > 379				PTR_ERR(drv->devfreq));
>>     380			goto out_remove_opp_table;
>>     381		}
>>     382	
>>     383		drv->opp_nb.notifier_call =
>> mtk_ccifreq_opp_notifier;
>>     384		ret = dev_pm_opp_register_notifier(dev, &drv-
>>> opp_nb);
>>     385		if (ret) {
>>     386			dev_err(dev, "failed to register opp
>> notifier: %d\n", ret);
>>     387			goto out_remove_devfreq_device;
>>     388		}
>>     389		return 0;
>>     390	
>>     391	out_remove_devfreq_device:
>>     392		devm_devfreq_remove_device(dev, drv->devfreq);
>>     393	
>>     394	out_remove_opp_table:
>>     395		dev_pm_opp_of_remove_table(dev);
>>     396	
>>     397	out_disable_inter_clk:
>>     398		clk_disable_unprepare(drv->inter_clk);
>>     399	
>>     400	out_disable_cci_clk:
>>     401		clk_disable_unprepare(drv->cci_clk);
>>     402	
>>     403	out_free_resources:
>>     404		if (regulator_is_enabled(drv->proc_reg))
>>     405			regulator_disable(drv->proc_reg);
>>     406		if (drv->sram_reg && regulator_is_enabled(drv-
>>> sram_reg))
>>     407			regulator_disable(drv->sram_reg);
>>     408	
>>     409		if (!IS_ERR(drv->proc_reg))
>>     410			regulator_put(drv->proc_reg);
>>     411		if (!IS_ERR(drv->sram_reg))
>>     412			regulator_put(drv->sram_reg);
>>     413		if (!IS_ERR(drv->cci_clk))
>>     414			clk_put(drv->cci_clk);
>>     415		if (!IS_ERR(drv->inter_clk))
>>     416			clk_put(drv->inter_clk);
>>     417	
>>     418		return ret;
>>     419	}
>>     420	
>>
> 
> Hi "kernel test robot",
> 
> Thanks for your review.
> 
> This patch is based on chanwoo/devfreq-testing[1]
> [1]
> https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing

Hi Johnson,

Thanks for the feedback, we'll take a look too.

Best Regards,
Rong Chen

> 
> I will follow your suggestion to use '--base' in the next version.
> 
> BRs,
> Johnson Wang
> _______________________________________________
> kbuild-all mailing list -- kbuild-all@lists.01.org
> To unsubscribe send an email to kbuild-all-leave@lists.01.org
> 

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-04-25 12:55 ` [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver Johnson Wang
                     ` (2 preceding siblings ...)
  2022-04-27  9:25   ` kernel test robot
@ 2022-05-06 11:38   ` Johnson Wang
  2022-05-07 13:53     ` Chanwoo Choi
  2022-05-06 18:57   ` Chanwoo Choi
  4 siblings, 1 reply; 27+ messages in thread
From: Johnson Wang @ 2022-05-06 11:38 UTC (permalink / raw)
  To: cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

On Mon, 2022-04-25 at 20:55 +0800, Johnson Wang wrote:
> We introduce a devfreq driver for the MediaTek Cache Coherent
> Interconnect
> (CCI) used by some MediaTek SoCs.
> 
> In this driver, we use the passive devfreq driver to get target
> frequencies
> and adjust voltages accordingly. In MT8183 and MT8186, the MediaTek
> CCI
> is supplied by the same regulators with the little core CPUs.
> 
> Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> ---
> This patch depends on "devfreq-testing"[1].
> [1]
> https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing
> ---
>  drivers/devfreq/Kconfig           |  10 +
>  drivers/devfreq/Makefile          |   1 +
>  drivers/devfreq/mtk-cci-devfreq.c | 474
> ++++++++++++++++++++++++++++++
>  3 files changed, 485 insertions(+)
>  create mode 100644 drivers/devfreq/mtk-cci-devfreq.c
> 
> diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
> index 87eb2b837e68..9754d8b31621 100644
> --- a/drivers/devfreq/Kconfig
> +++ b/drivers/devfreq/Kconfig
> @@ -120,6 +120,16 @@ config ARM_TEGRA_DEVFREQ
>  	  It reads ACTMON counters of memory controllers and adjusts
> the
>  	  operating frequencies and voltages with OPP support.
>  
> +config ARM_MEDIATEK_CCI_DEVFREQ
> +	tristate "MEDIATEK CCI DEVFREQ Driver"
> +	depends on ARM_MEDIATEK_CPUFREQ || COMPILE_TEST
> +	select DEVFREQ_GOV_PASSIVE
> +	help
> +	  This adds a devfreq driver for MediaTek Cache Coherent
> Interconnect
> +	  which is shared the same regulators with the cpu cluster. It
> can track
> +	  buck voltages and update a proper CCI frequency. Use the
> notification
> +	  to get the regulator status.
> +
>  config ARM_RK3399_DMC_DEVFREQ
>  	tristate "ARM RK3399 DMC DEVFREQ Driver"
>  	depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
> diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
> index 0b6be92a25d9..bf40d04928d0 100644
> --- a/drivers/devfreq/Makefile
> +++ b/drivers/devfreq/Makefile
> @@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+=
> governor_passive.o
>  obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
>  obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o
>  obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
> +obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ)	+= mtk-cci-devfreq.o
>  obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
>  obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ)	+= sun8i-a33-mbus.o
>  obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-devfreq.o
> diff --git a/drivers/devfreq/mtk-cci-devfreq.c b/drivers/devfreq/mtk-
> cci-devfreq.c
> new file mode 100644
> index 000000000000..b3e31c45a57c
> --- /dev/null
> +++ b/drivers/devfreq/mtk-cci-devfreq.c
> @@ -0,0 +1,474 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 MediaTek Inc.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/devfreq.h>
> +#include <linux/minmax.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_opp.h>
> +#include <linux/regulator/consumer.h>
> +
> +struct mtk_ccifreq_platform_data {
> +	int min_volt_shift;
> +	int max_volt_shift;
> +	int proc_max_volt;
> +	int sram_min_volt;
> +	int sram_max_volt;
> +};
> +
> +struct mtk_ccifreq_drv {
> +	struct device *dev;
> +	struct devfreq *devfreq;
> +	struct regulator *proc_reg;
> +	struct regulator *sram_reg;
> +	struct clk *cci_clk;
> +	struct clk *inter_clk;
> +	int inter_voltage;
> +	int pre_voltage;
> +	unsigned long pre_freq;
> +	/* Avoid race condition for regulators between notify and
> policy */
> +	struct mutex reg_lock;
> +	struct notifier_block opp_nb;
> +	const struct mtk_ccifreq_platform_data *soc_data;
> +	int vtrack_max;
> +};
> +
> +static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv, int
> new_voltage)
> +{
> +	const struct mtk_ccifreq_platform_data *soc_data = drv-
> >soc_data;
> +	struct device *dev = drv->dev;
> +	int pre_voltage, pre_vsram, new_vsram, vsram, voltage, ret;
> +	int retry_max = drv->vtrack_max;
> +
> +	if (!drv->sram_reg) {
> +		ret = regulator_set_voltage(drv->proc_reg, new_voltage,
> +					    drv->soc_data-
> >proc_max_volt);
> +		goto out_set_voltage;
> +	}
> +
> +	pre_voltage = regulator_get_voltage(drv->proc_reg);
> +	if (pre_voltage < 0) {
> +		dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
> +		return pre_voltage;
> +	}
> +
> +	pre_vsram = regulator_get_voltage(drv->sram_reg);
> +	if (pre_vsram < 0) {
> +		dev_err(dev, "invalid vsram value: %d\n", pre_vsram);
> +		return pre_vsram;
> +	}
> +
> +	new_vsram = clamp(new_voltage + soc_data->min_volt_shift,
> +			  soc_data->sram_min_volt, soc_data-
> >sram_max_volt);
> +
> +	do {
> +		if (pre_voltage <= new_voltage) {
> +			vsram = clamp(pre_voltage + soc_data-
> >max_volt_shift,
> +				      soc_data->sram_min_volt,
> new_vsram);
> +			ret = regulator_set_voltage(drv->sram_reg,
> vsram,
> +						    soc_data-
> >sram_max_volt);
> +			if (ret)
> +				return ret;
> +
> +			if (vsram == soc_data->sram_max_volt ||
> +			    new_vsram == soc_data->sram_min_volt)
> +				voltage = new_voltage;
> +			else
> +				voltage = vsram - soc_data-
> >min_volt_shift;
> +
> +			ret = regulator_set_voltage(drv->proc_reg,
> voltage,
> +						    soc_data-
> >proc_max_volt);
> +			if (ret) {
> +				regulator_set_voltage(drv->sram_reg,
> pre_vsram,
> +						      soc_data-
> >sram_max_volt);
> +				return ret;
> +			}
> +		} else if (pre_voltage > new_voltage) {
> +			voltage = max(new_voltage,
> +				      pre_vsram - soc_data-
> >max_volt_shift);
> +			ret = regulator_set_voltage(drv->proc_reg,
> voltage,
> +						    soc_data-
> >proc_max_volt);
> +			if (ret)
> +				return ret;
> +
> +			if (voltage == new_voltage)
> +				vsram = new_vsram;
> +			else
> +				vsram = max(new_vsram,
> +					    voltage + soc_data-
> >min_volt_shift);
> +
> +			ret = regulator_set_voltage(drv->sram_reg,
> vsram,
> +						    soc_data-
> >sram_max_volt);
> +			if (ret) {
> +				regulator_set_voltage(drv->proc_reg,
> pre_voltage,
> +						      soc_data-
> >proc_max_volt);
> +				return ret;
> +			}
> +		}
> +
> +		pre_voltage = voltage;
> +		pre_vsram = vsram;
> +
> +		if (--retry_max < 0) {
> +			dev_err(dev,
> +				"over loop count, failed to set
> voltage\n");
> +			return -EINVAL;
> +		}
> +	} while (voltage != new_voltage || vsram != new_vsram);
> +
> +out_set_voltage:
> +	if (!ret)
> +		drv->pre_voltage = new_voltage;
> +
> +	return ret;
> +}
> +
> +static int mtk_ccifreq_target(struct device *dev, unsigned long
> *freq,
> +			      u32 flags)
> +{
> +	struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev);
> +	struct clk *cci_pll = clk_get_parent(drv->cci_clk);
> +	struct dev_pm_opp *opp;
> +	unsigned long opp_rate;
> +	int voltage, pre_voltage, inter_voltage, target_voltage, ret;
> +
> +	if (!drv)
> +		return -EINVAL;
> +
> +	if (drv->pre_freq == *freq)
> +		return 0;
> +
> +	inter_voltage = drv->inter_voltage;
> +
> +	opp_rate = *freq;
> +	opp = devfreq_recommended_opp(dev, &opp_rate, 1);
> +	if (IS_ERR(opp)) {
> +		dev_err(dev, "failed to find opp for freq: %ld\n",
> opp_rate);
> +		return PTR_ERR(opp);
> +	}
> +
> +	mutex_lock(&drv->reg_lock);
> +
> +	voltage = dev_pm_opp_get_voltage(opp);
> +	dev_pm_opp_put(opp);
> +
> +	if (unlikely(drv->pre_voltage <= 0))
> +		pre_voltage = regulator_get_voltage(drv->proc_reg);
> +	else
> +		pre_voltage = drv->pre_voltage;
> +
> +	if (pre_voltage < 0) {
> +		dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
> +		return pre_voltage;
> +	}
> +
> +	/* scale up: set voltage first then freq. */
> +	target_voltage = max(inter_voltage, voltage);
> +	if (pre_voltage <= target_voltage) {
> +		ret = mtk_ccifreq_set_voltage(drv, target_voltage);
> +		if (ret) {
> +			dev_err(dev, "failed to scale up voltage\n");
> +			goto out_restore_voltage;
> +		}
> +	}
> +
> +	/* switch the cci clock to intermediate clock source. */
> +	ret = clk_set_parent(drv->cci_clk, drv->inter_clk);
> +	if (ret) {
> +		dev_err(dev, "failed to re-parent cci clock\n");
> +		goto out_restore_voltage;
> +	}
> +
> +	/* set the original clock to target rate. */
> +	ret = clk_set_rate(cci_pll, *freq);
> +	if (ret) {
> +		dev_err(dev, "failed to set cci pll rate: %d\n", ret);
> +		clk_set_parent(drv->cci_clk, cci_pll);
> +		goto out_restore_voltage;
> +	}
> +
> +	/* switch the cci clock back to the original clock source. */
> +	ret = clk_set_parent(drv->cci_clk, cci_pll);
> +	if (ret) {
> +		dev_err(dev, "failed to re-parent cci clock\n");
> +		mtk_ccifreq_set_voltage(drv, inter_voltage);
> +		goto out_unlock;
> +	}
> +
> +	/*
> +	 * If the new voltage is lower than the intermediate voltage or
> the
> +	 * original voltage, scale down to the new voltage.
> +	 */
> +	if (voltage < inter_voltage || voltage < pre_voltage) {
> +		ret = mtk_ccifreq_set_voltage(drv, voltage);
> +		if (ret) {
> +			dev_err(dev, "failed to scale down voltage\n");
> +			goto out_unlock;
> +		}
> +	}
> +
> +	drv->pre_freq = *freq;
> +	mutex_unlock(&drv->reg_lock);
> +
> +	return 0;
> +
> +out_restore_voltage:
> +	mtk_ccifreq_set_voltage(drv, pre_voltage);
> +
> +out_unlock:
> +	mutex_unlock(&drv->reg_lock);
> +	return ret;
> +}
> +
> +static int mtk_ccifreq_opp_notifier(struct notifier_block *nb,
> +				    unsigned long event, void *data)
> +{
> +	struct dev_pm_opp *opp = data;
> +	struct mtk_ccifreq_drv *drv;
> +	unsigned long freq, volt;
> +
> +	drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb);
> +
> +	if (event == OPP_EVENT_ADJUST_VOLTAGE) {
> +		freq = dev_pm_opp_get_freq(opp);
> +
> +		mutex_lock(&drv->reg_lock);
> +		/* current opp item is changed */
> +		if (freq == drv->pre_freq) {
> +			volt = dev_pm_opp_get_voltage(opp);
> +			mtk_ccifreq_set_voltage(drv, volt);
> +		}
> +		mutex_unlock(&drv->reg_lock);
> +	}
> +
> +	return 0;
> +}
> +
> +static struct devfreq_dev_profile mtk_ccifreq_profile = {
> +	.target = mtk_ccifreq_target,
> +};
> +
> +static int mtk_ccifreq_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct mtk_ccifreq_drv *drv;
> +	struct devfreq_passive_data *passive_data;
> +	struct dev_pm_opp *opp;
> +	unsigned long rate, opp_volt;
> +	int ret;
> +
> +	drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
> +	if (!drv)
> +		return -ENOMEM;
> +
> +	drv->dev = dev;
> +	drv->soc_data = (const struct mtk_ccifreq_platform_data *)
> +				of_device_get_match_data(&pdev->dev);
> +	mutex_init(&drv->reg_lock);
> +	platform_set_drvdata(pdev, drv);
> +
> +	drv->cci_clk = devm_clk_get(dev, "cci");
> +	if (IS_ERR(drv->cci_clk)) {
> +		ret = PTR_ERR(drv->cci_clk);
> +		return dev_err_probe(dev, ret,
> +				     "failed to get cci clk: %d\n",
> ret);
> +	}
> +
> +	drv->inter_clk = devm_clk_get(dev, "intermediate");
> +	if (IS_ERR(drv->inter_clk)) {
> +		ret = PTR_ERR(drv->inter_clk);
> +		dev_err_probe(dev, ret,
> +			      "failed to get intermediate clk: %d\n",
> ret);
> +		goto out_free_resources;
> +	}
> +
> +	drv->proc_reg = devm_regulator_get_optional(dev, "proc");
> +	if (IS_ERR(drv->proc_reg)) {
> +		ret = PTR_ERR(drv->proc_reg);
> +		dev_err_probe(dev, ret,
> +			      "failed to get proc regulator: %d\n",
> ret);
> +		goto out_free_resources;
> +	}
> +
> +	ret = regulator_enable(drv->proc_reg);
> +	if (ret) {
> +		dev_err(dev, "failed to enable proc regulator\n");
> +		goto out_free_resources;
> +	}
> +
> +	drv->sram_reg = regulator_get_optional(dev, "sram");
> +	if (IS_ERR(drv->sram_reg))
> +		drv->sram_reg = NULL;
> +	else {
> +		ret = regulator_enable(drv->sram_reg);
> +		if (ret) {
> +			dev_err(dev, "failed to enable sram
> regulator\n");
> +			goto out_free_resources;
> +		}
> +	}
> +
> +	/*
> +	 * We assume min voltage is 0 and tracking target voltage using
> +	 * min_volt_shift for each iteration.
> +	 * The retry_max is 3 times of expeted iteration count.
> +	 */
> +	drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data-
> >sram_max_volt,
> +					       drv->soc_data-
> >proc_max_volt),
> +					   drv->soc_data-
> >min_volt_shift);
> +
> +	ret = clk_prepare_enable(drv->cci_clk);
> +	if (ret)
> +		goto out_free_resources;
> +
> +	ret = clk_prepare_enable(drv->inter_clk);
> +	if (ret)
> +		goto out_disable_cci_clk;
> +
> +	ret = dev_pm_opp_of_add_table(dev);
> +	if (ret) {
> +		dev_err(dev, "failed to add opp table: %d\n", ret);
> +		goto out_disable_inter_clk;
> +	}
> +
> +	rate = clk_get_rate(drv->inter_clk);
> +	opp = dev_pm_opp_find_freq_ceil(dev, &rate);
> +	if (IS_ERR(opp)) {
> +		ret = PTR_ERR(opp);
> +		dev_err(dev, "failed to get intermediate opp: %d\n",
> ret);
> +		goto out_remove_opp_table;
> +	}
> +	drv->inter_voltage = dev_pm_opp_get_voltage(opp);
> +	dev_pm_opp_put(opp);
> +
> +	rate = U32_MAX;
> +	opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
> +	if (IS_ERR(opp)) {
> +		dev_err(dev, "failed to get opp\n");
> +		ret = PTR_ERR(opp);
> +		goto out_remove_opp_table;
> +	}
> +
> +	opp_volt = dev_pm_opp_get_voltage(opp);
> +	dev_pm_opp_put(opp);
> +	ret = mtk_ccifreq_set_voltage(drv, opp_volt);
> +	if (ret) {
> +		dev_err(dev, "failed to scale to highest voltage %lu in
> proc_reg\n",
> +			opp_volt);
> +		goto out_remove_opp_table;
> +	}
> +
> +	passive_data = devm_kzalloc(dev, sizeof(struct
> devfreq_passive_data),
> +				    GFP_KERNEL);
> +	if (!passive_data) {
> +		ret = -ENOMEM;
> +		goto out_remove_opp_table;
> +	}
> +
> +	passive_data->parent_type = CPUFREQ_PARENT_DEV;
> +	drv->devfreq = devm_devfreq_add_device(dev,
> &mtk_ccifreq_profile,
> +					       DEVFREQ_GOV_PASSIVE,
> +					       passive_data);
> +	if (IS_ERR(drv->devfreq)) {
> +		ret = -EPROBE_DEFER;
> +		dev_err(dev, "failed to add devfreq device: %d\n",
> +			PTR_ERR(drv->devfreq));
> +		goto out_remove_opp_table;
> +	}
> +
> +	drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
> +	ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
> +	if (ret) {
> +		dev_err(dev, "failed to register opp notifier: %d\n",
> ret);
> +		goto out_remove_devfreq_device;
> +	}
> +	return 0;
> +
> +out_remove_devfreq_device:
> +	devm_devfreq_remove_device(dev, drv->devfreq);
> +
> +out_remove_opp_table:
> +	dev_pm_opp_of_remove_table(dev);
> +
> +out_disable_inter_clk:
> +	clk_disable_unprepare(drv->inter_clk);
> +
> +out_disable_cci_clk:
> +	clk_disable_unprepare(drv->cci_clk);
> +
> +out_free_resources:
> +	if (regulator_is_enabled(drv->proc_reg))
> +		regulator_disable(drv->proc_reg);
> +	if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
> +		regulator_disable(drv->sram_reg);
> +
> +	if (!IS_ERR(drv->proc_reg))
> +		regulator_put(drv->proc_reg);
> +	if (!IS_ERR(drv->sram_reg))
> +		regulator_put(drv->sram_reg);
> +	if (!IS_ERR(drv->cci_clk))
> +		clk_put(drv->cci_clk);
> +	if (!IS_ERR(drv->inter_clk))
> +		clk_put(drv->inter_clk);
> +
> +	return ret;
> +}
> +
> +static int mtk_ccifreq_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct mtk_ccifreq_drv *drv;
> +
> +	drv = platform_get_drvdata(pdev);
> +
> +	dev_pm_opp_unregister_notifier(dev, &drv->opp_nb);
> +	dev_pm_opp_of_remove_table(dev);
> +	clk_disable_unprepare(drv->inter_clk);
> +	clk_disable_unprepare(drv->cci_clk);
> +	regulator_disable(drv->proc_reg);
> +	if (drv->sram_reg)
> +		regulator_disable(drv->sram_reg);
> +
> +	return 0;
> +}
> +
> +static const struct mtk_ccifreq_platform_data mt8183_platform_data =
> {
> +	.min_volt_shift = 100000,
> +	.max_volt_shift = 200000,
> +	.proc_max_volt = 1150000,
> +	.sram_min_volt = 0,
> +	.sram_max_volt = 1150000,
> +};
> +
> +static const struct mtk_ccifreq_platform_data mt8186_platform_data =
> {
> +	.min_volt_shift = 100000,
> +	.max_volt_shift = 250000,
> +	.proc_max_volt = 1118750,
> +	.sram_min_volt = 850000,
> +	.sram_max_volt = 1118750,
> +};
> +
> +static const struct of_device_id mtk_ccifreq_machines[] = {
> +	{ .compatible = "mediatek,mt8183-cci", .data =
> &mt8183_platform_data },
> +	{ .compatible = "mediatek,mt8186-cci", .data =
> &mt8186_platform_data },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines);
> +
> +static struct platform_driver mtk_ccifreq_platdrv = {
> +	.probe	= mtk_ccifreq_probe,
> +	.remove	= mtk_ccifreq_remove,
> +	.driver = {
> +		.name = "mtk-ccifreq",
> +		.of_match_table = mtk_ccifreq_machines,
> +	},
> +};
> +module_platform_driver(mtk_ccifreq_platdrv);
> +
> +MODULE_DESCRIPTION("MediaTek CCI devfreq driver");
> +MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>");
> +MODULE_LICENSE("GPL v2");

Hi Chanwoo,

Just a kindly ping.
Could you please give me some suggestion on this patch?
Thanks!

BRs,
Johnson Wang


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [kbuild-all] Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-04-28 11:39       ` [kbuild-all] " Chen, Rong A
@ 2022-05-06 12:03         ` Chen-Yu Tsai
  2022-05-09  2:53           ` Chanwoo Choi
  0 siblings, 1 reply; 27+ messages in thread
From: Chen-Yu Tsai @ 2022-05-06 12:03 UTC (permalink / raw)
  To: Chen, Rong A
  Cc: Johnson Wang, kernel test robot, cw00.choi, krzk+dt, robh+dt,
	kyungmin.park, llvm, kbuild-all, linux-pm, linux-kernel,
	devicetree, linux-arm-kernel, linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

On Thu, Apr 28, 2022 at 7:39 PM Chen, Rong A <rong.a.chen@intel.com> wrote:
> On 4/27/2022 6:11 PM, Johnson Wang wrote:
> > On Wed, 2022-04-27 at 17:25 +0800, kernel test robot wrote:
> >> Hi Johnson,
> >>
> >> Thank you for the patch! Perhaps something to improve:
> >>
> >> [auto build test WARNING on robh/for-next]
> >> [also build test WARNING on linus/master v5.18-rc4 next-20220427]
> >> [If your patch is applied to the wrong git tree, kindly drop us a
> >> note.
> >> And when submitting patch, we suggest to use '--base' as documented
> >> in
> >>
> > https://urldefense.com/v3/__https://git-scm.com/docs/git-format-patch__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMS_s9zEZ$
> >>   ]
> >>
> >> url:
> >> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux/commits/Johnson-Wang/Introduce-MediaTek-CCI-devfreq-driver/20220425-205820__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMc1U_tqz$
> >>
> >> base:
> >> https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMUzTprof$
> >>    for-next
> >> config: hexagon-allyesconfig (
> >> https://urldefense.com/v3/__https://download.01.org/0day-ci/archive/20220427/202204271737.oAuTwqZH-lkp@intel.com/config__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMaVRzbSL$
> >>   )
> >> compiler: clang version 15.0.0 (
> >> https://urldefense.com/v3/__https://github.com/llvm/llvm-project__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMRqw5IY-$
> >> $  1cddcfdc3c683b393df1a5c9063252eb60e52818)
> >> reproduce (this is a W=1 build):
> >>          wget
> >> https://urldefense.com/v3/__https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMQLiD-i9$
> >>    -O ~/bin/make.cross
> >>          chmod +x ~/bin/make.cross
> >>          #
> >> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux/commit/98b34c0587837b0e5b880b11a52433f8f0eee19f__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMU5yd7Y2$
> >>
> >>          git remote add linux-review
> >> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMW4ldtnH$
> >>
> >>          git fetch --no-tags linux-review Johnson-Wang/Introduce-
> >> MediaTek-CCI-devfreq-driver/20220425-205820
> >>          git checkout 98b34c0587837b0e5b880b11a52433f8f0eee19f
> >>          # save the config file
> >>          mkdir build_dir && cp config build_dir/.config
> >>          COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross
> >> W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash block/partitions/
> >> drivers/devfreq/ drivers/iio/imu/ drivers/misc/lkdtm/
> >>
> >> If you fix the issue, kindly add following tag as appropriate
> >> Reported-by: kernel test robot <lkp@intel.com>
> >>
> >> All warnings (new ones prefixed by >>):
> >>
> >>     drivers/devfreq/mtk-cci-devfreq.c:372:16: error: no member named
> >> 'parent_type' in 'struct devfreq_passive_data'
> >>             passive_data->parent_type = CPUFREQ_PARENT_DEV;
> >>             ~~~~~~~~~~~~  ^
> >>     drivers/devfreq/mtk-cci-devfreq.c:372:30: error: use of undeclared
> >> identifier 'CPUFREQ_PARENT_DEV'
> >>             passive_data->parent_type = CPUFREQ_PARENT_DEV;
> >>                                         ^
> >>>> drivers/devfreq/mtk-cci-devfreq.c:379:4: warning: format
> >>>> specifies type 'int' but the argument has type 'long' [-Wformat]
> >>
> >>                             PTR_ERR(drv->devfreq));
> >>                             ^~~~~~~~~~~~~~~~~~~~~
> >>     include/linux/dev_printk.h:144:65: note: expanded from macro
> >> 'dev_err'
> >>             dev_printk_index_wrap(_dev_err, KERN_ERR, dev,
> >> dev_fmt(fmt), ##__VA_ARGS__)
> >>                                                                    ~~~
> >>       ^~~~~~~~~~~
> >>     include/linux/dev_printk.h:110:23: note: expanded from macro
> >> 'dev_printk_index_wrap'
> >>                     _p_func(dev, fmt,
> >> ##__VA_ARGS__);                       \
> >>                                  ~~~    ^~~~~~~~~~~
> >>     1 warning and 2 errors generated.
> >>
> >>
> >> vim +379 drivers/devfreq/mtk-cci-devfreq.c
> >>
> >>     255
> >>     256      static int mtk_ccifreq_probe(struct platform_device
> >> *pdev)
> >>     257      {
> >>     258              struct device *dev = &pdev->dev;
> >>     259              struct mtk_ccifreq_drv *drv;
> >>     260              struct devfreq_passive_data *passive_data;
> >>     261              struct dev_pm_opp *opp;
> >>     262              unsigned long rate, opp_volt;
> >>     263              int ret;
> >>     264
> >>     265              drv = devm_kzalloc(dev, sizeof(*drv),
> >> GFP_KERNEL);
> >>     266              if (!drv)
> >>     267                      return -ENOMEM;
> >>     268
> >>     269              drv->dev = dev;
> >>     270              drv->soc_data = (const struct
> >> mtk_ccifreq_platform_data *)
> >>     271                                      of_device_get_match_dat
> >> a(&pdev->dev);
> >>     272              mutex_init(&drv->reg_lock);
> >>     273              platform_set_drvdata(pdev, drv);
> >>     274
> >>     275              drv->cci_clk = devm_clk_get(dev, "cci");
> >>     276              if (IS_ERR(drv->cci_clk)) {
> >>     277                      ret = PTR_ERR(drv->cci_clk);
> >>     278                      return dev_err_probe(dev, ret,
> >>     279                                           "failed to get cci
> >> clk: %d\n", ret);
> >>     280              }
> >>     281
> >>     282              drv->inter_clk = devm_clk_get(dev,
> >> "intermediate");
> >>     283              if (IS_ERR(drv->inter_clk)) {
> >>     284                      ret = PTR_ERR(drv->inter_clk);
> >>     285                      dev_err_probe(dev, ret,
> >>     286                                    "failed to get
> >> intermediate clk: %d\n", ret);
> >>     287                      goto out_free_resources;
> >>     288              }
> >>     289
> >>     290              drv->proc_reg =
> >> devm_regulator_get_optional(dev, "proc");
> >>     291              if (IS_ERR(drv->proc_reg)) {
> >>     292                      ret = PTR_ERR(drv->proc_reg);
> >>     293                      dev_err_probe(dev, ret,
> >>     294                                    "failed to get proc
> >> regulator: %d\n", ret);
> >>     295                      goto out_free_resources;
> >>     296              }
> >>     297
> >>     298              ret = regulator_enable(drv->proc_reg);
> >>     299              if (ret) {
> >>     300                      dev_err(dev, "failed to enable proc
> >> regulator\n");
> >>     301                      goto out_free_resources;
> >>     302              }
> >>     303
> >>     304              drv->sram_reg = regulator_get_optional(dev,
> >> "sram");
> >>     305              if (IS_ERR(drv->sram_reg))
> >>     306                      drv->sram_reg = NULL;
> >>     307              else {
> >>     308                      ret = regulator_enable(drv->sram_reg);
> >>     309                      if (ret) {
> >>     310                              dev_err(dev, "failed to enable
> >> sram regulator\n");
> >>     311                              goto out_free_resources;
> >>     312                      }
> >>     313              }
> >>     314
> >>     315              /*
> >>     316               * We assume min voltage is 0 and tracking
> >> target voltage using
> >>     317               * min_volt_shift for each iteration.
> >>     318               * The retry_max is 3 times of expeted
> >> iteration count.
> >>     319               */
> >>     320              drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv-
> >>> soc_data->sram_max_volt,
> >>     321                                                     drv-
> >>> soc_data->proc_max_volt),
> >>     322                                                 drv-
> >>> soc_data->min_volt_shift);
> >>     323
> >>     324              ret = clk_prepare_enable(drv->cci_clk);
> >>     325              if (ret)
> >>     326                      goto out_free_resources;
> >>     327
> >>     328              ret = clk_prepare_enable(drv->inter_clk);
> >>     329              if (ret)
> >>     330                      goto out_disable_cci_clk;
> >>     331
> >>     332              ret = dev_pm_opp_of_add_table(dev);
> >>     333              if (ret) {
> >>     334                      dev_err(dev, "failed to add opp table:
> >> %d\n", ret);
> >>     335                      goto out_disable_inter_clk;
> >>     336              }
> >>     337
> >>     338              rate = clk_get_rate(drv->inter_clk);
> >>     339              opp = dev_pm_opp_find_freq_ceil(dev, &rate);
> >>     340              if (IS_ERR(opp)) {
> >>     341                      ret = PTR_ERR(opp);
> >>     342                      dev_err(dev, "failed to get
> >> intermediate opp: %d\n", ret);
> >>     343                      goto out_remove_opp_table;
> >>     344              }
> >>     345              drv->inter_voltage =
> >> dev_pm_opp_get_voltage(opp);
> >>     346              dev_pm_opp_put(opp);
> >>     347
> >>     348              rate = U32_MAX;
> >>     349              opp = dev_pm_opp_find_freq_floor(drv->dev,
> >> &rate);
> >>     350              if (IS_ERR(opp)) {
> >>     351                      dev_err(dev, "failed to get opp\n");
> >>     352                      ret = PTR_ERR(opp);
> >>     353                      goto out_remove_opp_table;
> >>     354              }
> >>     355
> >>     356              opp_volt = dev_pm_opp_get_voltage(opp);
> >>     357              dev_pm_opp_put(opp);
> >>     358              ret = mtk_ccifreq_set_voltage(drv, opp_volt);
> >>     359              if (ret) {
> >>     360                      dev_err(dev, "failed to scale to
> >> highest voltage %lu in proc_reg\n",
> >>     361                              opp_volt);
> >>     362                      goto out_remove_opp_table;
> >>     363              }
> >>     364
> >>     365              passive_data = devm_kzalloc(dev, sizeof(struct
> >> devfreq_passive_data),
> >>     366                                          GFP_KERNEL);
> >>     367              if (!passive_data) {
> >>     368                      ret = -ENOMEM;
> >>     369                      goto out_remove_opp_table;
> >>     370              }
> >>     371
> >>     372              passive_data->parent_type = CPUFREQ_PARENT_DEV;
> >>     373              drv->devfreq = devm_devfreq_add_device(dev,
> >> &mtk_ccifreq_profile,
> >>     374                                                     DEVFREQ_
> >> GOV_PASSIVE,
> >>     375                                                     passive_
> >> data);
> >>     376              if (IS_ERR(drv->devfreq)) {
> >>     377                      ret = -EPROBE_DEFER;
> >>     378                      dev_err(dev, "failed to add devfreq
> >> device: %d\n",
> >>   > 379                              PTR_ERR(drv->devfreq));
> >>     380                      goto out_remove_opp_table;
> >>     381              }
> >>     382
> >>     383              drv->opp_nb.notifier_call =
> >> mtk_ccifreq_opp_notifier;
> >>     384              ret = dev_pm_opp_register_notifier(dev, &drv-
> >>> opp_nb);
> >>     385              if (ret) {
> >>     386                      dev_err(dev, "failed to register opp
> >> notifier: %d\n", ret);
> >>     387                      goto out_remove_devfreq_device;
> >>     388              }
> >>     389              return 0;
> >>     390
> >>     391      out_remove_devfreq_device:
> >>     392              devm_devfreq_remove_device(dev, drv->devfreq);
> >>     393
> >>     394      out_remove_opp_table:
> >>     395              dev_pm_opp_of_remove_table(dev);
> >>     396
> >>     397      out_disable_inter_clk:
> >>     398              clk_disable_unprepare(drv->inter_clk);
> >>     399
> >>     400      out_disable_cci_clk:
> >>     401              clk_disable_unprepare(drv->cci_clk);
> >>     402
> >>     403      out_free_resources:
> >>     404              if (regulator_is_enabled(drv->proc_reg))
> >>     405                      regulator_disable(drv->proc_reg);
> >>     406              if (drv->sram_reg && regulator_is_enabled(drv-
> >>> sram_reg))
> >>     407                      regulator_disable(drv->sram_reg);
> >>     408
> >>     409              if (!IS_ERR(drv->proc_reg))
> >>     410                      regulator_put(drv->proc_reg);
> >>     411              if (!IS_ERR(drv->sram_reg))
> >>     412                      regulator_put(drv->sram_reg);
> >>     413              if (!IS_ERR(drv->cci_clk))
> >>     414                      clk_put(drv->cci_clk);
> >>     415              if (!IS_ERR(drv->inter_clk))
> >>     416                      clk_put(drv->inter_clk);
> >>     417
> >>     418              return ret;
> >>     419      }
> >>     420
> >>
> >
> > Hi "kernel test robot",
> >
> > Thanks for your review.
> >
> > This patch is based on chanwoo/devfreq-testing[1]
> > [1]
> > https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing
>
> Hi Johnson,
>
> Thanks for the feedback, we'll take a look too.

I think the last patch on that branch might be broken.


ChenYu

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-04-25 12:55 ` [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver Johnson Wang
                     ` (3 preceding siblings ...)
  2022-05-06 11:38   ` Johnson Wang
@ 2022-05-06 18:57   ` Chanwoo Choi
  4 siblings, 0 replies; 27+ messages in thread
From: Chanwoo Choi @ 2022-05-06 18:57 UTC (permalink / raw)
  To: Johnson Wang, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

Hi Johnson,


On 22. 4. 25. 21:55, Johnson Wang wrote:
> We introduce a devfreq driver for the MediaTek Cache Coherent Interconnect
> (CCI) used by some MediaTek SoCs.
> 
> In this driver, we use the passive devfreq driver to get target frequencies
> and adjust voltages accordingly. In MT8183 and MT8186, the MediaTek CCI
> is supplied by the same regulators with the little core CPUs.
> 
> Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> ---
> This patch depends on "devfreq-testing"[1].
> [1]https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing
> ---
>   drivers/devfreq/Kconfig           |  10 +
>   drivers/devfreq/Makefile          |   1 +
>   drivers/devfreq/mtk-cci-devfreq.c | 474 ++++++++++++++++++++++++++++++
>   3 files changed, 485 insertions(+)
>   create mode 100644 drivers/devfreq/mtk-cci-devfreq.c
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>

I updated the passive governor on devfreq-testing[1] branch
[1] 
https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing

Could you please test your patches based on devfreq-testing[1] branch?


-- 
Best Regards,
Samsung Electronics
Chanwoo Choi

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-05-06 11:38   ` Johnson Wang
@ 2022-05-07 13:53     ` Chanwoo Choi
  2022-05-09  5:57       ` Johnson Wang
  0 siblings, 1 reply; 27+ messages in thread
From: Chanwoo Choi @ 2022-05-07 13:53 UTC (permalink / raw)
  To: Johnson Wang, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

On 22. 5. 6. 20:38, Johnson Wang wrote:
> On Mon, 2022-04-25 at 20:55 +0800, Johnson Wang wrote:
>> We introduce a devfreq driver for the MediaTek Cache Coherent
>> Interconnect
>> (CCI) used by some MediaTek SoCs.
>>
>> In this driver, we use the passive devfreq driver to get target
>> frequencies
>> and adjust voltages accordingly. In MT8183 and MT8186, the MediaTek
>> CCI
>> is supplied by the same regulators with the little core CPUs.
>>
>> Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
>> Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
>> ---
>> This patch depends on "devfreq-testing"[1].
>> [1]
>> https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing
>> ---
>>   drivers/devfreq/Kconfig           |  10 +
>>   drivers/devfreq/Makefile          |   1 +
>>   drivers/devfreq/mtk-cci-devfreq.c | 474
>> ++++++++++++++++++++++++++++++
>>   3 files changed, 485 insertions(+)
>>   create mode 100644 drivers/devfreq/mtk-cci-devfreq.c
>>
>> diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
>> index 87eb2b837e68..9754d8b31621 100644
>> --- a/drivers/devfreq/Kconfig
>> +++ b/drivers/devfreq/Kconfig
>> @@ -120,6 +120,16 @@ config ARM_TEGRA_DEVFREQ
>>   	  It reads ACTMON counters of memory controllers and adjusts
>> the
>>   	  operating frequencies and voltages with OPP support.
>>   
>> +config ARM_MEDIATEK_CCI_DEVFREQ
>> +	tristate "MEDIATEK CCI DEVFREQ Driver"
>> +	depends on ARM_MEDIATEK_CPUFREQ || COMPILE_TEST
>> +	select DEVFREQ_GOV_PASSIVE
>> +	help
>> +	  This adds a devfreq driver for MediaTek Cache Coherent
>> Interconnect
>> +	  which is shared the same regulators with the cpu cluster. It
>> can track
>> +	  buck voltages and update a proper CCI frequency. Use the
>> notification
>> +	  to get the regulator status.
>> +
>>   config ARM_RK3399_DMC_DEVFREQ
>>   	tristate "ARM RK3399 DMC DEVFREQ Driver"
>>   	depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
>> diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
>> index 0b6be92a25d9..bf40d04928d0 100644
>> --- a/drivers/devfreq/Makefile
>> +++ b/drivers/devfreq/Makefile
>> @@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+=
>> governor_passive.o
>>   obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
>>   obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o
>>   obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
>> +obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ)	+= mtk-cci-devfreq.o
>>   obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
>>   obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ)	+= sun8i-a33-mbus.o
>>   obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-devfreq.o
>> diff --git a/drivers/devfreq/mtk-cci-devfreq.c b/drivers/devfreq/mtk-
>> cci-devfreq.c
>> new file mode 100644
>> index 000000000000..b3e31c45a57c
>> --- /dev/null
>> +++ b/drivers/devfreq/mtk-cci-devfreq.c
>> @@ -0,0 +1,474 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (C) 2022 MediaTek Inc.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/devfreq.h>
>> +#include <linux/minmax.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_opp.h>
>> +#include <linux/regulator/consumer.h>
>> +
>> +struct mtk_ccifreq_platform_data {
>> +	int min_volt_shift;
>> +	int max_volt_shift;
>> +	int proc_max_volt;
>> +	int sram_min_volt;
>> +	int sram_max_volt;
>> +};
>> +
>> +struct mtk_ccifreq_drv {
>> +	struct device *dev;
>> +	struct devfreq *devfreq;
>> +	struct regulator *proc_reg;
>> +	struct regulator *sram_reg;
>> +	struct clk *cci_clk;
>> +	struct clk *inter_clk;
>> +	int inter_voltage;
>> +	int pre_voltage;
>> +	unsigned long pre_freq;
>> +	/* Avoid race condition for regulators between notify and
>> policy */
>> +	struct mutex reg_lock;
>> +	struct notifier_block opp_nb;
>> +	const struct mtk_ccifreq_platform_data *soc_data;
>> +	int vtrack_max;
>> +};
>> +
>> +static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv, int
>> new_voltage)
>> +{
>> +	const struct mtk_ccifreq_platform_data *soc_data = drv-
>>> soc_data;
>> +	struct device *dev = drv->dev;
>> +	int pre_voltage, pre_vsram, new_vsram, vsram, voltage, ret;
>> +	int retry_max = drv->vtrack_max;
>> +
>> +	if (!drv->sram_reg) {
>> +		ret = regulator_set_voltage(drv->proc_reg, new_voltage,
>> +					    drv->soc_data-
>>> proc_max_volt);
>> +		goto out_set_voltage;
>> +	}
>> +
>> +	pre_voltage = regulator_get_voltage(drv->proc_reg);
>> +	if (pre_voltage < 0) {
>> +		dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
>> +		return pre_voltage;
>> +	}
>> +
>> +	pre_vsram = regulator_get_voltage(drv->sram_reg);
>> +	if (pre_vsram < 0) {
>> +		dev_err(dev, "invalid vsram value: %d\n", pre_vsram);
>> +		return pre_vsram;
>> +	}
>> +
>> +	new_vsram = clamp(new_voltage + soc_data->min_volt_shift,
>> +			  soc_data->sram_min_volt, soc_data-
>>> sram_max_volt);
>> +
>> +	do {
>> +		if (pre_voltage <= new_voltage) {
>> +			vsram = clamp(pre_voltage + soc_data-
>>> max_volt_shift,
>> +				      soc_data->sram_min_volt,
>> new_vsram);
>> +			ret = regulator_set_voltage(drv->sram_reg,
>> vsram,
>> +						    soc_data-
>>> sram_max_volt);
>> +			if (ret)
>> +				return ret;
>> +
>> +			if (vsram == soc_data->sram_max_volt ||
>> +			    new_vsram == soc_data->sram_min_volt)
>> +				voltage = new_voltage;
>> +			else
>> +				voltage = vsram - soc_data-
>>> min_volt_shift;
>> +
>> +			ret = regulator_set_voltage(drv->proc_reg,
>> voltage,
>> +						    soc_data-
>>> proc_max_volt);
>> +			if (ret) {
>> +				regulator_set_voltage(drv->sram_reg,
>> pre_vsram,
>> +						      soc_data-
>>> sram_max_volt);
>> +				return ret;
>> +			}
>> +		} else if (pre_voltage > new_voltage) {
>> +			voltage = max(new_voltage,
>> +				      pre_vsram - soc_data-
>>> max_volt_shift);
>> +			ret = regulator_set_voltage(drv->proc_reg,
>> voltage,
>> +						    soc_data-
>>> proc_max_volt);
>> +			if (ret)
>> +				return ret;
>> +
>> +			if (voltage == new_voltage)
>> +				vsram = new_vsram;
>> +			else
>> +				vsram = max(new_vsram,
>> +					    voltage + soc_data-
>>> min_volt_shift);
>> +
>> +			ret = regulator_set_voltage(drv->sram_reg,
>> vsram,
>> +						    soc_data-
>>> sram_max_volt);
>> +			if (ret) {
>> +				regulator_set_voltage(drv->proc_reg,
>> pre_voltage,
>> +						      soc_data-
>>> proc_max_volt);
>> +				return ret;
>> +			}
>> +		}
>> +
>> +		pre_voltage = voltage;
>> +		pre_vsram = vsram;
>> +
>> +		if (--retry_max < 0) {
>> +			dev_err(dev,
>> +				"over loop count, failed to set
>> voltage\n");
>> +			return -EINVAL;
>> +		}
>> +	} while (voltage != new_voltage || vsram != new_vsram);
>> +
>> +out_set_voltage:
>> +	if (!ret)
>> +		drv->pre_voltage = new_voltage;
>> +
>> +	return ret;
>> +}
>> +
>> +static int mtk_ccifreq_target(struct device *dev, unsigned long
>> *freq,
>> +			      u32 flags)
>> +{
>> +	struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev);
>> +	struct clk *cci_pll = clk_get_parent(drv->cci_clk);
>> +	struct dev_pm_opp *opp;
>> +	unsigned long opp_rate;
>> +	int voltage, pre_voltage, inter_voltage, target_voltage, ret;
>> +
>> +	if (!drv)
>> +		return -EINVAL;
>> +
>> +	if (drv->pre_freq == *freq)
>> +		return 0;
>> +
>> +	inter_voltage = drv->inter_voltage;
>> +
>> +	opp_rate = *freq;
>> +	opp = devfreq_recommended_opp(dev, &opp_rate, 1);
>> +	if (IS_ERR(opp)) {
>> +		dev_err(dev, "failed to find opp for freq: %ld\n",
>> opp_rate);
>> +		return PTR_ERR(opp);
>> +	}
>> +
>> +	mutex_lock(&drv->reg_lock);
>> +
>> +	voltage = dev_pm_opp_get_voltage(opp);
>> +	dev_pm_opp_put(opp);
>> +
>> +	if (unlikely(drv->pre_voltage <= 0))
>> +		pre_voltage = regulator_get_voltage(drv->proc_reg);
>> +	else
>> +		pre_voltage = drv->pre_voltage;
>> +
>> +	if (pre_voltage < 0) {
>> +		dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
>> +		return pre_voltage;
>> +	}
>> +
>> +	/* scale up: set voltage first then freq. */
>> +	target_voltage = max(inter_voltage, voltage);
>> +	if (pre_voltage <= target_voltage) {
>> +		ret = mtk_ccifreq_set_voltage(drv, target_voltage);
>> +		if (ret) {
>> +			dev_err(dev, "failed to scale up voltage\n");
>> +			goto out_restore_voltage;
>> +		}
>> +	}
>> +
>> +	/* switch the cci clock to intermediate clock source. */
>> +	ret = clk_set_parent(drv->cci_clk, drv->inter_clk);
>> +	if (ret) {
>> +		dev_err(dev, "failed to re-parent cci clock\n");
>> +		goto out_restore_voltage;
>> +	}
>> +
>> +	/* set the original clock to target rate. */
>> +	ret = clk_set_rate(cci_pll, *freq);
>> +	if (ret) {
>> +		dev_err(dev, "failed to set cci pll rate: %d\n", ret);
>> +		clk_set_parent(drv->cci_clk, cci_pll);
>> +		goto out_restore_voltage;
>> +	}
>> +
>> +	/* switch the cci clock back to the original clock source. */
>> +	ret = clk_set_parent(drv->cci_clk, cci_pll);
>> +	if (ret) {
>> +		dev_err(dev, "failed to re-parent cci clock\n");
>> +		mtk_ccifreq_set_voltage(drv, inter_voltage);
>> +		goto out_unlock;
>> +	}
>> +
>> +	/*
>> +	 * If the new voltage is lower than the intermediate voltage or
>> the
>> +	 * original voltage, scale down to the new voltage.
>> +	 */
>> +	if (voltage < inter_voltage || voltage < pre_voltage) {
>> +		ret = mtk_ccifreq_set_voltage(drv, voltage);
>> +		if (ret) {
>> +			dev_err(dev, "failed to scale down voltage\n");
>> +			goto out_unlock;
>> +		}
>> +	}
>> +
>> +	drv->pre_freq = *freq;
>> +	mutex_unlock(&drv->reg_lock);
>> +
>> +	return 0;
>> +
>> +out_restore_voltage:
>> +	mtk_ccifreq_set_voltage(drv, pre_voltage);
>> +
>> +out_unlock:
>> +	mutex_unlock(&drv->reg_lock);
>> +	return ret;
>> +}
>> +
>> +static int mtk_ccifreq_opp_notifier(struct notifier_block *nb,
>> +				    unsigned long event, void *data)
>> +{
>> +	struct dev_pm_opp *opp = data;
>> +	struct mtk_ccifreq_drv *drv;
>> +	unsigned long freq, volt;
>> +
>> +	drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb);
>> +
>> +	if (event == OPP_EVENT_ADJUST_VOLTAGE) {
>> +		freq = dev_pm_opp_get_freq(opp);
>> +
>> +		mutex_lock(&drv->reg_lock);
>> +		/* current opp item is changed */
>> +		if (freq == drv->pre_freq) {
>> +			volt = dev_pm_opp_get_voltage(opp);
>> +			mtk_ccifreq_set_voltage(drv, volt);
>> +		}
>> +		mutex_unlock(&drv->reg_lock);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static struct devfreq_dev_profile mtk_ccifreq_profile = {
>> +	.target = mtk_ccifreq_target,
>> +};
>> +
>> +static int mtk_ccifreq_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct mtk_ccifreq_drv *drv;
>> +	struct devfreq_passive_data *passive_data;
>> +	struct dev_pm_opp *opp;
>> +	unsigned long rate, opp_volt;
>> +	int ret;
>> +
>> +	drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
>> +	if (!drv)
>> +		return -ENOMEM;
>> +
>> +	drv->dev = dev;
>> +	drv->soc_data = (const struct mtk_ccifreq_platform_data *)
>> +				of_device_get_match_data(&pdev->dev);
>> +	mutex_init(&drv->reg_lock);
>> +	platform_set_drvdata(pdev, drv);
>> +
>> +	drv->cci_clk = devm_clk_get(dev, "cci");
>> +	if (IS_ERR(drv->cci_clk)) {
>> +		ret = PTR_ERR(drv->cci_clk);
>> +		return dev_err_probe(dev, ret,
>> +				     "failed to get cci clk: %d\n",
>> ret);
>> +	}
>> +
>> +	drv->inter_clk = devm_clk_get(dev, "intermediate");
>> +	if (IS_ERR(drv->inter_clk)) {
>> +		ret = PTR_ERR(drv->inter_clk);
>> +		dev_err_probe(dev, ret,
>> +			      "failed to get intermediate clk: %d\n",
>> ret);
>> +		goto out_free_resources;
>> +	}
>> +
>> +	drv->proc_reg = devm_regulator_get_optional(dev, "proc");
>> +	if (IS_ERR(drv->proc_reg)) {
>> +		ret = PTR_ERR(drv->proc_reg);
>> +		dev_err_probe(dev, ret,
>> +			      "failed to get proc regulator: %d\n",
>> ret);
>> +		goto out_free_resources;
>> +	}
>> +
>> +	ret = regulator_enable(drv->proc_reg);
>> +	if (ret) {
>> +		dev_err(dev, "failed to enable proc regulator\n");
>> +		goto out_free_resources;
>> +	}
>> +
>> +	drv->sram_reg = regulator_get_optional(dev, "sram");
>> +	if (IS_ERR(drv->sram_reg))
>> +		drv->sram_reg = NULL;
>> +	else {
>> +		ret = regulator_enable(drv->sram_reg);
>> +		if (ret) {
>> +			dev_err(dev, "failed to enable sram
>> regulator\n");
>> +			goto out_free_resources;
>> +		}
>> +	}
>> +
>> +	/*
>> +	 * We assume min voltage is 0 and tracking target voltage using
>> +	 * min_volt_shift for each iteration.
>> +	 * The retry_max is 3 times of expeted iteration count.
>> +	 */
>> +	drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data-
>>> sram_max_volt,
>> +					       drv->soc_data-
>>> proc_max_volt),
>> +					   drv->soc_data-
>>> min_volt_shift);
>> +
>> +	ret = clk_prepare_enable(drv->cci_clk);
>> +	if (ret)
>> +		goto out_free_resources;
>> +
>> +	ret = clk_prepare_enable(drv->inter_clk);
>> +	if (ret)
>> +		goto out_disable_cci_clk;
>> +
>> +	ret = dev_pm_opp_of_add_table(dev);
>> +	if (ret) {
>> +		dev_err(dev, "failed to add opp table: %d\n", ret);
>> +		goto out_disable_inter_clk;
>> +	}
>> +
>> +	rate = clk_get_rate(drv->inter_clk);
>> +	opp = dev_pm_opp_find_freq_ceil(dev, &rate);
>> +	if (IS_ERR(opp)) {
>> +		ret = PTR_ERR(opp);
>> +		dev_err(dev, "failed to get intermediate opp: %d\n",
>> ret);
>> +		goto out_remove_opp_table;
>> +	}
>> +	drv->inter_voltage = dev_pm_opp_get_voltage(opp);
>> +	dev_pm_opp_put(opp);
>> +
>> +	rate = U32_MAX;
>> +	opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
>> +	if (IS_ERR(opp)) {
>> +		dev_err(dev, "failed to get opp\n");
>> +		ret = PTR_ERR(opp);
>> +		goto out_remove_opp_table;
>> +	}
>> +
>> +	opp_volt = dev_pm_opp_get_voltage(opp);
>> +	dev_pm_opp_put(opp);
>> +	ret = mtk_ccifreq_set_voltage(drv, opp_volt);
>> +	if (ret) {
>> +		dev_err(dev, "failed to scale to highest voltage %lu in
>> proc_reg\n",
>> +			opp_volt);
>> +		goto out_remove_opp_table;
>> +	}
>> +
>> +	passive_data = devm_kzalloc(dev, sizeof(struct
>> devfreq_passive_data),
>> +				    GFP_KERNEL);
>> +	if (!passive_data) {
>> +		ret = -ENOMEM;
>> +		goto out_remove_opp_table;
>> +	}
>> +
>> +	passive_data->parent_type = CPUFREQ_PARENT_DEV;
>> +	drv->devfreq = devm_devfreq_add_device(dev,
>> &mtk_ccifreq_profile,
>> +					       DEVFREQ_GOV_PASSIVE,
>> +					       passive_data);
>> +	if (IS_ERR(drv->devfreq)) {
>> +		ret = -EPROBE_DEFER;
>> +		dev_err(dev, "failed to add devfreq device: %d\n",
>> +			PTR_ERR(drv->devfreq));
>> +		goto out_remove_opp_table;
>> +	}
>> +
>> +	drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
>> +	ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
>> +	if (ret) {
>> +		dev_err(dev, "failed to register opp notifier: %d\n",
>> ret);
>> +		goto out_remove_devfreq_device;
>> +	}
>> +	return 0;
>> +
>> +out_remove_devfreq_device:
>> +	devm_devfreq_remove_device(dev, drv->devfreq);
>> +
>> +out_remove_opp_table:
>> +	dev_pm_opp_of_remove_table(dev);
>> +
>> +out_disable_inter_clk:
>> +	clk_disable_unprepare(drv->inter_clk);
>> +
>> +out_disable_cci_clk:
>> +	clk_disable_unprepare(drv->cci_clk);
>> +
>> +out_free_resources:
>> +	if (regulator_is_enabled(drv->proc_reg))
>> +		regulator_disable(drv->proc_reg);
>> +	if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
>> +		regulator_disable(drv->sram_reg);
>> +
>> +	if (!IS_ERR(drv->proc_reg))
>> +		regulator_put(drv->proc_reg);
>> +	if (!IS_ERR(drv->sram_reg))
>> +		regulator_put(drv->sram_reg);
>> +	if (!IS_ERR(drv->cci_clk))
>> +		clk_put(drv->cci_clk);
>> +	if (!IS_ERR(drv->inter_clk))
>> +		clk_put(drv->inter_clk);
>> +
>> +	return ret;
>> +}
>> +
>> +static int mtk_ccifreq_remove(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct mtk_ccifreq_drv *drv;
>> +
>> +	drv = platform_get_drvdata(pdev);
>> +
>> +	dev_pm_opp_unregister_notifier(dev, &drv->opp_nb);
>> +	dev_pm_opp_of_remove_table(dev);
>> +	clk_disable_unprepare(drv->inter_clk);
>> +	clk_disable_unprepare(drv->cci_clk);
>> +	regulator_disable(drv->proc_reg);
>> +	if (drv->sram_reg)
>> +		regulator_disable(drv->sram_reg);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct mtk_ccifreq_platform_data mt8183_platform_data =
>> {
>> +	.min_volt_shift = 100000,
>> +	.max_volt_shift = 200000,
>> +	.proc_max_volt = 1150000,
>> +	.sram_min_volt = 0,
>> +	.sram_max_volt = 1150000,
>> +};
>> +
>> +static const struct mtk_ccifreq_platform_data mt8186_platform_data =
>> {
>> +	.min_volt_shift = 100000,
>> +	.max_volt_shift = 250000,
>> +	.proc_max_volt = 1118750,
>> +	.sram_min_volt = 850000,
>> +	.sram_max_volt = 1118750,
>> +};
>> +
>> +static const struct of_device_id mtk_ccifreq_machines[] = {
>> +	{ .compatible = "mediatek,mt8183-cci", .data =
>> &mt8183_platform_data },
>> +	{ .compatible = "mediatek,mt8186-cci", .data =
>> &mt8186_platform_data },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines);
>> +
>> +static struct platform_driver mtk_ccifreq_platdrv = {
>> +	.probe	= mtk_ccifreq_probe,
>> +	.remove	= mtk_ccifreq_remove,
>> +	.driver = {
>> +		.name = "mtk-ccifreq",
>> +		.of_match_table = mtk_ccifreq_machines,
>> +	},
>> +};
>> +module_platform_driver(mtk_ccifreq_platdrv);
>> +
>> +MODULE_DESCRIPTION("MediaTek CCI devfreq driver");
>> +MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>");
>> +MODULE_LICENSE("GPL v2");
> 
> Hi Chanwoo,
> 
> Just a kindly ping.
> Could you please give me some suggestion on this patch?
> Thanks!
> 
> BRs,
> Johnson Wang
> 

Hi Johnson,

Sorry for late reply.But I replied it yesterday as following:
Maybe, this reply[1] has not yet arrrived at your mail box.
[1] 
https://lore.kernel.org/lkml/0846a062-2ea2-e6d4-03c8-992c2f2e24a0@gmail.com/T/#m3bc609d805d6e74ec7a105be0511926b4afbbaef

As I described on reply[1], I updated the patches on devfreq-testing
branch. Could you please test your patches based on devfreq-testing
branch?

-- 
Best Regards,
Samsung Electronics
Chanwoo Choi

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [kbuild-all] Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-05-06 12:03         ` Chen-Yu Tsai
@ 2022-05-09  2:53           ` Chanwoo Choi
  0 siblings, 0 replies; 27+ messages in thread
From: Chanwoo Choi @ 2022-05-09  2:53 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Chen, Rong A, Johnson Wang, kernel test robot, Chanwoo Choi,
	krzk+dt, Rob Herring, Kyungmin Park, llvm, kbuild-all,
	Linux PM list, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

Hi Chen-Yu,

On Mon, May 9, 2022 at 10:53 AM Chen-Yu Tsai <wenst@chromium.org> wrote:
>
> On Thu, Apr 28, 2022 at 7:39 PM Chen, Rong A <rong.a.chen@intel.com> wrote:
> > On 4/27/2022 6:11 PM, Johnson Wang wrote:
> > > On Wed, 2022-04-27 at 17:25 +0800, kernel test robot wrote:
> > >> Hi Johnson,
> > >>
> > >> Thank you for the patch! Perhaps something to improve:
> > >>
> > >> [auto build test WARNING on robh/for-next]
> > >> [also build test WARNING on linus/master v5.18-rc4 next-20220427]
> > >> [If your patch is applied to the wrong git tree, kindly drop us a
> > >> note.
> > >> And when submitting patch, we suggest to use '--base' as documented
> > >> in
> > >>
> > > https://urldefense.com/v3/__https://git-scm.com/docs/git-format-patch__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMS_s9zEZ$
> > >>   ]
> > >>
> > >> url:
> > >> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux/commits/Johnson-Wang/Introduce-MediaTek-CCI-devfreq-driver/20220425-205820__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMc1U_tqz$
> > >>
> > >> base:
> > >> https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMUzTprof$
> > >>    for-next
> > >> config: hexagon-allyesconfig (
> > >> https://urldefense.com/v3/__https://download.01.org/0day-ci/archive/20220427/202204271737.oAuTwqZH-lkp@intel.com/config__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMaVRzbSL$
> > >>   )
> > >> compiler: clang version 15.0.0 (
> > >> https://urldefense.com/v3/__https://github.com/llvm/llvm-project__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMRqw5IY-$
> > >> $  1cddcfdc3c683b393df1a5c9063252eb60e52818)
> > >> reproduce (this is a W=1 build):
> > >>          wget
> > >> https://urldefense.com/v3/__https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMQLiD-i9$
> > >>    -O ~/bin/make.cross
> > >>          chmod +x ~/bin/make.cross
> > >>          #
> > >> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux/commit/98b34c0587837b0e5b880b11a52433f8f0eee19f__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMU5yd7Y2$
> > >>
> > >>          git remote add linux-review
> > >> https://urldefense.com/v3/__https://github.com/intel-lab-lkp/linux__;!!CTRNKA9wMg0ARbw!wdyoWXNLBcYM97vMuNFQXZ9BaajEp-Kmh5-xrvU2Rlmb0o-b9tRvCD0cPzbLMW4ldtnH$
> > >>
> > >>          git fetch --no-tags linux-review Johnson-Wang/Introduce-
> > >> MediaTek-CCI-devfreq-driver/20220425-205820
> > >>          git checkout 98b34c0587837b0e5b880b11a52433f8f0eee19f
> > >>          # save the config file
> > >>          mkdir build_dir && cp config build_dir/.config
> > >>          COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross
> > >> W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash block/partitions/
> > >> drivers/devfreq/ drivers/iio/imu/ drivers/misc/lkdtm/
> > >>
> > >> If you fix the issue, kindly add following tag as appropriate
> > >> Reported-by: kernel test robot <lkp@intel.com>
> > >>
> > >> All warnings (new ones prefixed by >>):
> > >>
> > >>     drivers/devfreq/mtk-cci-devfreq.c:372:16: error: no member named
> > >> 'parent_type' in 'struct devfreq_passive_data'
> > >>             passive_data->parent_type = CPUFREQ_PARENT_DEV;
> > >>             ~~~~~~~~~~~~  ^
> > >>     drivers/devfreq/mtk-cci-devfreq.c:372:30: error: use of undeclared
> > >> identifier 'CPUFREQ_PARENT_DEV'
> > >>             passive_data->parent_type = CPUFREQ_PARENT_DEV;
> > >>                                         ^
> > >>>> drivers/devfreq/mtk-cci-devfreq.c:379:4: warning: format
> > >>>> specifies type 'int' but the argument has type 'long' [-Wformat]
> > >>
> > >>                             PTR_ERR(drv->devfreq));
> > >>                             ^~~~~~~~~~~~~~~~~~~~~
> > >>     include/linux/dev_printk.h:144:65: note: expanded from macro
> > >> 'dev_err'
> > >>             dev_printk_index_wrap(_dev_err, KERN_ERR, dev,
> > >> dev_fmt(fmt), ##__VA_ARGS__)
> > >>                                                                    ~~~
> > >>       ^~~~~~~~~~~
> > >>     include/linux/dev_printk.h:110:23: note: expanded from macro
> > >> 'dev_printk_index_wrap'
> > >>                     _p_func(dev, fmt,
> > >> ##__VA_ARGS__);                       \
> > >>                                  ~~~    ^~~~~~~~~~~
> > >>     1 warning and 2 errors generated.
> > >>
> > >>
> > >> vim +379 drivers/devfreq/mtk-cci-devfreq.c
> > >>
> > >>     255
> > >>     256      static int mtk_ccifreq_probe(struct platform_device
> > >> *pdev)
> > >>     257      {
> > >>     258              struct device *dev = &pdev->dev;
> > >>     259              struct mtk_ccifreq_drv *drv;
> > >>     260              struct devfreq_passive_data *passive_data;
> > >>     261              struct dev_pm_opp *opp;
> > >>     262              unsigned long rate, opp_volt;
> > >>     263              int ret;
> > >>     264
> > >>     265              drv = devm_kzalloc(dev, sizeof(*drv),
> > >> GFP_KERNEL);
> > >>     266              if (!drv)
> > >>     267                      return -ENOMEM;
> > >>     268
> > >>     269              drv->dev = dev;
> > >>     270              drv->soc_data = (const struct
> > >> mtk_ccifreq_platform_data *)
> > >>     271                                      of_device_get_match_dat
> > >> a(&pdev->dev);
> > >>     272              mutex_init(&drv->reg_lock);
> > >>     273              platform_set_drvdata(pdev, drv);
> > >>     274
> > >>     275              drv->cci_clk = devm_clk_get(dev, "cci");
> > >>     276              if (IS_ERR(drv->cci_clk)) {
> > >>     277                      ret = PTR_ERR(drv->cci_clk);
> > >>     278                      return dev_err_probe(dev, ret,
> > >>     279                                           "failed to get cci
> > >> clk: %d\n", ret);
> > >>     280              }
> > >>     281
> > >>     282              drv->inter_clk = devm_clk_get(dev,
> > >> "intermediate");
> > >>     283              if (IS_ERR(drv->inter_clk)) {
> > >>     284                      ret = PTR_ERR(drv->inter_clk);
> > >>     285                      dev_err_probe(dev, ret,
> > >>     286                                    "failed to get
> > >> intermediate clk: %d\n", ret);
> > >>     287                      goto out_free_resources;
> > >>     288              }
> > >>     289
> > >>     290              drv->proc_reg =
> > >> devm_regulator_get_optional(dev, "proc");
> > >>     291              if (IS_ERR(drv->proc_reg)) {
> > >>     292                      ret = PTR_ERR(drv->proc_reg);
> > >>     293                      dev_err_probe(dev, ret,
> > >>     294                                    "failed to get proc
> > >> regulator: %d\n", ret);
> > >>     295                      goto out_free_resources;
> > >>     296              }
> > >>     297
> > >>     298              ret = regulator_enable(drv->proc_reg);
> > >>     299              if (ret) {
> > >>     300                      dev_err(dev, "failed to enable proc
> > >> regulator\n");
> > >>     301                      goto out_free_resources;
> > >>     302              }
> > >>     303
> > >>     304              drv->sram_reg = regulator_get_optional(dev,
> > >> "sram");
> > >>     305              if (IS_ERR(drv->sram_reg))
> > >>     306                      drv->sram_reg = NULL;
> > >>     307              else {
> > >>     308                      ret = regulator_enable(drv->sram_reg);
> > >>     309                      if (ret) {
> > >>     310                              dev_err(dev, "failed to enable
> > >> sram regulator\n");
> > >>     311                              goto out_free_resources;
> > >>     312                      }
> > >>     313              }
> > >>     314
> > >>     315              /*
> > >>     316               * We assume min voltage is 0 and tracking
> > >> target voltage using
> > >>     317               * min_volt_shift for each iteration.
> > >>     318               * The retry_max is 3 times of expeted
> > >> iteration count.
> > >>     319               */
> > >>     320              drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv-
> > >>> soc_data->sram_max_volt,
> > >>     321                                                     drv-
> > >>> soc_data->proc_max_volt),
> > >>     322                                                 drv-
> > >>> soc_data->min_volt_shift);
> > >>     323
> > >>     324              ret = clk_prepare_enable(drv->cci_clk);
> > >>     325              if (ret)
> > >>     326                      goto out_free_resources;
> > >>     327
> > >>     328              ret = clk_prepare_enable(drv->inter_clk);
> > >>     329              if (ret)
> > >>     330                      goto out_disable_cci_clk;
> > >>     331
> > >>     332              ret = dev_pm_opp_of_add_table(dev);
> > >>     333              if (ret) {
> > >>     334                      dev_err(dev, "failed to add opp table:
> > >> %d\n", ret);
> > >>     335                      goto out_disable_inter_clk;
> > >>     336              }
> > >>     337
> > >>     338              rate = clk_get_rate(drv->inter_clk);
> > >>     339              opp = dev_pm_opp_find_freq_ceil(dev, &rate);
> > >>     340              if (IS_ERR(opp)) {
> > >>     341                      ret = PTR_ERR(opp);
> > >>     342                      dev_err(dev, "failed to get
> > >> intermediate opp: %d\n", ret);
> > >>     343                      goto out_remove_opp_table;
> > >>     344              }
> > >>     345              drv->inter_voltage =
> > >> dev_pm_opp_get_voltage(opp);
> > >>     346              dev_pm_opp_put(opp);
> > >>     347
> > >>     348              rate = U32_MAX;
> > >>     349              opp = dev_pm_opp_find_freq_floor(drv->dev,
> > >> &rate);
> > >>     350              if (IS_ERR(opp)) {
> > >>     351                      dev_err(dev, "failed to get opp\n");
> > >>     352                      ret = PTR_ERR(opp);
> > >>     353                      goto out_remove_opp_table;
> > >>     354              }
> > >>     355
> > >>     356              opp_volt = dev_pm_opp_get_voltage(opp);
> > >>     357              dev_pm_opp_put(opp);
> > >>     358              ret = mtk_ccifreq_set_voltage(drv, opp_volt);
> > >>     359              if (ret) {
> > >>     360                      dev_err(dev, "failed to scale to
> > >> highest voltage %lu in proc_reg\n",
> > >>     361                              opp_volt);
> > >>     362                      goto out_remove_opp_table;
> > >>     363              }
> > >>     364
> > >>     365              passive_data = devm_kzalloc(dev, sizeof(struct
> > >> devfreq_passive_data),
> > >>     366                                          GFP_KERNEL);
> > >>     367              if (!passive_data) {
> > >>     368                      ret = -ENOMEM;
> > >>     369                      goto out_remove_opp_table;
> > >>     370              }
> > >>     371
> > >>     372              passive_data->parent_type = CPUFREQ_PARENT_DEV;
> > >>     373              drv->devfreq = devm_devfreq_add_device(dev,
> > >> &mtk_ccifreq_profile,
> > >>     374                                                     DEVFREQ_
> > >> GOV_PASSIVE,
> > >>     375                                                     passive_
> > >> data);
> > >>     376              if (IS_ERR(drv->devfreq)) {
> > >>     377                      ret = -EPROBE_DEFER;
> > >>     378                      dev_err(dev, "failed to add devfreq
> > >> device: %d\n",
> > >>   > 379                              PTR_ERR(drv->devfreq));
> > >>     380                      goto out_remove_opp_table;
> > >>     381              }
> > >>     382
> > >>     383              drv->opp_nb.notifier_call =
> > >> mtk_ccifreq_opp_notifier;
> > >>     384              ret = dev_pm_opp_register_notifier(dev, &drv-
> > >>> opp_nb);
> > >>     385              if (ret) {
> > >>     386                      dev_err(dev, "failed to register opp
> > >> notifier: %d\n", ret);
> > >>     387                      goto out_remove_devfreq_device;
> > >>     388              }
> > >>     389              return 0;
> > >>     390
> > >>     391      out_remove_devfreq_device:
> > >>     392              devm_devfreq_remove_device(dev, drv->devfreq);
> > >>     393
> > >>     394      out_remove_opp_table:
> > >>     395              dev_pm_opp_of_remove_table(dev);
> > >>     396
> > >>     397      out_disable_inter_clk:
> > >>     398              clk_disable_unprepare(drv->inter_clk);
> > >>     399
> > >>     400      out_disable_cci_clk:
> > >>     401              clk_disable_unprepare(drv->cci_clk);
> > >>     402
> > >>     403      out_free_resources:
> > >>     404              if (regulator_is_enabled(drv->proc_reg))
> > >>     405                      regulator_disable(drv->proc_reg);
> > >>     406              if (drv->sram_reg && regulator_is_enabled(drv-
> > >>> sram_reg))
> > >>     407                      regulator_disable(drv->sram_reg);
> > >>     408
> > >>     409              if (!IS_ERR(drv->proc_reg))
> > >>     410                      regulator_put(drv->proc_reg);
> > >>     411              if (!IS_ERR(drv->sram_reg))
> > >>     412                      regulator_put(drv->sram_reg);
> > >>     413              if (!IS_ERR(drv->cci_clk))
> > >>     414                      clk_put(drv->cci_clk);
> > >>     415              if (!IS_ERR(drv->inter_clk))
> > >>     416                      clk_put(drv->inter_clk);
> > >>     417
> > >>     418              return ret;
> > >>     419      }
> > >>     420
> > >>
> > >
> > > Hi "kernel test robot",
> > >
> > > Thanks for your review.
> > >
> > > This patch is based on chanwoo/devfreq-testing[1]
> > > [1]
> > > https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing
> >
> > Hi Johnson,
> >
> > Thanks for the feedback, we'll take a look too.
>
> I think the last patch on that branch might be broken.

You mean the patch[1]. Without this patch[1], there are no problems?
[1] https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/commit/?h=devfreq-testing&id=ea1011fba665b95fc28f682c9b131799a88b11ae

When you tested these patches with patchset[2] without last patch[1]
if there are no problems, please reply to patchset[2] with your Tested-by tag.
[2] https://patchwork.kernel.org/project/linux-pm/cover/20220507150145.531864-1-cw00.choi@samsung.com/


--
Best Regards,
Chanwoo Choi

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-05-07 13:53     ` Chanwoo Choi
@ 2022-05-09  5:57       ` Johnson Wang
  2022-05-09 11:51         ` Chanwoo Choi
  0 siblings, 1 reply; 27+ messages in thread
From: Johnson Wang @ 2022-05-09  5:57 UTC (permalink / raw)
  To: Chanwoo Choi, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

On Sat, 2022-05-07 at 22:53 +0900, Chanwoo Choi wrote:
> On 22. 5. 6. 20:38, Johnson Wang wrote:
> > On Mon, 2022-04-25 at 20:55 +0800, Johnson Wang wrote:
> > > We introduce a devfreq driver for the MediaTek Cache Coherent
> > > Interconnect
> > > (CCI) used by some MediaTek SoCs.
> > > 
> > > In this driver, we use the passive devfreq driver to get target
> > > frequencies
> > > and adjust voltages accordingly. In MT8183 and MT8186, the
> > > MediaTek
> > > CCI
> > > is supplied by the same regulators with the little core CPUs.
> > > 
> > > Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> > > Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > > ---
> > > This patch depends on "devfreq-testing"[1].
> > > [1]
> > > 
https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing__;!!CTRNKA9wMg0ARbw!wnTkI_sh3TsliBPFP70DFwtSZGtKyPinFu9h2BwULWX-xrWF0C21rLV-n1HhstfmLw42$
> > >  
> > > ---
> > >   drivers/devfreq/Kconfig           |  10 +
> > >   drivers/devfreq/Makefile          |   1 +
> > >   drivers/devfreq/mtk-cci-devfreq.c | 474
> > > ++++++++++++++++++++++++++++++
> > >   3 files changed, 485 insertions(+)
> > >   create mode 100644 drivers/devfreq/mtk-cci-devfreq.c
> > > 
> > > diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
> > > index 87eb2b837e68..9754d8b31621 100644
> > > --- a/drivers/devfreq/Kconfig
> > > +++ b/drivers/devfreq/Kconfig
> > > @@ -120,6 +120,16 @@ config ARM_TEGRA_DEVFREQ
> > >   	  It reads ACTMON counters of memory controllers and
> > > adjusts
> > > the
> > >   	  operating frequencies and voltages with OPP support.
> > >   
> > > +config ARM_MEDIATEK_CCI_DEVFREQ
> > > +	tristate "MEDIATEK CCI DEVFREQ Driver"
> > > +	depends on ARM_MEDIATEK_CPUFREQ || COMPILE_TEST
> > > +	select DEVFREQ_GOV_PASSIVE
> > > +	help
> > > +	  This adds a devfreq driver for MediaTek Cache Coherent
> > > Interconnect
> > > +	  which is shared the same regulators with the cpu cluster. It
> > > can track
> > > +	  buck voltages and update a proper CCI frequency. Use the
> > > notification
> > > +	  to get the regulator status.
> > > +
> > >   config ARM_RK3399_DMC_DEVFREQ
> > >   	tristate "ARM RK3399 DMC DEVFREQ Driver"
> > >   	depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
> > > diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
> > > index 0b6be92a25d9..bf40d04928d0 100644
> > > --- a/drivers/devfreq/Makefile
> > > +++ b/drivers/devfreq/Makefile
> > > @@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+=
> > > governor_passive.o
> > >   obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
> > >   obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o
> > >   obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
> > > +obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ)	+= mtk-cci-devfreq.o
> > >   obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
> > >   obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ)	+= sun8i-a33-
> > > mbus.o
> > >   obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-devfreq.o
> > > diff --git a/drivers/devfreq/mtk-cci-devfreq.c
> > > b/drivers/devfreq/mtk-
> > > cci-devfreq.c
> > > new file mode 100644
> > > index 000000000000..b3e31c45a57c
> > > --- /dev/null
> > > +++ b/drivers/devfreq/mtk-cci-devfreq.c
> > > @@ -0,0 +1,474 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * Copyright (C) 2022 MediaTek Inc.
> > > + */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/devfreq.h>
> > > +#include <linux/minmax.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_device.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/pm_opp.h>
> > > +#include <linux/regulator/consumer.h>
> > > +
> > > +struct mtk_ccifreq_platform_data {
> > > +	int min_volt_shift;
> > > +	int max_volt_shift;
> > > +	int proc_max_volt;
> > > +	int sram_min_volt;
> > > +	int sram_max_volt;
> > > +};
> > > +
> > > +struct mtk_ccifreq_drv {
> > > +	struct device *dev;
> > > +	struct devfreq *devfreq;
> > > +	struct regulator *proc_reg;
> > > +	struct regulator *sram_reg;
> > > +	struct clk *cci_clk;
> > > +	struct clk *inter_clk;
> > > +	int inter_voltage;
> > > +	int pre_voltage;
> > > +	unsigned long pre_freq;
> > > +	/* Avoid race condition for regulators between notify and
> > > policy */
> > > +	struct mutex reg_lock;
> > > +	struct notifier_block opp_nb;
> > > +	const struct mtk_ccifreq_platform_data *soc_data;
> > > +	int vtrack_max;
> > > +};
> > > +
> > > +static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv,
> > > int
> > > new_voltage)
> > > +{
> > > +	const struct mtk_ccifreq_platform_data *soc_data = drv-
> > > > soc_data;
> > > 
> > > +	struct device *dev = drv->dev;
> > > +	int pre_voltage, pre_vsram, new_vsram, vsram, voltage, ret;
> > > +	int retry_max = drv->vtrack_max;
> > > +
> > > +	if (!drv->sram_reg) {
> > > +		ret = regulator_set_voltage(drv->proc_reg, new_voltage,
> > > +					    drv->soc_data-
> > > > proc_max_volt);
> > > 
> > > +		goto out_set_voltage;
> > > +	}
> > > +
> > > +	pre_voltage = regulator_get_voltage(drv->proc_reg);
> > > +	if (pre_voltage < 0) {
> > > +		dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
> > > +		return pre_voltage;
> > > +	}
> > > +
> > > +	pre_vsram = regulator_get_voltage(drv->sram_reg);
> > > +	if (pre_vsram < 0) {
> > > +		dev_err(dev, "invalid vsram value: %d\n", pre_vsram);
> > > +		return pre_vsram;
> > > +	}
> > > +
> > > +	new_vsram = clamp(new_voltage + soc_data->min_volt_shift,
> > > +			  soc_data->sram_min_volt, soc_data-
> > > > sram_max_volt);
> > > 
> > > +
> > > +	do {
> > > +		if (pre_voltage <= new_voltage) {
> > > +			vsram = clamp(pre_voltage + soc_data-
> > > > max_volt_shift,
> > > 
> > > +				      soc_data->sram_min_volt,
> > > new_vsram);
> > > +			ret = regulator_set_voltage(drv->sram_reg,
> > > vsram,
> > > +						    soc_data-
> > > > sram_max_volt);
> > > 
> > > +			if (ret)
> > > +				return ret;
> > > +
> > > +			if (vsram == soc_data->sram_max_volt ||
> > > +			    new_vsram == soc_data->sram_min_volt)
> > > +				voltage = new_voltage;
> > > +			else
> > > +				voltage = vsram - soc_data-
> > > > min_volt_shift;
> > > 
> > > +
> > > +			ret = regulator_set_voltage(drv->proc_reg,
> > > voltage,
> > > +						    soc_data-
> > > > proc_max_volt);
> > > 
> > > +			if (ret) {
> > > +				regulator_set_voltage(drv->sram_reg,
> > > pre_vsram,
> > > +						      soc_data-
> > > > sram_max_volt);
> > > 
> > > +				return ret;
> > > +			}
> > > +		} else if (pre_voltage > new_voltage) {
> > > +			voltage = max(new_voltage,
> > > +				      pre_vsram - soc_data-
> > > > max_volt_shift);
> > > 
> > > +			ret = regulator_set_voltage(drv->proc_reg,
> > > voltage,
> > > +						    soc_data-
> > > > proc_max_volt);
> > > 
> > > +			if (ret)
> > > +				return ret;
> > > +
> > > +			if (voltage == new_voltage)
> > > +				vsram = new_vsram;
> > > +			else
> > > +				vsram = max(new_vsram,
> > > +					    voltage + soc_data-
> > > > min_volt_shift);
> > > 
> > > +
> > > +			ret = regulator_set_voltage(drv->sram_reg,
> > > vsram,
> > > +						    soc_data-
> > > > sram_max_volt);
> > > 
> > > +			if (ret) {
> > > +				regulator_set_voltage(drv->proc_reg,
> > > pre_voltage,
> > > +						      soc_data-
> > > > proc_max_volt);
> > > 
> > > +				return ret;
> > > +			}
> > > +		}
> > > +
> > > +		pre_voltage = voltage;
> > > +		pre_vsram = vsram;
> > > +
> > > +		if (--retry_max < 0) {
> > > +			dev_err(dev,
> > > +				"over loop count, failed to set
> > > voltage\n");
> > > +			return -EINVAL;
> > > +		}
> > > +	} while (voltage != new_voltage || vsram != new_vsram);
> > > +
> > > +out_set_voltage:
> > > +	if (!ret)
> > > +		drv->pre_voltage = new_voltage;
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static int mtk_ccifreq_target(struct device *dev, unsigned long
> > > *freq,
> > > +			      u32 flags)
> > > +{
> > > +	struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev);
> > > +	struct clk *cci_pll = clk_get_parent(drv->cci_clk);
> > > +	struct dev_pm_opp *opp;
> > > +	unsigned long opp_rate;
> > > +	int voltage, pre_voltage, inter_voltage, target_voltage, ret;
> > > +
> > > +	if (!drv)
> > > +		return -EINVAL;
> > > +
> > > +	if (drv->pre_freq == *freq)
> > > +		return 0;
> > > +
> > > +	inter_voltage = drv->inter_voltage;
> > > +
> > > +	opp_rate = *freq;
> > > +	opp = devfreq_recommended_opp(dev, &opp_rate, 1);
> > > +	if (IS_ERR(opp)) {
> > > +		dev_err(dev, "failed to find opp for freq: %ld\n",
> > > opp_rate);
> > > +		return PTR_ERR(opp);
> > > +	}
> > > +
> > > +	mutex_lock(&drv->reg_lock);
> > > +
> > > +	voltage = dev_pm_opp_get_voltage(opp);
> > > +	dev_pm_opp_put(opp);
> > > +
> > > +	if (unlikely(drv->pre_voltage <= 0))
> > > +		pre_voltage = regulator_get_voltage(drv->proc_reg);
> > > +	else
> > > +		pre_voltage = drv->pre_voltage;
> > > +
> > > +	if (pre_voltage < 0) {
> > > +		dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
> > > +		return pre_voltage;
> > > +	}
> > > +
> > > +	/* scale up: set voltage first then freq. */
> > > +	target_voltage = max(inter_voltage, voltage);
> > > +	if (pre_voltage <= target_voltage) {
> > > +		ret = mtk_ccifreq_set_voltage(drv, target_voltage);
> > > +		if (ret) {
> > > +			dev_err(dev, "failed to scale up voltage\n");
> > > +			goto out_restore_voltage;
> > > +		}
> > > +	}
> > > +
> > > +	/* switch the cci clock to intermediate clock source. */
> > > +	ret = clk_set_parent(drv->cci_clk, drv->inter_clk);
> > > +	if (ret) {
> > > +		dev_err(dev, "failed to re-parent cci clock\n");
> > > +		goto out_restore_voltage;
> > > +	}
> > > +
> > > +	/* set the original clock to target rate. */
> > > +	ret = clk_set_rate(cci_pll, *freq);
> > > +	if (ret) {
> > > +		dev_err(dev, "failed to set cci pll rate: %d\n", ret);
> > > +		clk_set_parent(drv->cci_clk, cci_pll);
> > > +		goto out_restore_voltage;
> > > +	}
> > > +
> > > +	/* switch the cci clock back to the original clock source. */
> > > +	ret = clk_set_parent(drv->cci_clk, cci_pll);
> > > +	if (ret) {
> > > +		dev_err(dev, "failed to re-parent cci clock\n");
> > > +		mtk_ccifreq_set_voltage(drv, inter_voltage);
> > > +		goto out_unlock;
> > > +	}
> > > +
> > > +	/*
> > > +	 * If the new voltage is lower than the intermediate voltage or
> > > the
> > > +	 * original voltage, scale down to the new voltage.
> > > +	 */
> > > +	if (voltage < inter_voltage || voltage < pre_voltage) {
> > > +		ret = mtk_ccifreq_set_voltage(drv, voltage);
> > > +		if (ret) {
> > > +			dev_err(dev, "failed to scale down voltage\n");
> > > +			goto out_unlock;
> > > +		}
> > > +	}
> > > +
> > > +	drv->pre_freq = *freq;
> > > +	mutex_unlock(&drv->reg_lock);
> > > +
> > > +	return 0;
> > > +
> > > +out_restore_voltage:
> > > +	mtk_ccifreq_set_voltage(drv, pre_voltage);
> > > +
> > > +out_unlock:
> > > +	mutex_unlock(&drv->reg_lock);
> > > +	return ret;
> > > +}
> > > +
> > > +static int mtk_ccifreq_opp_notifier(struct notifier_block *nb,
> > > +				    unsigned long event, void *data)
> > > +{
> > > +	struct dev_pm_opp *opp = data;
> > > +	struct mtk_ccifreq_drv *drv;
> > > +	unsigned long freq, volt;
> > > +
> > > +	drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb);
> > > +
> > > +	if (event == OPP_EVENT_ADJUST_VOLTAGE) {
> > > +		freq = dev_pm_opp_get_freq(opp);
> > > +
> > > +		mutex_lock(&drv->reg_lock);
> > > +		/* current opp item is changed */
> > > +		if (freq == drv->pre_freq) {
> > > +			volt = dev_pm_opp_get_voltage(opp);
> > > +			mtk_ccifreq_set_voltage(drv, volt);
> > > +		}
> > > +		mutex_unlock(&drv->reg_lock);
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static struct devfreq_dev_profile mtk_ccifreq_profile = {
> > > +	.target = mtk_ccifreq_target,
> > > +};
> > > +
> > > +static int mtk_ccifreq_probe(struct platform_device *pdev)
> > > +{
> > > +	struct device *dev = &pdev->dev;
> > > +	struct mtk_ccifreq_drv *drv;
> > > +	struct devfreq_passive_data *passive_data;
> > > +	struct dev_pm_opp *opp;
> > > +	unsigned long rate, opp_volt;
> > > +	int ret;
> > > +
> > > +	drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
> > > +	if (!drv)
> > > +		return -ENOMEM;
> > > +
> > > +	drv->dev = dev;
> > > +	drv->soc_data = (const struct mtk_ccifreq_platform_data *)
> > > +				of_device_get_match_data(&pdev->dev);
> > > +	mutex_init(&drv->reg_lock);
> > > +	platform_set_drvdata(pdev, drv);
> > > +
> > > +	drv->cci_clk = devm_clk_get(dev, "cci");
> > > +	if (IS_ERR(drv->cci_clk)) {
> > > +		ret = PTR_ERR(drv->cci_clk);
> > > +		return dev_err_probe(dev, ret,
> > > +				     "failed to get cci clk: %d\n",
> > > ret);
> > > +	}
> > > +
> > > +	drv->inter_clk = devm_clk_get(dev, "intermediate");
> > > +	if (IS_ERR(drv->inter_clk)) {
> > > +		ret = PTR_ERR(drv->inter_clk);
> > > +		dev_err_probe(dev, ret,
> > > +			      "failed to get intermediate clk: %d\n",
> > > ret);
> > > +		goto out_free_resources;
> > > +	}
> > > +
> > > +	drv->proc_reg = devm_regulator_get_optional(dev, "proc");
> > > +	if (IS_ERR(drv->proc_reg)) {
> > > +		ret = PTR_ERR(drv->proc_reg);
> > > +		dev_err_probe(dev, ret,
> > > +			      "failed to get proc regulator: %d\n",
> > > ret);
> > > +		goto out_free_resources;
> > > +	}
> > > +
> > > +	ret = regulator_enable(drv->proc_reg);
> > > +	if (ret) {
> > > +		dev_err(dev, "failed to enable proc regulator\n");
> > > +		goto out_free_resources;
> > > +	}
> > > +
> > > +	drv->sram_reg = regulator_get_optional(dev, "sram");
> > > +	if (IS_ERR(drv->sram_reg))
> > > +		drv->sram_reg = NULL;
> > > +	else {
> > > +		ret = regulator_enable(drv->sram_reg);
> > > +		if (ret) {
> > > +			dev_err(dev, "failed to enable sram
> > > regulator\n");
> > > +			goto out_free_resources;
> > > +		}
> > > +	}
> > > +
> > > +	/*
> > > +	 * We assume min voltage is 0 and tracking target voltage using
> > > +	 * min_volt_shift for each iteration.
> > > +	 * The retry_max is 3 times of expeted iteration count.
> > > +	 */
> > > +	drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data-
> > > > sram_max_volt,
> > > 
> > > +					       drv->soc_data-
> > > > proc_max_volt),
> > > 
> > > +					   drv->soc_data-
> > > > min_volt_shift);
> > > 
> > > +
> > > +	ret = clk_prepare_enable(drv->cci_clk);
> > > +	if (ret)
> > > +		goto out_free_resources;
> > > +
> > > +	ret = clk_prepare_enable(drv->inter_clk);
> > > +	if (ret)
> > > +		goto out_disable_cci_clk;
> > > +
> > > +	ret = dev_pm_opp_of_add_table(dev);
> > > +	if (ret) {
> > > +		dev_err(dev, "failed to add opp table: %d\n", ret);
> > > +		goto out_disable_inter_clk;
> > > +	}
> > > +
> > > +	rate = clk_get_rate(drv->inter_clk);
> > > +	opp = dev_pm_opp_find_freq_ceil(dev, &rate);
> > > +	if (IS_ERR(opp)) {
> > > +		ret = PTR_ERR(opp);
> > > +		dev_err(dev, "failed to get intermediate opp: %d\n",
> > > ret);
> > > +		goto out_remove_opp_table;
> > > +	}
> > > +	drv->inter_voltage = dev_pm_opp_get_voltage(opp);
> > > +	dev_pm_opp_put(opp);
> > > +
> > > +	rate = U32_MAX;
> > > +	opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
> > > +	if (IS_ERR(opp)) {
> > > +		dev_err(dev, "failed to get opp\n");
> > > +		ret = PTR_ERR(opp);
> > > +		goto out_remove_opp_table;
> > > +	}
> > > +
> > > +	opp_volt = dev_pm_opp_get_voltage(opp);
> > > +	dev_pm_opp_put(opp);
> > > +	ret = mtk_ccifreq_set_voltage(drv, opp_volt);
> > > +	if (ret) {
> > > +		dev_err(dev, "failed to scale to highest voltage %lu in
> > > proc_reg\n",
> > > +			opp_volt);
> > > +		goto out_remove_opp_table;
> > > +	}
> > > +
> > > +	passive_data = devm_kzalloc(dev, sizeof(struct
> > > devfreq_passive_data),
> > > +				    GFP_KERNEL);
> > > +	if (!passive_data) {
> > > +		ret = -ENOMEM;
> > > +		goto out_remove_opp_table;
> > > +	}
> > > +
> > > +	passive_data->parent_type = CPUFREQ_PARENT_DEV;
> > > +	drv->devfreq = devm_devfreq_add_device(dev,
> > > &mtk_ccifreq_profile,
> > > +					       DEVFREQ_GOV_PASSIVE,
> > > +					       passive_data);
> > > +	if (IS_ERR(drv->devfreq)) {
> > > +		ret = -EPROBE_DEFER;
> > > +		dev_err(dev, "failed to add devfreq device: %d\n",
> > > +			PTR_ERR(drv->devfreq));
> > > +		goto out_remove_opp_table;
> > > +	}
> > > +
> > > +	drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
> > > +	ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
> > > +	if (ret) {
> > > +		dev_err(dev, "failed to register opp notifier: %d\n",
> > > ret);
> > > +		goto out_remove_devfreq_device;
> > > +	}
> > > +	return 0;
> > > +
> > > +out_remove_devfreq_device:
> > > +	devm_devfreq_remove_device(dev, drv->devfreq);
> > > +
> > > +out_remove_opp_table:
> > > +	dev_pm_opp_of_remove_table(dev);
> > > +
> > > +out_disable_inter_clk:
> > > +	clk_disable_unprepare(drv->inter_clk);
> > > +
> > > +out_disable_cci_clk:
> > > +	clk_disable_unprepare(drv->cci_clk);
> > > +
> > > +out_free_resources:
> > > +	if (regulator_is_enabled(drv->proc_reg))
> > > +		regulator_disable(drv->proc_reg);
> > > +	if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
> > > +		regulator_disable(drv->sram_reg);
> > > +
> > > +	if (!IS_ERR(drv->proc_reg))
> > > +		regulator_put(drv->proc_reg);
> > > +	if (!IS_ERR(drv->sram_reg))
> > > +		regulator_put(drv->sram_reg);
> > > +	if (!IS_ERR(drv->cci_clk))
> > > +		clk_put(drv->cci_clk);
> > > +	if (!IS_ERR(drv->inter_clk))
> > > +		clk_put(drv->inter_clk);
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static int mtk_ccifreq_remove(struct platform_device *pdev)
> > > +{
> > > +	struct device *dev = &pdev->dev;
> > > +	struct mtk_ccifreq_drv *drv;
> > > +
> > > +	drv = platform_get_drvdata(pdev);
> > > +
> > > +	dev_pm_opp_unregister_notifier(dev, &drv->opp_nb);
> > > +	dev_pm_opp_of_remove_table(dev);
> > > +	clk_disable_unprepare(drv->inter_clk);
> > > +	clk_disable_unprepare(drv->cci_clk);
> > > +	regulator_disable(drv->proc_reg);
> > > +	if (drv->sram_reg)
> > > +		regulator_disable(drv->sram_reg);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static const struct mtk_ccifreq_platform_data
> > > mt8183_platform_data =
> > > {
> > > +	.min_volt_shift = 100000,
> > > +	.max_volt_shift = 200000,
> > > +	.proc_max_volt = 1150000,
> > > +	.sram_min_volt = 0,
> > > +	.sram_max_volt = 1150000,
> > > +};
> > > +
> > > +static const struct mtk_ccifreq_platform_data
> > > mt8186_platform_data =
> > > {
> > > +	.min_volt_shift = 100000,
> > > +	.max_volt_shift = 250000,
> > > +	.proc_max_volt = 1118750,
> > > +	.sram_min_volt = 850000,
> > > +	.sram_max_volt = 1118750,
> > > +};
> > > +
> > > +static const struct of_device_id mtk_ccifreq_machines[] = {
> > > +	{ .compatible = "mediatek,mt8183-cci", .data =
> > > &mt8183_platform_data },
> > > +	{ .compatible = "mediatek,mt8186-cci", .data =
> > > &mt8186_platform_data },
> > > +	{ },
> > > +};
> > > +MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines);
> > > +
> > > +static struct platform_driver mtk_ccifreq_platdrv = {
> > > +	.probe	= mtk_ccifreq_probe,
> > > +	.remove	= mtk_ccifreq_remove,
> > > +	.driver = {
> > > +		.name = "mtk-ccifreq",
> > > +		.of_match_table = mtk_ccifreq_machines,
> > > +	},
> > > +};
> > > +module_platform_driver(mtk_ccifreq_platdrv);
> > > +
> > > +MODULE_DESCRIPTION("MediaTek CCI devfreq driver");
> > > +MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>");
> > > +MODULE_LICENSE("GPL v2");
> > 
> > Hi Chanwoo,
> > 
> > Just a kindly ping.
> > Could you please give me some suggestion on this patch?
> > Thanks!
> > 
> > BRs,
> > Johnson Wang
> > 
> 
> Hi Johnson,
> 
> Sorry for late reply.But I replied it yesterday as following:
> Maybe, this reply[1] has not yet arrrived at your mail box.
> [1] 
> 
https://lore.kernel.org/lkml/0846a062-2ea2-e6d4-03c8-992c2f2e24a0@gmail.com/T/#m3bc609d805d6e74ec7a105be0511926b4afbbaef
> 
> As I described on reply[1], I updated the patches on devfreq-testing
> branch. Could you please test your patches based on devfreq-testing
> branch?
> 

Hi Chanwoo,

Thanks for your information.
I've tested this patch based on the latest devfreq-testing branch.
It encounters the same crash as Chen-Yu mentioned[1].

[1]https://lore.kernel.org/linux-pm/YniX1w+oI1eOCmCx@google.com/T/#u


BRs,
Johnson Wang


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-05-09  5:57       ` Johnson Wang
@ 2022-05-09 11:51         ` Chanwoo Choi
  2022-05-11  5:14           ` Johnson Wang
  0 siblings, 1 reply; 27+ messages in thread
From: Chanwoo Choi @ 2022-05-09 11:51 UTC (permalink / raw)
  To: Johnson Wang, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

On 22. 5. 9. 14:57, Johnson Wang wrote:
> On Sat, 2022-05-07 at 22:53 +0900, Chanwoo Choi wrote:
>> On 22. 5. 6. 20:38, Johnson Wang wrote:
>>> On Mon, 2022-04-25 at 20:55 +0800, Johnson Wang wrote:
>>>> We introduce a devfreq driver for the MediaTek Cache Coherent
>>>> Interconnect
>>>> (CCI) used by some MediaTek SoCs.
>>>>
>>>> In this driver, we use the passive devfreq driver to get target
>>>> frequencies
>>>> and adjust voltages accordingly. In MT8183 and MT8186, the
>>>> MediaTek
>>>> CCI
>>>> is supplied by the same regulators with the little core CPUs.
>>>>
>>>> Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
>>>> Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
>>>> ---
>>>> This patch depends on "devfreq-testing"[1].
>>>> [1]
>>>>
> https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing__;!!CTRNKA9wMg0ARbw!wnTkI_sh3TsliBPFP70DFwtSZGtKyPinFu9h2BwULWX-xrWF0C21rLV-n1HhstfmLw42$
>>>>   
>>>> ---
>>>>    drivers/devfreq/Kconfig           |  10 +
>>>>    drivers/devfreq/Makefile          |   1 +
>>>>    drivers/devfreq/mtk-cci-devfreq.c | 474
>>>> ++++++++++++++++++++++++++++++
>>>>    3 files changed, 485 insertions(+)
>>>>    create mode 100644 drivers/devfreq/mtk-cci-devfreq.c
>>>>
>>>> diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
>>>> index 87eb2b837e68..9754d8b31621 100644
>>>> --- a/drivers/devfreq/Kconfig
>>>> +++ b/drivers/devfreq/Kconfig
>>>> @@ -120,6 +120,16 @@ config ARM_TEGRA_DEVFREQ
>>>>    	  It reads ACTMON counters of memory controllers and
>>>> adjusts
>>>> the
>>>>    	  operating frequencies and voltages with OPP support.
>>>>    
>>>> +config ARM_MEDIATEK_CCI_DEVFREQ
>>>> +	tristate "MEDIATEK CCI DEVFREQ Driver"
>>>> +	depends on ARM_MEDIATEK_CPUFREQ || COMPILE_TEST
>>>> +	select DEVFREQ_GOV_PASSIVE
>>>> +	help
>>>> +	  This adds a devfreq driver for MediaTek Cache Coherent
>>>> Interconnect
>>>> +	  which is shared the same regulators with the cpu cluster. It
>>>> can track
>>>> +	  buck voltages and update a proper CCI frequency. Use the
>>>> notification
>>>> +	  to get the regulator status.
>>>> +
>>>>    config ARM_RK3399_DMC_DEVFREQ
>>>>    	tristate "ARM RK3399 DMC DEVFREQ Driver"
>>>>    	depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
>>>> diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
>>>> index 0b6be92a25d9..bf40d04928d0 100644
>>>> --- a/drivers/devfreq/Makefile
>>>> +++ b/drivers/devfreq/Makefile
>>>> @@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+=
>>>> governor_passive.o
>>>>    obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
>>>>    obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o
>>>>    obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
>>>> +obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ)	+= mtk-cci-devfreq.o
>>>>    obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
>>>>    obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ)	+= sun8i-a33-
>>>> mbus.o
>>>>    obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-devfreq.o
>>>> diff --git a/drivers/devfreq/mtk-cci-devfreq.c
>>>> b/drivers/devfreq/mtk-
>>>> cci-devfreq.c
>>>> new file mode 100644
>>>> index 000000000000..b3e31c45a57c
>>>> --- /dev/null
>>>> +++ b/drivers/devfreq/mtk-cci-devfreq.c
>>>> @@ -0,0 +1,474 @@
>>>> +// SPDX-License-Identifier: GPL-2.0-only
>>>> +/*
>>>> + * Copyright (C) 2022 MediaTek Inc.
>>>> + */
>>>> +
>>>> +#include <linux/clk.h>
>>>> +#include <linux/devfreq.h>
>>>> +#include <linux/minmax.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_device.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/pm_opp.h>
>>>> +#include <linux/regulator/consumer.h>
>>>> +
>>>> +struct mtk_ccifreq_platform_data {
>>>> +	int min_volt_shift;
>>>> +	int max_volt_shift;
>>>> +	int proc_max_volt;
>>>> +	int sram_min_volt;
>>>> +	int sram_max_volt;
>>>> +};
>>>> +
>>>> +struct mtk_ccifreq_drv {
>>>> +	struct device *dev;
>>>> +	struct devfreq *devfreq;
>>>> +	struct regulator *proc_reg;
>>>> +	struct regulator *sram_reg;
>>>> +	struct clk *cci_clk;
>>>> +	struct clk *inter_clk;
>>>> +	int inter_voltage;
>>>> +	int pre_voltage;
>>>> +	unsigned long pre_freq;
>>>> +	/* Avoid race condition for regulators between notify and
>>>> policy */
>>>> +	struct mutex reg_lock;
>>>> +	struct notifier_block opp_nb;
>>>> +	const struct mtk_ccifreq_platform_data *soc_data;
>>>> +	int vtrack_max;
>>>> +};
>>>> +
>>>> +static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv,
>>>> int
>>>> new_voltage)
>>>> +{
>>>> +	const struct mtk_ccifreq_platform_data *soc_data = drv-
>>>>> soc_data;
>>>>
>>>> +	struct device *dev = drv->dev;
>>>> +	int pre_voltage, pre_vsram, new_vsram, vsram, voltage, ret;
>>>> +	int retry_max = drv->vtrack_max;
>>>> +
>>>> +	if (!drv->sram_reg) {
>>>> +		ret = regulator_set_voltage(drv->proc_reg, new_voltage,
>>>> +					    drv->soc_data-
>>>>> proc_max_volt);
>>>>
>>>> +		goto out_set_voltage;
>>>> +	}
>>>> +
>>>> +	pre_voltage = regulator_get_voltage(drv->proc_reg);
>>>> +	if (pre_voltage < 0) {
>>>> +		dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
>>>> +		return pre_voltage;
>>>> +	}
>>>> +
>>>> +	pre_vsram = regulator_get_voltage(drv->sram_reg);
>>>> +	if (pre_vsram < 0) {
>>>> +		dev_err(dev, "invalid vsram value: %d\n", pre_vsram);
>>>> +		return pre_vsram;
>>>> +	}
>>>> +
>>>> +	new_vsram = clamp(new_voltage + soc_data->min_volt_shift,
>>>> +			  soc_data->sram_min_volt, soc_data-
>>>>> sram_max_volt);
>>>>
>>>> +
>>>> +	do {
>>>> +		if (pre_voltage <= new_voltage) {
>>>> +			vsram = clamp(pre_voltage + soc_data-
>>>>> max_volt_shift,
>>>>
>>>> +				      soc_data->sram_min_volt,
>>>> new_vsram);
>>>> +			ret = regulator_set_voltage(drv->sram_reg,
>>>> vsram,
>>>> +						    soc_data-
>>>>> sram_max_volt);
>>>>
>>>> +			if (ret)
>>>> +				return ret;
>>>> +
>>>> +			if (vsram == soc_data->sram_max_volt ||
>>>> +			    new_vsram == soc_data->sram_min_volt)
>>>> +				voltage = new_voltage;
>>>> +			else
>>>> +				voltage = vsram - soc_data-
>>>>> min_volt_shift;
>>>>
>>>> +
>>>> +			ret = regulator_set_voltage(drv->proc_reg,
>>>> voltage,
>>>> +						    soc_data-
>>>>> proc_max_volt);
>>>>
>>>> +			if (ret) {
>>>> +				regulator_set_voltage(drv->sram_reg,
>>>> pre_vsram,
>>>> +						      soc_data-
>>>>> sram_max_volt);
>>>>
>>>> +				return ret;
>>>> +			}
>>>> +		} else if (pre_voltage > new_voltage) {
>>>> +			voltage = max(new_voltage,
>>>> +				      pre_vsram - soc_data-
>>>>> max_volt_shift);
>>>>
>>>> +			ret = regulator_set_voltage(drv->proc_reg,
>>>> voltage,
>>>> +						    soc_data-
>>>>> proc_max_volt);
>>>>
>>>> +			if (ret)
>>>> +				return ret;
>>>> +
>>>> +			if (voltage == new_voltage)
>>>> +				vsram = new_vsram;
>>>> +			else
>>>> +				vsram = max(new_vsram,
>>>> +					    voltage + soc_data-
>>>>> min_volt_shift);
>>>>
>>>> +
>>>> +			ret = regulator_set_voltage(drv->sram_reg,
>>>> vsram,
>>>> +						    soc_data-
>>>>> sram_max_volt);
>>>>
>>>> +			if (ret) {
>>>> +				regulator_set_voltage(drv->proc_reg,
>>>> pre_voltage,
>>>> +						      soc_data-
>>>>> proc_max_volt);
>>>>
>>>> +				return ret;
>>>> +			}
>>>> +		}
>>>> +
>>>> +		pre_voltage = voltage;
>>>> +		pre_vsram = vsram;
>>>> +
>>>> +		if (--retry_max < 0) {
>>>> +			dev_err(dev,
>>>> +				"over loop count, failed to set
>>>> voltage\n");
>>>> +			return -EINVAL;
>>>> +		}
>>>> +	} while (voltage != new_voltage || vsram != new_vsram);
>>>> +
>>>> +out_set_voltage:
>>>> +	if (!ret)
>>>> +		drv->pre_voltage = new_voltage;
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static int mtk_ccifreq_target(struct device *dev, unsigned long
>>>> *freq,
>>>> +			      u32 flags)
>>>> +{
>>>> +	struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev);
>>>> +	struct clk *cci_pll = clk_get_parent(drv->cci_clk);
>>>> +	struct dev_pm_opp *opp;
>>>> +	unsigned long opp_rate;
>>>> +	int voltage, pre_voltage, inter_voltage, target_voltage, ret;
>>>> +
>>>> +	if (!drv)
>>>> +		return -EINVAL;
>>>> +
>>>> +	if (drv->pre_freq == *freq)
>>>> +		return 0;
>>>> +
>>>> +	inter_voltage = drv->inter_voltage;
>>>> +
>>>> +	opp_rate = *freq;
>>>> +	opp = devfreq_recommended_opp(dev, &opp_rate, 1);
>>>> +	if (IS_ERR(opp)) {
>>>> +		dev_err(dev, "failed to find opp for freq: %ld\n",
>>>> opp_rate);
>>>> +		return PTR_ERR(opp);
>>>> +	}
>>>> +
>>>> +	mutex_lock(&drv->reg_lock);
>>>> +
>>>> +	voltage = dev_pm_opp_get_voltage(opp);
>>>> +	dev_pm_opp_put(opp);
>>>> +
>>>> +	if (unlikely(drv->pre_voltage <= 0))
>>>> +		pre_voltage = regulator_get_voltage(drv->proc_reg);
>>>> +	else
>>>> +		pre_voltage = drv->pre_voltage;
>>>> +
>>>> +	if (pre_voltage < 0) {
>>>> +		dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
>>>> +		return pre_voltage;
>>>> +	}
>>>> +
>>>> +	/* scale up: set voltage first then freq. */
>>>> +	target_voltage = max(inter_voltage, voltage);
>>>> +	if (pre_voltage <= target_voltage) {
>>>> +		ret = mtk_ccifreq_set_voltage(drv, target_voltage);
>>>> +		if (ret) {
>>>> +			dev_err(dev, "failed to scale up voltage\n");
>>>> +			goto out_restore_voltage;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	/* switch the cci clock to intermediate clock source. */
>>>> +	ret = clk_set_parent(drv->cci_clk, drv->inter_clk);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "failed to re-parent cci clock\n");
>>>> +		goto out_restore_voltage;
>>>> +	}
>>>> +
>>>> +	/* set the original clock to target rate. */
>>>> +	ret = clk_set_rate(cci_pll, *freq);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "failed to set cci pll rate: %d\n", ret);
>>>> +		clk_set_parent(drv->cci_clk, cci_pll);
>>>> +		goto out_restore_voltage;
>>>> +	}
>>>> +
>>>> +	/* switch the cci clock back to the original clock source. */
>>>> +	ret = clk_set_parent(drv->cci_clk, cci_pll);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "failed to re-parent cci clock\n");
>>>> +		mtk_ccifreq_set_voltage(drv, inter_voltage);
>>>> +		goto out_unlock;
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * If the new voltage is lower than the intermediate voltage or
>>>> the
>>>> +	 * original voltage, scale down to the new voltage.
>>>> +	 */
>>>> +	if (voltage < inter_voltage || voltage < pre_voltage) {
>>>> +		ret = mtk_ccifreq_set_voltage(drv, voltage);
>>>> +		if (ret) {
>>>> +			dev_err(dev, "failed to scale down voltage\n");
>>>> +			goto out_unlock;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	drv->pre_freq = *freq;
>>>> +	mutex_unlock(&drv->reg_lock);
>>>> +
>>>> +	return 0;
>>>> +
>>>> +out_restore_voltage:
>>>> +	mtk_ccifreq_set_voltage(drv, pre_voltage);
>>>> +
>>>> +out_unlock:
>>>> +	mutex_unlock(&drv->reg_lock);
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static int mtk_ccifreq_opp_notifier(struct notifier_block *nb,
>>>> +				    unsigned long event, void *data)
>>>> +{
>>>> +	struct dev_pm_opp *opp = data;
>>>> +	struct mtk_ccifreq_drv *drv;
>>>> +	unsigned long freq, volt;
>>>> +
>>>> +	drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb);
>>>> +
>>>> +	if (event == OPP_EVENT_ADJUST_VOLTAGE) {
>>>> +		freq = dev_pm_opp_get_freq(opp);
>>>> +
>>>> +		mutex_lock(&drv->reg_lock);
>>>> +		/* current opp item is changed */
>>>> +		if (freq == drv->pre_freq) {
>>>> +			volt = dev_pm_opp_get_voltage(opp);
>>>> +			mtk_ccifreq_set_voltage(drv, volt);
>>>> +		}
>>>> +		mutex_unlock(&drv->reg_lock);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static struct devfreq_dev_profile mtk_ccifreq_profile = {
>>>> +	.target = mtk_ccifreq_target,
>>>> +};
>>>> +
>>>> +static int mtk_ccifreq_probe(struct platform_device *pdev)
>>>> +{
>>>> +	struct device *dev = &pdev->dev;
>>>> +	struct mtk_ccifreq_drv *drv;
>>>> +	struct devfreq_passive_data *passive_data;
>>>> +	struct dev_pm_opp *opp;
>>>> +	unsigned long rate, opp_volt;
>>>> +	int ret;
>>>> +
>>>> +	drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
>>>> +	if (!drv)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	drv->dev = dev;
>>>> +	drv->soc_data = (const struct mtk_ccifreq_platform_data *)
>>>> +				of_device_get_match_data(&pdev->dev);
>>>> +	mutex_init(&drv->reg_lock);
>>>> +	platform_set_drvdata(pdev, drv);
>>>> +
>>>> +	drv->cci_clk = devm_clk_get(dev, "cci");
>>>> +	if (IS_ERR(drv->cci_clk)) {
>>>> +		ret = PTR_ERR(drv->cci_clk);
>>>> +		return dev_err_probe(dev, ret,
>>>> +				     "failed to get cci clk: %d\n",
>>>> ret);
>>>> +	}
>>>> +
>>>> +	drv->inter_clk = devm_clk_get(dev, "intermediate");
>>>> +	if (IS_ERR(drv->inter_clk)) {
>>>> +		ret = PTR_ERR(drv->inter_clk);
>>>> +		dev_err_probe(dev, ret,
>>>> +			      "failed to get intermediate clk: %d\n",
>>>> ret);
>>>> +		goto out_free_resources;
>>>> +	}
>>>> +
>>>> +	drv->proc_reg = devm_regulator_get_optional(dev, "proc");
>>>> +	if (IS_ERR(drv->proc_reg)) {
>>>> +		ret = PTR_ERR(drv->proc_reg);
>>>> +		dev_err_probe(dev, ret,
>>>> +			      "failed to get proc regulator: %d\n",
>>>> ret);
>>>> +		goto out_free_resources;
>>>> +	}
>>>> +
>>>> +	ret = regulator_enable(drv->proc_reg);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "failed to enable proc regulator\n");
>>>> +		goto out_free_resources;
>>>> +	}
>>>> +
>>>> +	drv->sram_reg = regulator_get_optional(dev, "sram");
>>>> +	if (IS_ERR(drv->sram_reg))
>>>> +		drv->sram_reg = NULL;
>>>> +	else {
>>>> +		ret = regulator_enable(drv->sram_reg);
>>>> +		if (ret) {
>>>> +			dev_err(dev, "failed to enable sram
>>>> regulator\n");
>>>> +			goto out_free_resources;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * We assume min voltage is 0 and tracking target voltage using
>>>> +	 * min_volt_shift for each iteration.
>>>> +	 * The retry_max is 3 times of expeted iteration count.
>>>> +	 */
>>>> +	drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data-
>>>>> sram_max_volt,
>>>>
>>>> +					       drv->soc_data-
>>>>> proc_max_volt),
>>>>
>>>> +					   drv->soc_data-
>>>>> min_volt_shift);
>>>>
>>>> +
>>>> +	ret = clk_prepare_enable(drv->cci_clk);
>>>> +	if (ret)
>>>> +		goto out_free_resources;
>>>> +
>>>> +	ret = clk_prepare_enable(drv->inter_clk);
>>>> +	if (ret)
>>>> +		goto out_disable_cci_clk;
>>>> +
>>>> +	ret = dev_pm_opp_of_add_table(dev);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "failed to add opp table: %d\n", ret);
>>>> +		goto out_disable_inter_clk;
>>>> +	}
>>>> +
>>>> +	rate = clk_get_rate(drv->inter_clk);
>>>> +	opp = dev_pm_opp_find_freq_ceil(dev, &rate);
>>>> +	if (IS_ERR(opp)) {
>>>> +		ret = PTR_ERR(opp);
>>>> +		dev_err(dev, "failed to get intermediate opp: %d\n",
>>>> ret);
>>>> +		goto out_remove_opp_table;
>>>> +	}
>>>> +	drv->inter_voltage = dev_pm_opp_get_voltage(opp);
>>>> +	dev_pm_opp_put(opp);
>>>> +
>>>> +	rate = U32_MAX;
>>>> +	opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
>>>> +	if (IS_ERR(opp)) {
>>>> +		dev_err(dev, "failed to get opp\n");
>>>> +		ret = PTR_ERR(opp);
>>>> +		goto out_remove_opp_table;
>>>> +	}
>>>> +
>>>> +	opp_volt = dev_pm_opp_get_voltage(opp);
>>>> +	dev_pm_opp_put(opp);
>>>> +	ret = mtk_ccifreq_set_voltage(drv, opp_volt);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "failed to scale to highest voltage %lu in
>>>> proc_reg\n",
>>>> +			opp_volt);
>>>> +		goto out_remove_opp_table;
>>>> +	}
>>>> +
>>>> +	passive_data = devm_kzalloc(dev, sizeof(struct
>>>> devfreq_passive_data),
>>>> +				    GFP_KERNEL);
>>>> +	if (!passive_data) {
>>>> +		ret = -ENOMEM;
>>>> +		goto out_remove_opp_table;
>>>> +	}
>>>> +
>>>> +	passive_data->parent_type = CPUFREQ_PARENT_DEV;
>>>> +	drv->devfreq = devm_devfreq_add_device(dev,
>>>> &mtk_ccifreq_profile,
>>>> +					       DEVFREQ_GOV_PASSIVE,
>>>> +					       passive_data);
>>>> +	if (IS_ERR(drv->devfreq)) {
>>>> +		ret = -EPROBE_DEFER;
>>>> +		dev_err(dev, "failed to add devfreq device: %d\n",
>>>> +			PTR_ERR(drv->devfreq));
>>>> +		goto out_remove_opp_table;
>>>> +	}
>>>> +
>>>> +	drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
>>>> +	ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "failed to register opp notifier: %d\n",
>>>> ret);
>>>> +		goto out_remove_devfreq_device;
>>>> +	}
>>>> +	return 0;
>>>> +
>>>> +out_remove_devfreq_device:
>>>> +	devm_devfreq_remove_device(dev, drv->devfreq);
>>>> +
>>>> +out_remove_opp_table:
>>>> +	dev_pm_opp_of_remove_table(dev);
>>>> +
>>>> +out_disable_inter_clk:
>>>> +	clk_disable_unprepare(drv->inter_clk);
>>>> +
>>>> +out_disable_cci_clk:
>>>> +	clk_disable_unprepare(drv->cci_clk);
>>>> +
>>>> +out_free_resources:
>>>> +	if (regulator_is_enabled(drv->proc_reg))
>>>> +		regulator_disable(drv->proc_reg);
>>>> +	if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
>>>> +		regulator_disable(drv->sram_reg);
>>>> +
>>>> +	if (!IS_ERR(drv->proc_reg))
>>>> +		regulator_put(drv->proc_reg);
>>>> +	if (!IS_ERR(drv->sram_reg))
>>>> +		regulator_put(drv->sram_reg);
>>>> +	if (!IS_ERR(drv->cci_clk))
>>>> +		clk_put(drv->cci_clk);
>>>> +	if (!IS_ERR(drv->inter_clk))
>>>> +		clk_put(drv->inter_clk);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static int mtk_ccifreq_remove(struct platform_device *pdev)
>>>> +{
>>>> +	struct device *dev = &pdev->dev;
>>>> +	struct mtk_ccifreq_drv *drv;
>>>> +
>>>> +	drv = platform_get_drvdata(pdev);
>>>> +
>>>> +	dev_pm_opp_unregister_notifier(dev, &drv->opp_nb);
>>>> +	dev_pm_opp_of_remove_table(dev);
>>>> +	clk_disable_unprepare(drv->inter_clk);
>>>> +	clk_disable_unprepare(drv->cci_clk);
>>>> +	regulator_disable(drv->proc_reg);
>>>> +	if (drv->sram_reg)
>>>> +		regulator_disable(drv->sram_reg);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static const struct mtk_ccifreq_platform_data
>>>> mt8183_platform_data =
>>>> {
>>>> +	.min_volt_shift = 100000,
>>>> +	.max_volt_shift = 200000,
>>>> +	.proc_max_volt = 1150000,
>>>> +	.sram_min_volt = 0,
>>>> +	.sram_max_volt = 1150000,
>>>> +};
>>>> +
>>>> +static const struct mtk_ccifreq_platform_data
>>>> mt8186_platform_data =
>>>> {
>>>> +	.min_volt_shift = 100000,
>>>> +	.max_volt_shift = 250000,
>>>> +	.proc_max_volt = 1118750,
>>>> +	.sram_min_volt = 850000,
>>>> +	.sram_max_volt = 1118750,
>>>> +};
>>>> +
>>>> +static const struct of_device_id mtk_ccifreq_machines[] = {
>>>> +	{ .compatible = "mediatek,mt8183-cci", .data =
>>>> &mt8183_platform_data },
>>>> +	{ .compatible = "mediatek,mt8186-cci", .data =
>>>> &mt8186_platform_data },
>>>> +	{ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines);
>>>> +
>>>> +static struct platform_driver mtk_ccifreq_platdrv = {
>>>> +	.probe	= mtk_ccifreq_probe,
>>>> +	.remove	= mtk_ccifreq_remove,
>>>> +	.driver = {
>>>> +		.name = "mtk-ccifreq",
>>>> +		.of_match_table = mtk_ccifreq_machines,
>>>> +	},
>>>> +};
>>>> +module_platform_driver(mtk_ccifreq_platdrv);
>>>> +
>>>> +MODULE_DESCRIPTION("MediaTek CCI devfreq driver");
>>>> +MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>");
>>>> +MODULE_LICENSE("GPL v2");
>>>
>>> Hi Chanwoo,
>>>
>>> Just a kindly ping.
>>> Could you please give me some suggestion on this patch?
>>> Thanks!
>>>
>>> BRs,
>>> Johnson Wang
>>>
>>
>> Hi Johnson,
>>
>> Sorry for late reply.But I replied it yesterday as following:
>> Maybe, this reply[1] has not yet arrrived at your mail box.
>> [1]
>>
> https://lore.kernel.org/lkml/0846a062-2ea2-e6d4-03c8-992c2f2e24a0@gmail.com/T/#m3bc609d805d6e74ec7a105be0511926b4afbbaef
>>
>> As I described on reply[1], I updated the patches on devfreq-testing
>> branch. Could you please test your patches based on devfreq-testing
>> branch?
>>
> 
> Hi Chanwoo,
> 
> Thanks for your information.
> I've tested this patch based on the latest devfreq-testing branch.
> It encounters the same crash as Chen-Yu mentioned[1].
> 
> [1]https://lore.kernel.org/linux-pm/YniX1w+oI1eOCmCx@google.com/T/#u

Hi Johnson,

Thanks for the test. I'll drop the last patch caused of crash.
And I'll send v3 patchset right now.


-- 
Best Regards,
Samsung Electronics
Chanwoo Choi

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  2022-04-25 12:55 ` [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings Johnson Wang
  2022-04-25 17:56   ` Krzysztof Kozlowski
  2022-04-26  3:18   ` Chen-Yu Tsai
@ 2022-05-09 12:09   ` Chanwoo Choi
  2022-05-09 12:43     ` Chanwoo Choi
  2022-05-10  2:59     ` Johnson Wang
  2 siblings, 2 replies; 27+ messages in thread
From: Chanwoo Choi @ 2022-05-09 12:09 UTC (permalink / raw)
  To: Johnson Wang, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

Hi,

On 22. 4. 25. 21:55, Johnson Wang wrote:
> Add devicetree binding of MediaTek CCI on MT8183 and MT8186.
> 
> Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> ---
>   .../bindings/interconnect/mediatek,cci.yaml   | 139 ++++++++++++++++++
>   1 file changed, 139 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> 
> diff --git a/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> new file mode 100644
> index 000000000000..e5221e17d11b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> @@ -0,0 +1,139 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/interconnect/mediatek,cci.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek Cache Coherent Interconnect (CCI) frequency and voltage scaling
> +
> +maintainers:
> +  - Jia-Wei Chang <jia-wei.chang@mediatek.com>

Why did you add your author information?
Please add your author information.

And add this dt-binding information to MAINTAINERS
as following: because I cannot catch the later patch
of modification.

cwchoi00@chanwoo:~/kernel/linux.chanwoo$ d
diff --git a/MAINTAINERS b/MAINTAINERS
index edc96cdb85e8..a11e9c1947b7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5698,6 +5698,7 @@ L:        linux-pm@vger.kernel.org
  S:     Maintained
  T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
  F:     Documentation/devicetree/bindings/devfreq/
+F:     Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
  F:     drivers/devfreq/
  F:     include/linux/devfreq.h
  F:     include/trace/events/devfreq.h


> +
> +description: |
> +  MediaTek Cache Coherent Interconnect (CCI) is a hardware engine used by
> +  MT8183 and MT8186 SoCs to scale the frequency and adjust the voltage in
> +  hardware. It can also optimize the voltage to reduce the power consumption.
> +
> +properties:
> +  compatible:
> +    enum:
> +      - mediatek,mt8183-cci
> +      - mediatek,mt8186-cci
> +
> +  clocks:
> +    items:
> +      - description:
> +          The multiplexer for clock input of CPU cluster.
> +      - description:
> +          A parent of "cpu" clock which is used as an intermediate clock source
> +          when the original CPU is under transition and not stable yet.
> +
> +  clock-names:
> +    items:
> +      - const: cci
> +      - const: intermediate
> +
> +  operating-points-v2: true
> +  opp-table: true
> +
> +  proc-supply:
> +    description:
> +      Phandle of the regulator for CCI that provides the supply voltage.
> +
> +  sram-supply:
> +    description:
> +      Phandle of the regulator for sram of CCI that provides the supply
> +      voltage. When it presents, the cci devfreq driver needs to do
> +      "voltage tracking" to step by step scale up/down Vproc and Vsram to fit
> +      SoC specific needs. When absent, the voltage scaling flow is handled by
> +      hardware, hence no software "voltage tracking" is needed.
> +
> +required:
> +  - compatible
> +  - clocks
> +  - clock-names
> +  - operating-points-v2
> +  - proc-supply
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/mt8183-clk.h>
> +    cci: cci {
> +        compatible = "mediatek,mt8183-cci";
> +        clocks = <&mcucfg CLK_MCU_BUS_SEL>,
> +                 <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
> +        clock-names = "cci", "intermediate";
> +        operating-points-v2 = <&cci_opp>;
> +        proc-supply = <&mt6358_vproc12_reg>;
> +    };
> +
> +    cci_opp: opp-table-cci {
> +        compatible = "operating-points-v2";
> +        opp-shared;
> +        opp2_00: opp-273000000 {
> +            opp-hz = /bits/ 64 <273000000>;
> +            opp-microvolt = <650000>;
> +        };
> +        opp2_01: opp-338000000 {
> +            opp-hz = /bits/ 64 <338000000>;
> +            opp-microvolt = <687500>;
> +        };
> +        opp2_02: opp-403000000 {
> +            opp-hz = /bits/ 64 <403000000>;
> +            opp-microvolt = <718750>;
> +        };
> +        opp2_03: opp-463000000 {
> +            opp-hz = /bits/ 64 <463000000>;
> +            opp-microvolt = <756250>;
> +        };
> +        opp2_04: opp-546000000 {
> +            opp-hz = /bits/ 64 <546000000>;
> +            opp-microvolt = <800000>;
> +        };
> +        opp2_05: opp-624000000 {
> +            opp-hz = /bits/ 64 <624000000>;
> +            opp-microvolt = <818750>;
> +        };
> +        opp2_06: opp-689000000 {
> +            opp-hz = /bits/ 64 <689000000>;
> +            opp-microvolt = <850000>;
> +        };
> +        opp2_07: opp-767000000 {
> +            opp-hz = /bits/ 64 <767000000>;
> +            opp-microvolt = <868750>;
> +        };
> +        opp2_08: opp-845000000 {
> +            opp-hz = /bits/ 64 <845000000>;
> +            opp-microvolt = <893750>;
> +        };
> +        opp2_09: opp-871000000 {
> +            opp-hz = /bits/ 64 <871000000>;
> +            opp-microvolt = <906250>;
> +        };
> +        opp2_10: opp-923000000 {
> +            opp-hz = /bits/ 64 <923000000>;
> +            opp-microvolt = <931250>;
> +        };
> +        opp2_11: opp-962000000 {
> +            opp-hz = /bits/ 64 <962000000>;
> +            opp-microvolt = <943750>;
> +        };
> +        opp2_12: opp-1027000000 {
> +            opp-hz = /bits/ 64 <1027000000>;
> +            opp-microvolt = <975000>;
> +        };
> +        opp2_13: opp-1092000000 {
> +            opp-hz = /bits/ 64 <1092000000>;
> +            opp-microvolt = <1000000>;
> +        };
> +        opp2_14: opp-1144000000 {
> +            opp-hz = /bits/ 64 <1144000000>;
> +            opp-microvolt = <1025000>;
> +        };
> +        opp2_15: opp-1196000000 {
> +            opp-hz = /bits/ 64 <1196000000>;
> +            opp-microvolt = <1050000>;
> +        };
> +    };


-- 
Best Regards,
Samsung Electronics
Chanwoo Choi

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  2022-04-26  3:18   ` Chen-Yu Tsai
@ 2022-05-09 12:14     ` Johnson Wang
  2022-05-11 10:48       ` Chen-Yu Tsai
  0 siblings, 1 reply; 27+ messages in thread
From: Johnson Wang @ 2022-05-09 12:14 UTC (permalink / raw)
  To: Chen-Yu Tsai, krzk+dt
  Cc: cw00.choi, robh+dt, kyungmin.park, khilman, linux-pm,
	linux-kernel, devicetree, linux-arm-kernel, linux-mediatek,
	jia-wei.chang, Project_Global_Chrome_Upstream_Group

Hi Chen-Yu,

On Tue, 2022-04-26 at 11:18 +0800, Chen-Yu Tsai wrote:
> On Mon, Apr 25, 2022 at 8:56 PM Johnson Wang <
> johnson.wang@mediatek.com> wrote:
> > 
> > Add devicetree binding of MediaTek CCI on MT8183 and MT8186.
> > 
> > Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> > Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > ---
> >  .../bindings/interconnect/mediatek,cci.yaml   | 139
> > ++++++++++++++++++
> >  1 file changed, 139 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > 
> > diff --git
> > a/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > new file mode 100644
> > index 000000000000..e5221e17d11b
> > --- /dev/null
> > +++
> > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > @@ -0,0 +1,139 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: 
> > https://urldefense.com/v3/__http://devicetree.org/schemas/interconnect/mediatek,cci.yaml*__;Iw!!CTRNKA9wMg0ARbw!zuufEcqpKbditY3eqLTHpL8P8humMCyh4D4QWsximmw124tJUPE3ZBUyBqBtDlQ9pSDO$
> >  
> > +$schema: 
> > https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!zuufEcqpKbditY3eqLTHpL8P8humMCyh4D4QWsximmw124tJUPE3ZBUyBqBtDoE9YHyu$
> >  
> > +
> > +title: MediaTek Cache Coherent Interconnect (CCI) frequency and
> > voltage scaling
> > +
> > +maintainers:
> > +  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > +
> > +description: |
> > +  MediaTek Cache Coherent Interconnect (CCI) is a hardware engine
> > used by
> > +  MT8183 and MT8186 SoCs to scale the frequency and adjust the
> > voltage in
> > +  hardware. It can also optimize the voltage to reduce the power
> > consumption.
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - mediatek,mt8183-cci
> > +      - mediatek,mt8186-cci
> > +
> > +  clocks:
> > +    items:
> > +      - description:
> > +          The multiplexer for clock input of CPU cluster.
> 
> of the bus, not CPU cluster.

Thanks for your suggestion.
I will correct it in the next version.

> 
> > +      - description:
> > +          A parent of "cpu" clock which is used as an intermediate
> > clock source
> > +          when the original CPU is under transition and not stable
> > yet.
> 
> This really should be handled in the clk controller, and not by every
> device
> that happens to take a clock from a mux with upstream PLLs that can
> change
> in clock rate. The end device hardware only takes one clock input.
> That's it.
> 

To make this intermediate clock works properly, this driver is also
responsible for handling the Vproc voltage and ensures the voltage is
high enough to support intermediate clock rate.

If we move intermediate clock rate control to clock driver, then
intermediate voltage control may be handled by the clock driver itself
as well.

We believe that is not reasonable because clock driver shouldn't handle
voltage control. On the other hand, DVFS driver is more suitable for
doing this job.

> > +
> > +  clock-names:
> > +    items:
> > +      - const: cci
> > +      - const: intermediate
> > +
> > +  operating-points-v2: true
> > +  opp-table: true
> > +
> > +  proc-supply:
> > +    description:
> > +      Phandle of the regulator for CCI that provides the supply
> > voltage.
> > +
> > +  sram-supply:
> > +    description:
> > +      Phandle of the regulator for sram of CCI that provides the
> > supply
> > +      voltage. When it presents, the cci devfreq driver needs to
> > do
> 
> When it is present, the implementation needs to ...
> 
> ChenYu

I will modify it in the next version.

BRs,
Johnson Wang

> 
> > +      "voltage tracking" to step by step scale up/down Vproc and
> > Vsram to fit
> > +      SoC specific needs. When absent, the voltage scaling flow is
> > handled by
> > +      hardware, hence no software "voltage tracking" is needed.
> > +
> > +required:
> > +  - compatible
> > +  - clocks
> > +  - clock-names
> > +  - operating-points-v2
> > +  - proc-supply
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/clock/mt8183-clk.h>
> > +    cci: cci {
> > +        compatible = "mediatek,mt8183-cci";
> > +        clocks = <&mcucfg CLK_MCU_BUS_SEL>,
> > +                 <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
> > +        clock-names = "cci", "intermediate";
> > +        operating-points-v2 = <&cci_opp>;
> > +        proc-supply = <&mt6358_vproc12_reg>;
> > +    };
> > +
> > +    cci_opp: opp-table-cci {
> > +        compatible = "operating-points-v2";
> > +        opp-shared;
> > +        opp2_00: opp-273000000 {
> > +            opp-hz = /bits/ 64 <273000000>;
> > +            opp-microvolt = <650000>;
> > +        };
> > +        opp2_01: opp-338000000 {
> > +            opp-hz = /bits/ 64 <338000000>;
> > +            opp-microvolt = <687500>;
> > +        };
> > +        opp2_02: opp-403000000 {
> > +            opp-hz = /bits/ 64 <403000000>;
> > +            opp-microvolt = <718750>;
> > +        };
> > +        opp2_03: opp-463000000 {
> > +            opp-hz = /bits/ 64 <463000000>;
> > +            opp-microvolt = <756250>;
> > +        };
> > +        opp2_04: opp-546000000 {
> > +            opp-hz = /bits/ 64 <546000000>;
> > +            opp-microvolt = <800000>;
> > +        };
> > +        opp2_05: opp-624000000 {
> > +            opp-hz = /bits/ 64 <624000000>;
> > +            opp-microvolt = <818750>;
> > +        };
> > +        opp2_06: opp-689000000 {
> > +            opp-hz = /bits/ 64 <689000000>;
> > +            opp-microvolt = <850000>;
> > +        };
> > +        opp2_07: opp-767000000 {
> > +            opp-hz = /bits/ 64 <767000000>;
> > +            opp-microvolt = <868750>;
> > +        };
> > +        opp2_08: opp-845000000 {
> > +            opp-hz = /bits/ 64 <845000000>;
> > +            opp-microvolt = <893750>;
> > +        };
> > +        opp2_09: opp-871000000 {
> > +            opp-hz = /bits/ 64 <871000000>;
> > +            opp-microvolt = <906250>;
> > +        };
> > +        opp2_10: opp-923000000 {
> > +            opp-hz = /bits/ 64 <923000000>;
> > +            opp-microvolt = <931250>;
> > +        };
> > +        opp2_11: opp-962000000 {
> > +            opp-hz = /bits/ 64 <962000000>;
> > +            opp-microvolt = <943750>;
> > +        };
> > +        opp2_12: opp-1027000000 {
> > +            opp-hz = /bits/ 64 <1027000000>;
> > +            opp-microvolt = <975000>;
> > +        };
> > +        opp2_13: opp-1092000000 {
> > +            opp-hz = /bits/ 64 <1092000000>;
> > +            opp-microvolt = <1000000>;
> > +        };
> > +        opp2_14: opp-1144000000 {
> > +            opp-hz = /bits/ 64 <1144000000>;
> > +            opp-microvolt = <1025000>;
> > +        };
> > +        opp2_15: opp-1196000000 {
> > +            opp-hz = /bits/ 64 <1196000000>;
> > +            opp-microvolt = <1050000>;
> > +        };
> > +    };
> > --
> > 2.18.0
> > 
> > 
> > _______________________________________________
> > Linux-mediatek mailing list
> > Linux-mediatek@lists.infradead.org
> > 
https://urldefense.com/v3/__http://lists.infradead.org/mailman/listinfo/linux-mediatek__;!!CTRNKA9wMg0ARbw!zuufEcqpKbditY3eqLTHpL8P8humMCyh4D4QWsximmw124tJUPE3ZBUyBqBtDvdNpOFZ$
> >  


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  2022-05-09 12:09   ` Chanwoo Choi
@ 2022-05-09 12:43     ` Chanwoo Choi
  2022-05-10  2:59     ` Johnson Wang
  1 sibling, 0 replies; 27+ messages in thread
From: Chanwoo Choi @ 2022-05-09 12:43 UTC (permalink / raw)
  To: Johnson Wang, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

On 22. 5. 9. 21:09, Chanwoo Choi wrote:
> Hi,
> 
> On 22. 4. 25. 21:55, Johnson Wang wrote:
>> Add devicetree binding of MediaTek CCI on MT8183 and MT8186.
>>
>> Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
>> Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
>> ---
>>   .../bindings/interconnect/mediatek,cci.yaml   | 139 ++++++++++++++++++
>>   1 file changed, 139 insertions(+)
>>   create mode 100644 
>> Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
>>
>> diff --git 
>> a/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml 
>> b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
>> new file mode 100644
>> index 000000000000..e5221e17d11b
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
>> @@ -0,0 +1,139 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/interconnect/mediatek,cci.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: MediaTek Cache Coherent Interconnect (CCI) frequency and 
>> voltage scaling
>> +
>> +maintainers:
>> +  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
> 
> Why did you add your author information?

I'm sorry. I missed 'not' above sentence.
IMHO, please add your author information.

(snip)


-- 
Best Regards,
Samsung Electronics
Chanwoo Choi

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  2022-05-09 12:09   ` Chanwoo Choi
  2022-05-09 12:43     ` Chanwoo Choi
@ 2022-05-10  2:59     ` Johnson Wang
  2022-05-10  4:27       ` Chanwoo Choi
  1 sibling, 1 reply; 27+ messages in thread
From: Johnson Wang @ 2022-05-10  2:59 UTC (permalink / raw)
  To: Chanwoo Choi, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

Hi Chanwoo,

On Mon, 2022-05-09 at 21:09 +0900, Chanwoo Choi wrote:
> Hi,
> 
> On 22. 4. 25. 21:55, Johnson Wang wrote:
> > Add devicetree binding of MediaTek CCI on MT8183 and MT8186.
> > 
> > Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> > Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > ---
> >   .../bindings/interconnect/mediatek,cci.yaml   | 139
> > ++++++++++++++++++
> >   1 file changed, 139 insertions(+)
> >   create mode 100644
> > Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > 
> > diff --git
> > a/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > new file mode 100644
> > index 000000000000..e5221e17d11b
> > --- /dev/null
> > +++
> > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > @@ -0,0 +1,139 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: 
> > https://urldefense.com/v3/__http://devicetree.org/schemas/interconnect/mediatek,cci.yaml*__;Iw!!CTRNKA9wMg0ARbw!z6ogArqzuIzPR3TYO1aW-Z-scpuZJxIriWMofdfnvrKTXAYBBLZeitAPIKyZayMYZGsR$
> >  
> > +$schema: 
> > https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!z6ogArqzuIzPR3TYO1aW-Z-scpuZJxIriWMofdfnvrKTXAYBBLZeitAPIKyZa9f2pALd$
> >  
> > +
> > +title: MediaTek Cache Coherent Interconnect (CCI) frequency and
> > voltage scaling
> > +
> > +maintainers:
> > +  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
> 
> Why did you add your author information?
> Please add your author information.

Sorry, I don't really understand what you mean.
Could you please explain your advice again?

The author of this driver is 'Jia-Wei Chang'.
We have added author information to the driver code and this binding
document as above.

> 
> And add this dt-binding information to MAINTAINERS
> as following: because I cannot catch the later patch
> of modification.
> 
> cwchoi00@chanwoo:~/kernel/linux.chanwoo$ d
> diff --git a/MAINTAINERS b/MAINTAINERS
> index edc96cdb85e8..a11e9c1947b7 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -5698,6 +5698,7 @@ L:        linux-pm@vger.kernel.org
>   S:     Maintained
>   T:     git
> git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
>   F:     Documentation/devicetree/bindings/devfreq/
> +F:     Documentation/devicetree/bindings/interconnect/mediatek,cci.y
> aml
>   F:     drivers/devfreq/
>   F:     include/linux/devfreq.h
>   F:     include/trace/events/devfreq.h
> 

I will add it in the next version.

BRs,
Johnson Wang
> 
> > +
> > +description: |
> > +  MediaTek Cache Coherent Interconnect (CCI) is a hardware engine
> > used by
> > +  MT8183 and MT8186 SoCs to scale the frequency and adjust the
> > voltage in
> > +  hardware. It can also optimize the voltage to reduce the power
> > consumption.
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - mediatek,mt8183-cci
> > +      - mediatek,mt8186-cci
> > +
> > +  clocks:
> > +    items:
> > +      - description:
> > +          The multiplexer for clock input of CPU cluster.
> > +      - description:
> > +          A parent of "cpu" clock which is used as an intermediate
> > clock source
> > +          when the original CPU is under transition and not stable
> > yet.
> > +
> > +  clock-names:
> > +    items:
> > +      - const: cci
> > +      - const: intermediate
> > +
> > +  operating-points-v2: true
> > +  opp-table: true
> > +
> > +  proc-supply:
> > +    description:
> > +      Phandle of the regulator for CCI that provides the supply
> > voltage.
> > +
> > +  sram-supply:
> > +    description:
> > +      Phandle of the regulator for sram of CCI that provides the
> > supply
> > +      voltage. When it presents, the cci devfreq driver needs to
> > do
> > +      "voltage tracking" to step by step scale up/down Vproc and
> > Vsram to fit
> > +      SoC specific needs. When absent, the voltage scaling flow is
> > handled by
> > +      hardware, hence no software "voltage tracking" is needed.
> > +
> > +required:
> > +  - compatible
> > +  - clocks
> > +  - clock-names
> > +  - operating-points-v2
> > +  - proc-supply
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/clock/mt8183-clk.h>
> > +    cci: cci {
> > +        compatible = "mediatek,mt8183-cci";
> > +        clocks = <&mcucfg CLK_MCU_BUS_SEL>,
> > +                 <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
> > +        clock-names = "cci", "intermediate";
> > +        operating-points-v2 = <&cci_opp>;
> > +        proc-supply = <&mt6358_vproc12_reg>;
> > +    };
> > +
> > +    cci_opp: opp-table-cci {
> > +        compatible = "operating-points-v2";
> > +        opp-shared;
> > +        opp2_00: opp-273000000 {
> > +            opp-hz = /bits/ 64 <273000000>;
> > +            opp-microvolt = <650000>;
> > +        };
> > +        opp2_01: opp-338000000 {
> > +            opp-hz = /bits/ 64 <338000000>;
> > +            opp-microvolt = <687500>;
> > +        };
> > +        opp2_02: opp-403000000 {
> > +            opp-hz = /bits/ 64 <403000000>;
> > +            opp-microvolt = <718750>;
> > +        };
> > +        opp2_03: opp-463000000 {
> > +            opp-hz = /bits/ 64 <463000000>;
> > +            opp-microvolt = <756250>;
> > +        };
> > +        opp2_04: opp-546000000 {
> > +            opp-hz = /bits/ 64 <546000000>;
> > +            opp-microvolt = <800000>;
> > +        };
> > +        opp2_05: opp-624000000 {
> > +            opp-hz = /bits/ 64 <624000000>;
> > +            opp-microvolt = <818750>;
> > +        };
> > +        opp2_06: opp-689000000 {
> > +            opp-hz = /bits/ 64 <689000000>;
> > +            opp-microvolt = <850000>;
> > +        };
> > +        opp2_07: opp-767000000 {
> > +            opp-hz = /bits/ 64 <767000000>;
> > +            opp-microvolt = <868750>;
> > +        };
> > +        opp2_08: opp-845000000 {
> > +            opp-hz = /bits/ 64 <845000000>;
> > +            opp-microvolt = <893750>;
> > +        };
> > +        opp2_09: opp-871000000 {
> > +            opp-hz = /bits/ 64 <871000000>;
> > +            opp-microvolt = <906250>;
> > +        };
> > +        opp2_10: opp-923000000 {
> > +            opp-hz = /bits/ 64 <923000000>;
> > +            opp-microvolt = <931250>;
> > +        };
> > +        opp2_11: opp-962000000 {
> > +            opp-hz = /bits/ 64 <962000000>;
> > +            opp-microvolt = <943750>;
> > +        };
> > +        opp2_12: opp-1027000000 {
> > +            opp-hz = /bits/ 64 <1027000000>;
> > +            opp-microvolt = <975000>;
> > +        };
> > +        opp2_13: opp-1092000000 {
> > +            opp-hz = /bits/ 64 <1092000000>;
> > +            opp-microvolt = <1000000>;
> > +        };
> > +        opp2_14: opp-1144000000 {
> > +            opp-hz = /bits/ 64 <1144000000>;
> > +            opp-microvolt = <1025000>;
> > +        };
> > +        opp2_15: opp-1196000000 {
> > +            opp-hz = /bits/ 64 <1196000000>;
> > +            opp-microvolt = <1050000>;
> > +        };
> > +    };
> 
> 


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  2022-05-10  2:59     ` Johnson Wang
@ 2022-05-10  4:27       ` Chanwoo Choi
  0 siblings, 0 replies; 27+ messages in thread
From: Chanwoo Choi @ 2022-05-10  4:27 UTC (permalink / raw)
  To: Johnson Wang
  Cc: Chanwoo Choi, krzk+dt, Rob Herring, Kyungmin Park, Kevin Hilman,
	Linux PM list, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

On Tue, May 10, 2022 at 11:59 AM Johnson Wang <johnson.wang@mediatek.com> wrote:
>
> Hi Chanwoo,
>
> On Mon, 2022-05-09 at 21:09 +0900, Chanwoo Choi wrote:
> > Hi,
> >
> > On 22. 4. 25. 21:55, Johnson Wang wrote:
> > > Add devicetree binding of MediaTek CCI on MT8183 and MT8186.
> > >
> > > Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> > > Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > > ---
> > >   .../bindings/interconnect/mediatek,cci.yaml   | 139
> > > ++++++++++++++++++
> > >   1 file changed, 139 insertions(+)
> > >   create mode 100644
> > > Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > >
> > > diff --git
> > > a/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > > new file mode 100644
> > > index 000000000000..e5221e17d11b
> > > --- /dev/null
> > > +++
> > > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > > @@ -0,0 +1,139 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id:
> > > https://urldefense.com/v3/__http://devicetree.org/schemas/interconnect/mediatek,cci.yaml*__;Iw!!CTRNKA9wMg0ARbw!z6ogArqzuIzPR3TYO1aW-Z-scpuZJxIriWMofdfnvrKTXAYBBLZeitAPIKyZayMYZGsR$
> > >
> > > +$schema:
> > > https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!z6ogArqzuIzPR3TYO1aW-Z-scpuZJxIriWMofdfnvrKTXAYBBLZeitAPIKyZa9f2pALd$
> > >
> > > +
> > > +title: MediaTek Cache Coherent Interconnect (CCI) frequency and
> > > voltage scaling
> > > +
> > > +maintainers:
> > > +  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
> >
> > Why did you add your author information?
> > Please add your author information.
>
> Sorry, I don't really understand what you mean.
> Could you please explain your advice again?
>
> The author of this driver is 'Jia-Wei Chang'.
> We have added author information to the driver code and this binding
> document as above.

Firstly, sorry for the confusion.

I have discussed this patch with you. I think that you (Johnson Wang)
should be added to 'maintainers' of this binding document as following:

+maintainers:
+  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
+  - Johnson Wang <johnson.wang@mediatek.com>

>
> >
> > And add this dt-binding information to MAINTAINERS
> > as following: because I cannot catch the later patch
> > of modification.
> >
> > cwchoi00@chanwoo:~/kernel/linux.chanwoo$ d
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index edc96cdb85e8..a11e9c1947b7 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -5698,6 +5698,7 @@ L:        linux-pm@vger.kernel.org
> >   S:     Maintained
> >   T:     git
> > git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
> >   F:     Documentation/devicetree/bindings/devfreq/
> > +F:     Documentation/devicetree/bindings/interconnect/mediatek,cci.y
> > aml
> >   F:     drivers/devfreq/
> >   F:     include/linux/devfreq.h
> >   F:     include/trace/events/devfreq.h
> >
>
> I will add it in the next version.
>
> BRs,
> Johnson Wang
> >
> > > +
> > > +description: |
> > > +  MediaTek Cache Coherent Interconnect (CCI) is a hardware engine
> > > used by
> > > +  MT8183 and MT8186 SoCs to scale the frequency and adjust the
> > > voltage in
> > > +  hardware. It can also optimize the voltage to reduce the power
> > > consumption.
> > > +
> > > +properties:
> > > +  compatible:
> > > +    enum:
> > > +      - mediatek,mt8183-cci
> > > +      - mediatek,mt8186-cci
> > > +
> > > +  clocks:
> > > +    items:
> > > +      - description:
> > > +          The multiplexer for clock input of CPU cluster.
> > > +      - description:
> > > +          A parent of "cpu" clock which is used as an intermediate
> > > clock source
> > > +          when the original CPU is under transition and not stable
> > > yet.
> > > +
> > > +  clock-names:
> > > +    items:
> > > +      - const: cci
> > > +      - const: intermediate
> > > +
> > > +  operating-points-v2: true
> > > +  opp-table: true
> > > +
> > > +  proc-supply:
> > > +    description:
> > > +      Phandle of the regulator for CCI that provides the supply
> > > voltage.
> > > +
> > > +  sram-supply:
> > > +    description:
> > > +      Phandle of the regulator for sram of CCI that provides the
> > > supply
> > > +      voltage. When it presents, the cci devfreq driver needs to
> > > do
> > > +      "voltage tracking" to step by step scale up/down Vproc and
> > > Vsram to fit
> > > +      SoC specific needs. When absent, the voltage scaling flow is
> > > handled by
> > > +      hardware, hence no software "voltage tracking" is needed.
> > > +
> > > +required:
> > > +  - compatible
> > > +  - clocks
> > > +  - clock-names
> > > +  - operating-points-v2
> > > +  - proc-supply
> > > +
> > > +additionalProperties: false
> > > +
> > > +examples:
> > > +  - |
> > > +    #include <dt-bindings/clock/mt8183-clk.h>
> > > +    cci: cci {
> > > +        compatible = "mediatek,mt8183-cci";
> > > +        clocks = <&mcucfg CLK_MCU_BUS_SEL>,
> > > +                 <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
> > > +        clock-names = "cci", "intermediate";
> > > +        operating-points-v2 = <&cci_opp>;
> > > +        proc-supply = <&mt6358_vproc12_reg>;
> > > +    };
> > > +
> > > +    cci_opp: opp-table-cci {
> > > +        compatible = "operating-points-v2";
> > > +        opp-shared;
> > > +        opp2_00: opp-273000000 {
> > > +            opp-hz = /bits/ 64 <273000000>;
> > > +            opp-microvolt = <650000>;
> > > +        };
> > > +        opp2_01: opp-338000000 {
> > > +            opp-hz = /bits/ 64 <338000000>;
> > > +            opp-microvolt = <687500>;
> > > +        };
> > > +        opp2_02: opp-403000000 {
> > > +            opp-hz = /bits/ 64 <403000000>;
> > > +            opp-microvolt = <718750>;
> > > +        };
> > > +        opp2_03: opp-463000000 {
> > > +            opp-hz = /bits/ 64 <463000000>;
> > > +            opp-microvolt = <756250>;
> > > +        };
> > > +        opp2_04: opp-546000000 {
> > > +            opp-hz = /bits/ 64 <546000000>;
> > > +            opp-microvolt = <800000>;
> > > +        };
> > > +        opp2_05: opp-624000000 {
> > > +            opp-hz = /bits/ 64 <624000000>;
> > > +            opp-microvolt = <818750>;
> > > +        };
> > > +        opp2_06: opp-689000000 {
> > > +            opp-hz = /bits/ 64 <689000000>;
> > > +            opp-microvolt = <850000>;
> > > +        };
> > > +        opp2_07: opp-767000000 {
> > > +            opp-hz = /bits/ 64 <767000000>;
> > > +            opp-microvolt = <868750>;
> > > +        };
> > > +        opp2_08: opp-845000000 {
> > > +            opp-hz = /bits/ 64 <845000000>;
> > > +            opp-microvolt = <893750>;
> > > +        };
> > > +        opp2_09: opp-871000000 {
> > > +            opp-hz = /bits/ 64 <871000000>;
> > > +            opp-microvolt = <906250>;
> > > +        };
> > > +        opp2_10: opp-923000000 {
> > > +            opp-hz = /bits/ 64 <923000000>;
> > > +            opp-microvolt = <931250>;
> > > +        };
> > > +        opp2_11: opp-962000000 {
> > > +            opp-hz = /bits/ 64 <962000000>;
> > > +            opp-microvolt = <943750>;
> > > +        };
> > > +        opp2_12: opp-1027000000 {
> > > +            opp-hz = /bits/ 64 <1027000000>;
> > > +            opp-microvolt = <975000>;
> > > +        };
> > > +        opp2_13: opp-1092000000 {
> > > +            opp-hz = /bits/ 64 <1092000000>;
> > > +            opp-microvolt = <1000000>;
> > > +        };
> > > +        opp2_14: opp-1144000000 {
> > > +            opp-hz = /bits/ 64 <1144000000>;
> > > +            opp-microvolt = <1025000>;
> > > +        };
> > > +        opp2_15: opp-1196000000 {
> > > +            opp-hz = /bits/ 64 <1196000000>;
> > > +            opp-microvolt = <1050000>;
> > > +        };
> > > +    };
> >
> >
>


-- 
Best Regards,
Chanwoo Choi

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-05-09 11:51         ` Chanwoo Choi
@ 2022-05-11  5:14           ` Johnson Wang
  2022-05-11  7:08             ` Chanwoo Choi
  0 siblings, 1 reply; 27+ messages in thread
From: Johnson Wang @ 2022-05-11  5:14 UTC (permalink / raw)
  To: Chanwoo Choi, cw00.choi, krzk+dt, robh+dt, kyungmin.park
  Cc: khilman, linux-pm, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

On Mon, 2022-05-09 at 20:51 +0900, Chanwoo Choi wrote:
> On 22. 5. 9. 14:57, Johnson Wang wrote:
> > On Sat, 2022-05-07 at 22:53 +0900, Chanwoo Choi wrote:
> > > On 22. 5. 6. 20:38, Johnson Wang wrote:
> > > > On Mon, 2022-04-25 at 20:55 +0800, Johnson Wang wrote:
> > > > > We introduce a devfreq driver for the MediaTek Cache Coherent
> > > > > Interconnect
> > > > > (CCI) used by some MediaTek SoCs.
> > > > > 
> > > > > In this driver, we use the passive devfreq driver to get
> > > > > target
> > > > > frequencies
> > > > > and adjust voltages accordingly. In MT8183 and MT8186, the
> > > > > MediaTek
> > > > > CCI
> > > > > is supplied by the same regulators with the little core CPUs.
> > > > > 
> > > > > Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> > > > > Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > > > > ---
> > > > > This patch depends on "devfreq-testing"[1].
> > > > > [1]
> > > > > 
> > 
> > 
https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing__;!!CTRNKA9wMg0ARbw!wnTkI_sh3TsliBPFP70DFwtSZGtKyPinFu9h2BwULWX-xrWF0C21rLV-n1HhstfmLw42$
> > > > >   
> > > > > ---
> > > > >    drivers/devfreq/Kconfig           |  10 +
> > > > >    drivers/devfreq/Makefile          |   1 +
> > > > >    drivers/devfreq/mtk-cci-devfreq.c | 474
> > > > > ++++++++++++++++++++++++++++++
> > > > >    3 files changed, 485 insertions(+)
> > > > >    create mode 100644 drivers/devfreq/mtk-cci-devfreq.c
> > > > > 
> > > > > diff --git a/drivers/devfreq/Kconfig
> > > > > b/drivers/devfreq/Kconfig
> > > > > index 87eb2b837e68..9754d8b31621 100644
> > > > > --- a/drivers/devfreq/Kconfig
> > > > > +++ b/drivers/devfreq/Kconfig
> > > > > @@ -120,6 +120,16 @@ config ARM_TEGRA_DEVFREQ
> > > > >    	  It reads ACTMON counters of memory controllers and
> > > > > adjusts
> > > > > the
> > > > >    	  operating frequencies and voltages with OPP support.
> > > > >    
> > > > > +config ARM_MEDIATEK_CCI_DEVFREQ
> > > > > +	tristate "MEDIATEK CCI DEVFREQ Driver"
> > > > > +	depends on ARM_MEDIATEK_CPUFREQ || COMPILE_TEST
> > > > > +	select DEVFREQ_GOV_PASSIVE
> > > > > +	help
> > > > > +	  This adds a devfreq driver for MediaTek Cache
> > > > > Coherent
> > > > > Interconnect
> > > > > +	  which is shared the same regulators with the cpu
> > > > > cluster. It
> > > > > can track
> > > > > +	  buck voltages and update a proper CCI frequency. Use
> > > > > the
> > > > > notification
> > > > > +	  to get the regulator status.
> > > > > +
> > > > >    config ARM_RK3399_DMC_DEVFREQ
> > > > >    	tristate "ARM RK3399 DMC DEVFREQ Driver"
> > > > >    	depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
> > > > > diff --git a/drivers/devfreq/Makefile
> > > > > b/drivers/devfreq/Makefile
> > > > > index 0b6be92a25d9..bf40d04928d0 100644
> > > > > --- a/drivers/devfreq/Makefile
> > > > > +++ b/drivers/devfreq/Makefile
> > > > > @@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+=
> > > > > governor_passive.o
> > > > >    obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
> > > > >    obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)	+= imx-bus.o
> > > > >    obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)	+= imx8m-ddrc.o
> > > > > +obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ)	+= mtk-cci-
> > > > > devfreq.o
> > > > >    obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)	+= rk3399_dmc.o
> > > > >    obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ)	+= sun8i-a33-
> > > > > mbus.o
> > > > >    obj-$(CONFIG_ARM_TEGRA_DEVFREQ)		+= tegra30-
> > > > > devfreq.o
> > > > > diff --git a/drivers/devfreq/mtk-cci-devfreq.c
> > > > > b/drivers/devfreq/mtk-
> > > > > cci-devfreq.c
> > > > > new file mode 100644
> > > > > index 000000000000..b3e31c45a57c
> > > > > --- /dev/null
> > > > > +++ b/drivers/devfreq/mtk-cci-devfreq.c
> > > > > @@ -0,0 +1,474 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > > +/*
> > > > > + * Copyright (C) 2022 MediaTek Inc.
> > > > > + */
> > > > > +
> > > > > +#include <linux/clk.h>
> > > > > +#include <linux/devfreq.h>
> > > > > +#include <linux/minmax.h>
> > > > > +#include <linux/module.h>
> > > > > +#include <linux/of.h>
> > > > > +#include <linux/of_device.h>
> > > > > +#include <linux/platform_device.h>
> > > > > +#include <linux/pm_opp.h>
> > > > > +#include <linux/regulator/consumer.h>
> > > > > +
> > > > > +struct mtk_ccifreq_platform_data {
> > > > > +	int min_volt_shift;
> > > > > +	int max_volt_shift;
> > > > > +	int proc_max_volt;
> > > > > +	int sram_min_volt;
> > > > > +	int sram_max_volt;
> > > > > +};
> > > > > +
> > > > > +struct mtk_ccifreq_drv {
> > > > > +	struct device *dev;
> > > > > +	struct devfreq *devfreq;
> > > > > +	struct regulator *proc_reg;
> > > > > +	struct regulator *sram_reg;
> > > > > +	struct clk *cci_clk;
> > > > > +	struct clk *inter_clk;
> > > > > +	int inter_voltage;
> > > > > +	int pre_voltage;
> > > > > +	unsigned long pre_freq;
> > > > > +	/* Avoid race condition for regulators between notify
> > > > > and
> > > > > policy */
> > > > > +	struct mutex reg_lock;
> > > > > +	struct notifier_block opp_nb;
> > > > > +	const struct mtk_ccifreq_platform_data *soc_data;
> > > > > +	int vtrack_max;
> > > > > +};
> > > > > +
> > > > > +static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv
> > > > > *drv,
> > > > > int
> > > > > new_voltage)
> > > > > +{
> > > > > +	const struct mtk_ccifreq_platform_data *soc_data = drv-
> > > > > > soc_data;
> > > > > 
> > > > > +	struct device *dev = drv->dev;
> > > > > +	int pre_voltage, pre_vsram, new_vsram, vsram, voltage,
> > > > > ret;
> > > > > +	int retry_max = drv->vtrack_max;
> > > > > +
> > > > > +	if (!drv->sram_reg) {
> > > > > +		ret = regulator_set_voltage(drv->proc_reg,
> > > > > new_voltage,
> > > > > +					    drv->soc_data-
> > > > > > proc_max_volt);
> > > > > 
> > > > > +		goto out_set_voltage;
> > > > > +	}
> > > > > +
> > > > > +	pre_voltage = regulator_get_voltage(drv->proc_reg);
> > > > > +	if (pre_voltage < 0) {
> > > > > +		dev_err(dev, "invalid vproc value: %d\n",
> > > > > pre_voltage);
> > > > > +		return pre_voltage;
> > > > > +	}
> > > > > +
> > > > > +	pre_vsram = regulator_get_voltage(drv->sram_reg);
> > > > > +	if (pre_vsram < 0) {
> > > > > +		dev_err(dev, "invalid vsram value: %d\n",
> > > > > pre_vsram);
> > > > > +		return pre_vsram;
> > > > > +	}
> > > > > +
> > > > > +	new_vsram = clamp(new_voltage + soc_data-
> > > > > >min_volt_shift,
> > > > > +			  soc_data->sram_min_volt, soc_data-
> > > > > > sram_max_volt);
> > > > > 
> > > > > +
> > > > > +	do {
> > > > > +		if (pre_voltage <= new_voltage) {
> > > > > +			vsram = clamp(pre_voltage + soc_data-
> > > > > > max_volt_shift,
> > > > > 
> > > > > +				      soc_data->sram_min_volt,
> > > > > new_vsram);
> > > > > +			ret = regulator_set_voltage(drv-
> > > > > >sram_reg,
> > > > > vsram,
> > > > > +						    soc_data-
> > > > > > sram_max_volt);
> > > > > 
> > > > > +			if (ret)
> > > > > +				return ret;
> > > > > +
> > > > > +			if (vsram == soc_data->sram_max_volt ||
> > > > > +			    new_vsram == soc_data-
> > > > > >sram_min_volt)
> > > > > +				voltage = new_voltage;
> > > > > +			else
> > > > > +				voltage = vsram - soc_data-
> > > > > > min_volt_shift;
> > > > > 
> > > > > +
> > > > > +			ret = regulator_set_voltage(drv-
> > > > > >proc_reg,
> > > > > voltage,
> > > > > +						    soc_data-
> > > > > > proc_max_volt);
> > > > > 
> > > > > +			if (ret) {
> > > > > +				regulator_set_voltage(drv-
> > > > > >sram_reg,
> > > > > pre_vsram,
> > > > > +						      soc_data-
> > > > > > sram_max_volt);
> > > > > 
> > > > > +				return ret;
> > > > > +			}
> > > > > +		} else if (pre_voltage > new_voltage) {
> > > > > +			voltage = max(new_voltage,
> > > > > +				      pre_vsram - soc_data-
> > > > > > max_volt_shift);
> > > > > 
> > > > > +			ret = regulator_set_voltage(drv-
> > > > > >proc_reg,
> > > > > voltage,
> > > > > +						    soc_data-
> > > > > > proc_max_volt);
> > > > > 
> > > > > +			if (ret)
> > > > > +				return ret;
> > > > > +
> > > > > +			if (voltage == new_voltage)
> > > > > +				vsram = new_vsram;
> > > > > +			else
> > > > > +				vsram = max(new_vsram,
> > > > > +					    voltage + soc_data-
> > > > > > min_volt_shift);
> > > > > 
> > > > > +
> > > > > +			ret = regulator_set_voltage(drv-
> > > > > >sram_reg,
> > > > > vsram,
> > > > > +						    soc_data-
> > > > > > sram_max_volt);
> > > > > 
> > > > > +			if (ret) {
> > > > > +				regulator_set_voltage(drv-
> > > > > >proc_reg,
> > > > > pre_voltage,
> > > > > +						      soc_data-
> > > > > > proc_max_volt);
> > > > > 
> > > > > +				return ret;
> > > > > +			}
> > > > > +		}
> > > > > +
> > > > > +		pre_voltage = voltage;
> > > > > +		pre_vsram = vsram;
> > > > > +
> > > > > +		if (--retry_max < 0) {
> > > > > +			dev_err(dev,
> > > > > +				"over loop count, failed to set
> > > > > voltage\n");
> > > > > +			return -EINVAL;
> > > > > +		}
> > > > > +	} while (voltage != new_voltage || vsram != new_vsram);
> > > > > +
> > > > > +out_set_voltage:
> > > > > +	if (!ret)
> > > > > +		drv->pre_voltage = new_voltage;
> > > > > +
> > > > > +	return ret;
> > > > > +}
> > > > > +
> > > > > +static int mtk_ccifreq_target(struct device *dev, unsigned
> > > > > long
> > > > > *freq,
> > > > > +			      u32 flags)
> > > > > +{
> > > > > +	struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev);
> > > > > +	struct clk *cci_pll = clk_get_parent(drv->cci_clk);
> > > > > +	struct dev_pm_opp *opp;
> > > > > +	unsigned long opp_rate;
> > > > > +	int voltage, pre_voltage, inter_voltage,
> > > > > target_voltage, ret;
> > > > > +
> > > > > +	if (!drv)
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	if (drv->pre_freq == *freq)
> > > > > +		return 0;
> > > > > +
> > > > > +	inter_voltage = drv->inter_voltage;
> > > > > +
> > > > > +	opp_rate = *freq;
> > > > > +	opp = devfreq_recommended_opp(dev, &opp_rate, 1);
> > > > > +	if (IS_ERR(opp)) {
> > > > > +		dev_err(dev, "failed to find opp for freq:
> > > > > %ld\n",
> > > > > opp_rate);
> > > > > +		return PTR_ERR(opp);
> > > > > +	}
> > > > > +
> > > > > +	mutex_lock(&drv->reg_lock);
> > > > > +
> > > > > +	voltage = dev_pm_opp_get_voltage(opp);
> > > > > +	dev_pm_opp_put(opp);
> > > > > +
> > > > > +	if (unlikely(drv->pre_voltage <= 0))
> > > > > +		pre_voltage = regulator_get_voltage(drv-
> > > > > >proc_reg);
> > > > > +	else
> > > > > +		pre_voltage = drv->pre_voltage;
> > > > > +
> > > > > +	if (pre_voltage < 0) {
> > > > > +		dev_err(dev, "invalid vproc value: %d\n",
> > > > > pre_voltage);
> > > > > +		return pre_voltage;
> > > > > +	}
> > > > > +
> > > > > +	/* scale up: set voltage first then freq. */
> > > > > +	target_voltage = max(inter_voltage, voltage);
> > > > > +	if (pre_voltage <= target_voltage) {
> > > > > +		ret = mtk_ccifreq_set_voltage(drv,
> > > > > target_voltage);
> > > > > +		if (ret) {
> > > > > +			dev_err(dev, "failed to scale up
> > > > > voltage\n");
> > > > > +			goto out_restore_voltage;
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	/* switch the cci clock to intermediate clock source.
> > > > > */
> > > > > +	ret = clk_set_parent(drv->cci_clk, drv->inter_clk);
> > > > > +	if (ret) {
> > > > > +		dev_err(dev, "failed to re-parent cci
> > > > > clock\n");
> > > > > +		goto out_restore_voltage;
> > > > > +	}
> > > > > +
> > > > > +	/* set the original clock to target rate. */
> > > > > +	ret = clk_set_rate(cci_pll, *freq);
> > > > > +	if (ret) {
> > > > > +		dev_err(dev, "failed to set cci pll rate:
> > > > > %d\n", ret);
> > > > > +		clk_set_parent(drv->cci_clk, cci_pll);
> > > > > +		goto out_restore_voltage;
> > > > > +	}
> > > > > +
> > > > > +	/* switch the cci clock back to the original clock
> > > > > source. */
> > > > > +	ret = clk_set_parent(drv->cci_clk, cci_pll);
> > > > > +	if (ret) {
> > > > > +		dev_err(dev, "failed to re-parent cci
> > > > > clock\n");
> > > > > +		mtk_ccifreq_set_voltage(drv, inter_voltage);
> > > > > +		goto out_unlock;
> > > > > +	}
> > > > > +
> > > > > +	/*
> > > > > +	 * If the new voltage is lower than the intermediate
> > > > > voltage or
> > > > > the
> > > > > +	 * original voltage, scale down to the new voltage.
> > > > > +	 */
> > > > > +	if (voltage < inter_voltage || voltage < pre_voltage) {
> > > > > +		ret = mtk_ccifreq_set_voltage(drv, voltage);
> > > > > +		if (ret) {
> > > > > +			dev_err(dev, "failed to scale down
> > > > > voltage\n");
> > > > > +			goto out_unlock;
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	drv->pre_freq = *freq;
> > > > > +	mutex_unlock(&drv->reg_lock);
> > > > > +
> > > > > +	return 0;
> > > > > +
> > > > > +out_restore_voltage:
> > > > > +	mtk_ccifreq_set_voltage(drv, pre_voltage);
> > > > > +
> > > > > +out_unlock:
> > > > > +	mutex_unlock(&drv->reg_lock);
> > > > > +	return ret;
> > > > > +}
> > > > > +
> > > > > +static int mtk_ccifreq_opp_notifier(struct notifier_block
> > > > > *nb,
> > > > > +				    unsigned long event, void
> > > > > *data)
> > > > > +{
> > > > > +	struct dev_pm_opp *opp = data;
> > > > > +	struct mtk_ccifreq_drv *drv;
> > > > > +	unsigned long freq, volt;
> > > > > +
> > > > > +	drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb);
> > > > > +
> > > > > +	if (event == OPP_EVENT_ADJUST_VOLTAGE) {
> > > > > +		freq = dev_pm_opp_get_freq(opp);
> > > > > +
> > > > > +		mutex_lock(&drv->reg_lock);
> > > > > +		/* current opp item is changed */
> > > > > +		if (freq == drv->pre_freq) {
> > > > > +			volt = dev_pm_opp_get_voltage(opp);
> > > > > +			mtk_ccifreq_set_voltage(drv, volt);
> > > > > +		}
> > > > > +		mutex_unlock(&drv->reg_lock);
> > > > > +	}
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static struct devfreq_dev_profile mtk_ccifreq_profile = {
> > > > > +	.target = mtk_ccifreq_target,
> > > > > +};
> > > > > +
> > > > > +static int mtk_ccifreq_probe(struct platform_device *pdev)
> > > > > +{
> > > > > +	struct device *dev = &pdev->dev;
> > > > > +	struct mtk_ccifreq_drv *drv;
> > > > > +	struct devfreq_passive_data *passive_data;
> > > > > +	struct dev_pm_opp *opp;
> > > > > +	unsigned long rate, opp_volt;
> > > > > +	int ret;
> > > > > +
> > > > > +	drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
> > > > > +	if (!drv)
> > > > > +		return -ENOMEM;
> > > > > +
> > > > > +	drv->dev = dev;
> > > > > +	drv->soc_data = (const struct mtk_ccifreq_platform_data
> > > > > *)
> > > > > +				of_device_get_match_data(&pdev-
> > > > > >dev);
> > > > > +	mutex_init(&drv->reg_lock);
> > > > > +	platform_set_drvdata(pdev, drv);
> > > > > +
> > > > > +	drv->cci_clk = devm_clk_get(dev, "cci");
> > > > > +	if (IS_ERR(drv->cci_clk)) {
> > > > > +		ret = PTR_ERR(drv->cci_clk);
> > > > > +		return dev_err_probe(dev, ret,
> > > > > +				     "failed to get cci clk:
> > > > > %d\n",
> > > > > ret);
> > > > > +	}
> > > > > +
> > > > > +	drv->inter_clk = devm_clk_get(dev, "intermediate");
> > > > > +	if (IS_ERR(drv->inter_clk)) {
> > > > > +		ret = PTR_ERR(drv->inter_clk);
> > > > > +		dev_err_probe(dev, ret,
> > > > > +			      "failed to get intermediate clk:
> > > > > %d\n",
> > > > > ret);
> > > > > +		goto out_free_resources;
> > > > > +	}
> > > > > +
> > > > > +	drv->proc_reg = devm_regulator_get_optional(dev,
> > > > > "proc");
> > > > > +	if (IS_ERR(drv->proc_reg)) {
> > > > > +		ret = PTR_ERR(drv->proc_reg);
> > > > > +		dev_err_probe(dev, ret,
> > > > > +			      "failed to get proc regulator:
> > > > > %d\n",
> > > > > ret);
> > > > > +		goto out_free_resources;
> > > > > +	}
> > > > > +
> > > > > +	ret = regulator_enable(drv->proc_reg);
> > > > > +	if (ret) {
> > > > > +		dev_err(dev, "failed to enable proc
> > > > > regulator\n");
> > > > > +		goto out_free_resources;
> > > > > +	}
> > > > > +
> > > > > +	drv->sram_reg = regulator_get_optional(dev, "sram");
> > > > > +	if (IS_ERR(drv->sram_reg))
> > > > > +		drv->sram_reg = NULL;
> > > > > +	else {
> > > > > +		ret = regulator_enable(drv->sram_reg);
> > > > > +		if (ret) {
> > > > > +			dev_err(dev, "failed to enable sram
> > > > > regulator\n");
> > > > > +			goto out_free_resources;
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	/*
> > > > > +	 * We assume min voltage is 0 and tracking target
> > > > > voltage using
> > > > > +	 * min_volt_shift for each iteration.
> > > > > +	 * The retry_max is 3 times of expeted iteration count.
> > > > > +	 */
> > > > > +	drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data-
> > > > > > sram_max_volt,
> > > > > 
> > > > > +					       drv->soc_data-
> > > > > > proc_max_volt),
> > > > > 
> > > > > +					   drv->soc_data-
> > > > > > min_volt_shift);
> > > > > 
> > > > > +
> > > > > +	ret = clk_prepare_enable(drv->cci_clk);
> > > > > +	if (ret)
> > > > > +		goto out_free_resources;
> > > > > +
> > > > > +	ret = clk_prepare_enable(drv->inter_clk);
> > > > > +	if (ret)
> > > > > +		goto out_disable_cci_clk;
> > > > > +
> > > > > +	ret = dev_pm_opp_of_add_table(dev);
> > > > > +	if (ret) {
> > > > > +		dev_err(dev, "failed to add opp table: %d\n",
> > > > > ret);
> > > > > +		goto out_disable_inter_clk;
> > > > > +	}
> > > > > +
> > > > > +	rate = clk_get_rate(drv->inter_clk);
> > > > > +	opp = dev_pm_opp_find_freq_ceil(dev, &rate);
> > > > > +	if (IS_ERR(opp)) {
> > > > > +		ret = PTR_ERR(opp);
> > > > > +		dev_err(dev, "failed to get intermediate opp:
> > > > > %d\n",
> > > > > ret);
> > > > > +		goto out_remove_opp_table;
> > > > > +	}
> > > > > +	drv->inter_voltage = dev_pm_opp_get_voltage(opp);
> > > > > +	dev_pm_opp_put(opp);
> > > > > +
> > > > > +	rate = U32_MAX;
> > > > > +	opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
> > > > > +	if (IS_ERR(opp)) {
> > > > > +		dev_err(dev, "failed to get opp\n");
> > > > > +		ret = PTR_ERR(opp);
> > > > > +		goto out_remove_opp_table;
> > > > > +	}
> > > > > +
> > > > > +	opp_volt = dev_pm_opp_get_voltage(opp);
> > > > > +	dev_pm_opp_put(opp);
> > > > > +	ret = mtk_ccifreq_set_voltage(drv, opp_volt);
> > > > > +	if (ret) {
> > > > > +		dev_err(dev, "failed to scale to highest
> > > > > voltage %lu in
> > > > > proc_reg\n",
> > > > > +			opp_volt);
> > > > > +		goto out_remove_opp_table;
> > > > > +	}
> > > > > +
> > > > > +	passive_data = devm_kzalloc(dev, sizeof(struct
> > > > > devfreq_passive_data),
> > > > > +				    GFP_KERNEL);
> > > > > +	if (!passive_data) {
> > > > > +		ret = -ENOMEM;
> > > > > +		goto out_remove_opp_table;
> > > > > +	}
> > > > > +
> > > > > +	passive_data->parent_type = CPUFREQ_PARENT_DEV;
> > > > > +	drv->devfreq = devm_devfreq_add_device(dev,
> > > > > &mtk_ccifreq_profile,
> > > > > +					       DEVFREQ_GOV_PASS
> > > > > IVE,
> > > > > +					       passive_data);
> > > > > +	if (IS_ERR(drv->devfreq)) {
> > > > > +		ret = -EPROBE_DEFER;
> > > > > +		dev_err(dev, "failed to add devfreq device:
> > > > > %d\n",
> > > > > +			PTR_ERR(drv->devfreq));
> > > > > +		goto out_remove_opp_table;
> > > > > +	}
> > > > > +
> > > > > +	drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
> > > > > +	ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
> > > > > +	if (ret) {
> > > > > +		dev_err(dev, "failed to register opp notifier:
> > > > > %d\n",
> > > > > ret);
> > > > > +		goto out_remove_devfreq_device;
> > > > > +	}
> > > > > +	return 0;
> > > > > +
> > > > > +out_remove_devfreq_device:
> > > > > +	devm_devfreq_remove_device(dev, drv->devfreq);
> > > > > +
> > > > > +out_remove_opp_table:
> > > > > +	dev_pm_opp_of_remove_table(dev);
> > > > > +
> > > > > +out_disable_inter_clk:
> > > > > +	clk_disable_unprepare(drv->inter_clk);
> > > > > +
> > > > > +out_disable_cci_clk:
> > > > > +	clk_disable_unprepare(drv->cci_clk);
> > > > > +
> > > > > +out_free_resources:
> > > > > +	if (regulator_is_enabled(drv->proc_reg))
> > > > > +		regulator_disable(drv->proc_reg);
> > > > > +	if (drv->sram_reg && regulator_is_enabled(drv-
> > > > > >sram_reg))
> > > > > +		regulator_disable(drv->sram_reg);
> > > > > +
> > > > > +	if (!IS_ERR(drv->proc_reg))
> > > > > +		regulator_put(drv->proc_reg);
> > > > > +	if (!IS_ERR(drv->sram_reg))
> > > > > +		regulator_put(drv->sram_reg);
> > > > > +	if (!IS_ERR(drv->cci_clk))
> > > > > +		clk_put(drv->cci_clk);
> > > > > +	if (!IS_ERR(drv->inter_clk))
> > > > > +		clk_put(drv->inter_clk);
> > > > > +
> > > > > +	return ret;
> > > > > +}
> > > > > +
> > > > > +static int mtk_ccifreq_remove(struct platform_device *pdev)
> > > > > +{
> > > > > +	struct device *dev = &pdev->dev;
> > > > > +	struct mtk_ccifreq_drv *drv;
> > > > > +
> > > > > +	drv = platform_get_drvdata(pdev);
> > > > > +
> > > > > +	dev_pm_opp_unregister_notifier(dev, &drv->opp_nb);
> > > > > +	dev_pm_opp_of_remove_table(dev);
> > > > > +	clk_disable_unprepare(drv->inter_clk);
> > > > > +	clk_disable_unprepare(drv->cci_clk);
> > > > > +	regulator_disable(drv->proc_reg);
> > > > > +	if (drv->sram_reg)
> > > > > +		regulator_disable(drv->sram_reg);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static const struct mtk_ccifreq_platform_data
> > > > > mt8183_platform_data =
> > > > > {
> > > > > +	.min_volt_shift = 100000,
> > > > > +	.max_volt_shift = 200000,
> > > > > +	.proc_max_volt = 1150000,
> > > > > +	.sram_min_volt = 0,
> > > > > +	.sram_max_volt = 1150000,
> > > > > +};
> > > > > +
> > > > > +static const struct mtk_ccifreq_platform_data
> > > > > mt8186_platform_data =
> > > > > {
> > > > > +	.min_volt_shift = 100000,
> > > > > +	.max_volt_shift = 250000,
> > > > > +	.proc_max_volt = 1118750,
> > > > > +	.sram_min_volt = 850000,
> > > > > +	.sram_max_volt = 1118750,
> > > > > +};
> > > > > +
> > > > > +static const struct of_device_id mtk_ccifreq_machines[] = {
> > > > > +	{ .compatible = "mediatek,mt8183-cci", .data =
> > > > > &mt8183_platform_data },
> > > > > +	{ .compatible = "mediatek,mt8186-cci", .data =
> > > > > &mt8186_platform_data },
> > > > > +	{ },
> > > > > +};
> > > > > +MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines);
> > > > > +
> > > > > +static struct platform_driver mtk_ccifreq_platdrv = {
> > > > > +	.probe	= mtk_ccifreq_probe,
> > > > > +	.remove	= mtk_ccifreq_remove,
> > > > > +	.driver = {
> > > > > +		.name = "mtk-ccifreq",
> > > > > +		.of_match_table = mtk_ccifreq_machines,
> > > > > +	},
> > > > > +};
> > > > > +module_platform_driver(mtk_ccifreq_platdrv);
> > > > > +
> > > > > +MODULE_DESCRIPTION("MediaTek CCI devfreq driver");
> > > > > +MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>");
> > > > > +MODULE_LICENSE("GPL v2");
> > > > 
> > > > Hi Chanwoo,
> > > > 
> > > > Just a kindly ping.
> > > > Could you please give me some suggestion on this patch?
> > > > Thanks!
> > > > 
> > > > BRs,
> > > > Johnson Wang
> > > > 
> > > 
> > > Hi Johnson,
> > > 
> > > Sorry for late reply.But I replied it yesterday as following:
> > > Maybe, this reply[1] has not yet arrrived at your mail box.
> > > [1]
> > > 
> > 
> > 
https://lore.kernel.org/lkml/0846a062-2ea2-e6d4-03c8-992c2f2e24a0@gmail.com/T/#m3bc609d805d6e74ec7a105be0511926b4afbbaef
> > > 
> > > As I described on reply[1], I updated the patches on devfreq-
> > > testing
> > > branch. Could you please test your patches based on devfreq-
> > > testing
> > > branch?
> > > 
> > 
> > Hi Chanwoo,
> > 
> > Thanks for your information.
> > I've tested this patch based on the latest devfreq-testing branch.
> > It encounters the same crash as Chen-Yu mentioned[1].
> > 
> > [1]
> > https://lore.kernel.org/linux-pm/YniX1w+oI1eOCmCx@google.com/T/#u
> 
> Hi Johnson,
> 
> Thanks for the test. I'll drop the last patch caused of crash.
> And I'll send v3 patchset right now.
> 
> 

Hi Chanwoo,

With your v3 patchset, this CCI devfreq driver works properly on the
target.
Thanks!

BRs,
Johnson Wang


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  2022-05-11  5:14           ` Johnson Wang
@ 2022-05-11  7:08             ` Chanwoo Choi
  0 siblings, 0 replies; 27+ messages in thread
From: Chanwoo Choi @ 2022-05-11  7:08 UTC (permalink / raw)
  To: Johnson Wang
  Cc: Chanwoo Choi, krzk+dt, Rob Herring, Kyungmin Park, Kevin Hilman,
	Linux PM list, linux-kernel, devicetree, linux-arm-kernel,
	linux-mediatek, jia-wei.chang,
	Project_Global_Chrome_Upstream_Group

On Wed, May 11, 2022 at 2:14 PM Johnson Wang <johnson.wang@mediatek.com> wrote:
>
> On Mon, 2022-05-09 at 20:51 +0900, Chanwoo Choi wrote:
> > On 22. 5. 9. 14:57, Johnson Wang wrote:
> > > On Sat, 2022-05-07 at 22:53 +0900, Chanwoo Choi wrote:
> > > > On 22. 5. 6. 20:38, Johnson Wang wrote:
> > > > > On Mon, 2022-04-25 at 20:55 +0800, Johnson Wang wrote:
> > > > > > We introduce a devfreq driver for the MediaTek Cache Coherent
> > > > > > Interconnect
> > > > > > (CCI) used by some MediaTek SoCs.
> > > > > >
> > > > > > In this driver, we use the passive devfreq driver to get
> > > > > > target
> > > > > > frequencies
> > > > > > and adjust voltages accordingly. In MT8183 and MT8186, the
> > > > > > MediaTek
> > > > > > CCI
> > > > > > is supplied by the same regulators with the little core CPUs.
> > > > > >
> > > > > > Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> > > > > > Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > > > > > ---
> > > > > > This patch depends on "devfreq-testing"[1].
> > > > > > [1]
> > > > > >
> > >
> > >
> https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git/log/?h=devfreq-testing__;!!CTRNKA9wMg0ARbw!wnTkI_sh3TsliBPFP70DFwtSZGtKyPinFu9h2BwULWX-xrWF0C21rLV-n1HhstfmLw42$
> > > > > >
> > > > > > ---
> > > > > >    drivers/devfreq/Kconfig           |  10 +
> > > > > >    drivers/devfreq/Makefile          |   1 +
> > > > > >    drivers/devfreq/mtk-cci-devfreq.c | 474
> > > > > > ++++++++++++++++++++++++++++++
> > > > > >    3 files changed, 485 insertions(+)
> > > > > >    create mode 100644 drivers/devfreq/mtk-cci-devfreq.c
> > > > > >
> > > > > > diff --git a/drivers/devfreq/Kconfig
> > > > > > b/drivers/devfreq/Kconfig
> > > > > > index 87eb2b837e68..9754d8b31621 100644
> > > > > > --- a/drivers/devfreq/Kconfig
> > > > > > +++ b/drivers/devfreq/Kconfig
> > > > > > @@ -120,6 +120,16 @@ config ARM_TEGRA_DEVFREQ
> > > > > >         It reads ACTMON counters of memory controllers and
> > > > > > adjusts
> > > > > > the
> > > > > >         operating frequencies and voltages with OPP support.
> > > > > >
> > > > > > +config ARM_MEDIATEK_CCI_DEVFREQ
> > > > > > +     tristate "MEDIATEK CCI DEVFREQ Driver"
> > > > > > +     depends on ARM_MEDIATEK_CPUFREQ || COMPILE_TEST
> > > > > > +     select DEVFREQ_GOV_PASSIVE
> > > > > > +     help
> > > > > > +       This adds a devfreq driver for MediaTek Cache
> > > > > > Coherent
> > > > > > Interconnect
> > > > > > +       which is shared the same regulators with the cpu
> > > > > > cluster. It
> > > > > > can track
> > > > > > +       buck voltages and update a proper CCI frequency. Use
> > > > > > the
> > > > > > notification
> > > > > > +       to get the regulator status.
> > > > > > +
> > > > > >    config ARM_RK3399_DMC_DEVFREQ
> > > > > >       tristate "ARM RK3399 DMC DEVFREQ Driver"
> > > > > >       depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
> > > > > > diff --git a/drivers/devfreq/Makefile
> > > > > > b/drivers/devfreq/Makefile
> > > > > > index 0b6be92a25d9..bf40d04928d0 100644
> > > > > > --- a/drivers/devfreq/Makefile
> > > > > > +++ b/drivers/devfreq/Makefile
> > > > > > @@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)   +=
> > > > > > governor_passive.o
> > > > > >    obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)       += exynos-bus.o
> > > > > >    obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)  += imx-bus.o
> > > > > >    obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)       += imx8m-ddrc.o
> > > > > > +obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ)       += mtk-cci-
> > > > > > devfreq.o
> > > > > >    obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)       += rk3399_dmc.o
> > > > > >    obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ)   += sun8i-a33-
> > > > > > mbus.o
> > > > > >    obj-$(CONFIG_ARM_TEGRA_DEVFREQ)            += tegra30-
> > > > > > devfreq.o
> > > > > > diff --git a/drivers/devfreq/mtk-cci-devfreq.c
> > > > > > b/drivers/devfreq/mtk-
> > > > > > cci-devfreq.c
> > > > > > new file mode 100644
> > > > > > index 000000000000..b3e31c45a57c
> > > > > > --- /dev/null
> > > > > > +++ b/drivers/devfreq/mtk-cci-devfreq.c
> > > > > > @@ -0,0 +1,474 @@
> > > > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > > > +/*
> > > > > > + * Copyright (C) 2022 MediaTek Inc.
> > > > > > + */
> > > > > > +
> > > > > > +#include <linux/clk.h>
> > > > > > +#include <linux/devfreq.h>
> > > > > > +#include <linux/minmax.h>
> > > > > > +#include <linux/module.h>
> > > > > > +#include <linux/of.h>
> > > > > > +#include <linux/of_device.h>
> > > > > > +#include <linux/platform_device.h>
> > > > > > +#include <linux/pm_opp.h>
> > > > > > +#include <linux/regulator/consumer.h>
> > > > > > +
> > > > > > +struct mtk_ccifreq_platform_data {
> > > > > > +     int min_volt_shift;
> > > > > > +     int max_volt_shift;
> > > > > > +     int proc_max_volt;
> > > > > > +     int sram_min_volt;
> > > > > > +     int sram_max_volt;
> > > > > > +};
> > > > > > +
> > > > > > +struct mtk_ccifreq_drv {
> > > > > > +     struct device *dev;
> > > > > > +     struct devfreq *devfreq;
> > > > > > +     struct regulator *proc_reg;
> > > > > > +     struct regulator *sram_reg;
> > > > > > +     struct clk *cci_clk;
> > > > > > +     struct clk *inter_clk;
> > > > > > +     int inter_voltage;
> > > > > > +     int pre_voltage;
> > > > > > +     unsigned long pre_freq;
> > > > > > +     /* Avoid race condition for regulators between notify
> > > > > > and
> > > > > > policy */
> > > > > > +     struct mutex reg_lock;
> > > > > > +     struct notifier_block opp_nb;
> > > > > > +     const struct mtk_ccifreq_platform_data *soc_data;
> > > > > > +     int vtrack_max;
> > > > > > +};
> > > > > > +
> > > > > > +static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv
> > > > > > *drv,
> > > > > > int
> > > > > > new_voltage)
> > > > > > +{
> > > > > > +     const struct mtk_ccifreq_platform_data *soc_data = drv-
> > > > > > > soc_data;
> > > > > >
> > > > > > +     struct device *dev = drv->dev;
> > > > > > +     int pre_voltage, pre_vsram, new_vsram, vsram, voltage,
> > > > > > ret;
> > > > > > +     int retry_max = drv->vtrack_max;
> > > > > > +
> > > > > > +     if (!drv->sram_reg) {
> > > > > > +             ret = regulator_set_voltage(drv->proc_reg,
> > > > > > new_voltage,
> > > > > > +                                         drv->soc_data-
> > > > > > > proc_max_volt);
> > > > > >
> > > > > > +             goto out_set_voltage;
> > > > > > +     }
> > > > > > +
> > > > > > +     pre_voltage = regulator_get_voltage(drv->proc_reg);
> > > > > > +     if (pre_voltage < 0) {
> > > > > > +             dev_err(dev, "invalid vproc value: %d\n",
> > > > > > pre_voltage);
> > > > > > +             return pre_voltage;
> > > > > > +     }
> > > > > > +
> > > > > > +     pre_vsram = regulator_get_voltage(drv->sram_reg);
> > > > > > +     if (pre_vsram < 0) {
> > > > > > +             dev_err(dev, "invalid vsram value: %d\n",
> > > > > > pre_vsram);
> > > > > > +             return pre_vsram;
> > > > > > +     }
> > > > > > +
> > > > > > +     new_vsram = clamp(new_voltage + soc_data-
> > > > > > >min_volt_shift,
> > > > > > +                       soc_data->sram_min_volt, soc_data-
> > > > > > > sram_max_volt);
> > > > > >
> > > > > > +
> > > > > > +     do {
> > > > > > +             if (pre_voltage <= new_voltage) {
> > > > > > +                     vsram = clamp(pre_voltage + soc_data-
> > > > > > > max_volt_shift,
> > > > > >
> > > > > > +                                   soc_data->sram_min_volt,
> > > > > > new_vsram);
> > > > > > +                     ret = regulator_set_voltage(drv-
> > > > > > >sram_reg,
> > > > > > vsram,
> > > > > > +                                                 soc_data-
> > > > > > > sram_max_volt);
> > > > > >
> > > > > > +                     if (ret)
> > > > > > +                             return ret;
> > > > > > +
> > > > > > +                     if (vsram == soc_data->sram_max_volt ||
> > > > > > +                         new_vsram == soc_data-
> > > > > > >sram_min_volt)
> > > > > > +                             voltage = new_voltage;
> > > > > > +                     else
> > > > > > +                             voltage = vsram - soc_data-
> > > > > > > min_volt_shift;
> > > > > >
> > > > > > +
> > > > > > +                     ret = regulator_set_voltage(drv-
> > > > > > >proc_reg,
> > > > > > voltage,
> > > > > > +                                                 soc_data-
> > > > > > > proc_max_volt);
> > > > > >
> > > > > > +                     if (ret) {
> > > > > > +                             regulator_set_voltage(drv-
> > > > > > >sram_reg,
> > > > > > pre_vsram,
> > > > > > +                                                   soc_data-
> > > > > > > sram_max_volt);
> > > > > >
> > > > > > +                             return ret;
> > > > > > +                     }
> > > > > > +             } else if (pre_voltage > new_voltage) {
> > > > > > +                     voltage = max(new_voltage,
> > > > > > +                                   pre_vsram - soc_data-
> > > > > > > max_volt_shift);
> > > > > >
> > > > > > +                     ret = regulator_set_voltage(drv-
> > > > > > >proc_reg,
> > > > > > voltage,
> > > > > > +                                                 soc_data-
> > > > > > > proc_max_volt);
> > > > > >
> > > > > > +                     if (ret)
> > > > > > +                             return ret;
> > > > > > +
> > > > > > +                     if (voltage == new_voltage)
> > > > > > +                             vsram = new_vsram;
> > > > > > +                     else
> > > > > > +                             vsram = max(new_vsram,
> > > > > > +                                         voltage + soc_data-
> > > > > > > min_volt_shift);
> > > > > >
> > > > > > +
> > > > > > +                     ret = regulator_set_voltage(drv-
> > > > > > >sram_reg,
> > > > > > vsram,
> > > > > > +                                                 soc_data-
> > > > > > > sram_max_volt);
> > > > > >
> > > > > > +                     if (ret) {
> > > > > > +                             regulator_set_voltage(drv-
> > > > > > >proc_reg,
> > > > > > pre_voltage,
> > > > > > +                                                   soc_data-
> > > > > > > proc_max_volt);
> > > > > >
> > > > > > +                             return ret;
> > > > > > +                     }
> > > > > > +             }
> > > > > > +
> > > > > > +             pre_voltage = voltage;
> > > > > > +             pre_vsram = vsram;
> > > > > > +
> > > > > > +             if (--retry_max < 0) {
> > > > > > +                     dev_err(dev,
> > > > > > +                             "over loop count, failed to set
> > > > > > voltage\n");
> > > > > > +                     return -EINVAL;
> > > > > > +             }
> > > > > > +     } while (voltage != new_voltage || vsram != new_vsram);
> > > > > > +
> > > > > > +out_set_voltage:
> > > > > > +     if (!ret)
> > > > > > +             drv->pre_voltage = new_voltage;
> > > > > > +
> > > > > > +     return ret;
> > > > > > +}
> > > > > > +
> > > > > > +static int mtk_ccifreq_target(struct device *dev, unsigned
> > > > > > long
> > > > > > *freq,
> > > > > > +                           u32 flags)
> > > > > > +{
> > > > > > +     struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev);
> > > > > > +     struct clk *cci_pll = clk_get_parent(drv->cci_clk);
> > > > > > +     struct dev_pm_opp *opp;
> > > > > > +     unsigned long opp_rate;
> > > > > > +     int voltage, pre_voltage, inter_voltage,
> > > > > > target_voltage, ret;
> > > > > > +
> > > > > > +     if (!drv)
> > > > > > +             return -EINVAL;
> > > > > > +
> > > > > > +     if (drv->pre_freq == *freq)
> > > > > > +             return 0;
> > > > > > +
> > > > > > +     inter_voltage = drv->inter_voltage;
> > > > > > +
> > > > > > +     opp_rate = *freq;
> > > > > > +     opp = devfreq_recommended_opp(dev, &opp_rate, 1);
> > > > > > +     if (IS_ERR(opp)) {
> > > > > > +             dev_err(dev, "failed to find opp for freq:
> > > > > > %ld\n",
> > > > > > opp_rate);
> > > > > > +             return PTR_ERR(opp);
> > > > > > +     }
> > > > > > +
> > > > > > +     mutex_lock(&drv->reg_lock);
> > > > > > +
> > > > > > +     voltage = dev_pm_opp_get_voltage(opp);
> > > > > > +     dev_pm_opp_put(opp);
> > > > > > +
> > > > > > +     if (unlikely(drv->pre_voltage <= 0))
> > > > > > +             pre_voltage = regulator_get_voltage(drv-
> > > > > > >proc_reg);
> > > > > > +     else
> > > > > > +             pre_voltage = drv->pre_voltage;
> > > > > > +
> > > > > > +     if (pre_voltage < 0) {
> > > > > > +             dev_err(dev, "invalid vproc value: %d\n",
> > > > > > pre_voltage);
> > > > > > +             return pre_voltage;
> > > > > > +     }
> > > > > > +
> > > > > > +     /* scale up: set voltage first then freq. */
> > > > > > +     target_voltage = max(inter_voltage, voltage);
> > > > > > +     if (pre_voltage <= target_voltage) {
> > > > > > +             ret = mtk_ccifreq_set_voltage(drv,
> > > > > > target_voltage);
> > > > > > +             if (ret) {
> > > > > > +                     dev_err(dev, "failed to scale up
> > > > > > voltage\n");
> > > > > > +                     goto out_restore_voltage;
> > > > > > +             }
> > > > > > +     }
> > > > > > +
> > > > > > +     /* switch the cci clock to intermediate clock source.
> > > > > > */
> > > > > > +     ret = clk_set_parent(drv->cci_clk, drv->inter_clk);
> > > > > > +     if (ret) {
> > > > > > +             dev_err(dev, "failed to re-parent cci
> > > > > > clock\n");
> > > > > > +             goto out_restore_voltage;
> > > > > > +     }
> > > > > > +
> > > > > > +     /* set the original clock to target rate. */
> > > > > > +     ret = clk_set_rate(cci_pll, *freq);
> > > > > > +     if (ret) {
> > > > > > +             dev_err(dev, "failed to set cci pll rate:
> > > > > > %d\n", ret);
> > > > > > +             clk_set_parent(drv->cci_clk, cci_pll);
> > > > > > +             goto out_restore_voltage;
> > > > > > +     }
> > > > > > +
> > > > > > +     /* switch the cci clock back to the original clock
> > > > > > source. */
> > > > > > +     ret = clk_set_parent(drv->cci_clk, cci_pll);
> > > > > > +     if (ret) {
> > > > > > +             dev_err(dev, "failed to re-parent cci
> > > > > > clock\n");
> > > > > > +             mtk_ccifreq_set_voltage(drv, inter_voltage);
> > > > > > +             goto out_unlock;
> > > > > > +     }
> > > > > > +
> > > > > > +     /*
> > > > > > +      * If the new voltage is lower than the intermediate
> > > > > > voltage or
> > > > > > the
> > > > > > +      * original voltage, scale down to the new voltage.
> > > > > > +      */
> > > > > > +     if (voltage < inter_voltage || voltage < pre_voltage) {
> > > > > > +             ret = mtk_ccifreq_set_voltage(drv, voltage);
> > > > > > +             if (ret) {
> > > > > > +                     dev_err(dev, "failed to scale down
> > > > > > voltage\n");
> > > > > > +                     goto out_unlock;
> > > > > > +             }
> > > > > > +     }
> > > > > > +
> > > > > > +     drv->pre_freq = *freq;
> > > > > > +     mutex_unlock(&drv->reg_lock);
> > > > > > +
> > > > > > +     return 0;
> > > > > > +
> > > > > > +out_restore_voltage:
> > > > > > +     mtk_ccifreq_set_voltage(drv, pre_voltage);
> > > > > > +
> > > > > > +out_unlock:
> > > > > > +     mutex_unlock(&drv->reg_lock);
> > > > > > +     return ret;
> > > > > > +}
> > > > > > +
> > > > > > +static int mtk_ccifreq_opp_notifier(struct notifier_block
> > > > > > *nb,
> > > > > > +                                 unsigned long event, void
> > > > > > *data)
> > > > > > +{
> > > > > > +     struct dev_pm_opp *opp = data;
> > > > > > +     struct mtk_ccifreq_drv *drv;
> > > > > > +     unsigned long freq, volt;
> > > > > > +
> > > > > > +     drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb);
> > > > > > +
> > > > > > +     if (event == OPP_EVENT_ADJUST_VOLTAGE) {
> > > > > > +             freq = dev_pm_opp_get_freq(opp);
> > > > > > +
> > > > > > +             mutex_lock(&drv->reg_lock);
> > > > > > +             /* current opp item is changed */
> > > > > > +             if (freq == drv->pre_freq) {
> > > > > > +                     volt = dev_pm_opp_get_voltage(opp);
> > > > > > +                     mtk_ccifreq_set_voltage(drv, volt);
> > > > > > +             }
> > > > > > +             mutex_unlock(&drv->reg_lock);
> > > > > > +     }
> > > > > > +
> > > > > > +     return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static struct devfreq_dev_profile mtk_ccifreq_profile = {
> > > > > > +     .target = mtk_ccifreq_target,
> > > > > > +};
> > > > > > +
> > > > > > +static int mtk_ccifreq_probe(struct platform_device *pdev)
> > > > > > +{
> > > > > > +     struct device *dev = &pdev->dev;
> > > > > > +     struct mtk_ccifreq_drv *drv;
> > > > > > +     struct devfreq_passive_data *passive_data;
> > > > > > +     struct dev_pm_opp *opp;
> > > > > > +     unsigned long rate, opp_volt;
> > > > > > +     int ret;
> > > > > > +
> > > > > > +     drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
> > > > > > +     if (!drv)
> > > > > > +             return -ENOMEM;
> > > > > > +
> > > > > > +     drv->dev = dev;
> > > > > > +     drv->soc_data = (const struct mtk_ccifreq_platform_data
> > > > > > *)
> > > > > > +                             of_device_get_match_data(&pdev-
> > > > > > >dev);
> > > > > > +     mutex_init(&drv->reg_lock);
> > > > > > +     platform_set_drvdata(pdev, drv);
> > > > > > +
> > > > > > +     drv->cci_clk = devm_clk_get(dev, "cci");
> > > > > > +     if (IS_ERR(drv->cci_clk)) {
> > > > > > +             ret = PTR_ERR(drv->cci_clk);
> > > > > > +             return dev_err_probe(dev, ret,
> > > > > > +                                  "failed to get cci clk:
> > > > > > %d\n",
> > > > > > ret);
> > > > > > +     }
> > > > > > +
> > > > > > +     drv->inter_clk = devm_clk_get(dev, "intermediate");
> > > > > > +     if (IS_ERR(drv->inter_clk)) {
> > > > > > +             ret = PTR_ERR(drv->inter_clk);
> > > > > > +             dev_err_probe(dev, ret,
> > > > > > +                           "failed to get intermediate clk:
> > > > > > %d\n",
> > > > > > ret);
> > > > > > +             goto out_free_resources;
> > > > > > +     }
> > > > > > +
> > > > > > +     drv->proc_reg = devm_regulator_get_optional(dev,
> > > > > > "proc");
> > > > > > +     if (IS_ERR(drv->proc_reg)) {
> > > > > > +             ret = PTR_ERR(drv->proc_reg);
> > > > > > +             dev_err_probe(dev, ret,
> > > > > > +                           "failed to get proc regulator:
> > > > > > %d\n",
> > > > > > ret);
> > > > > > +             goto out_free_resources;
> > > > > > +     }
> > > > > > +
> > > > > > +     ret = regulator_enable(drv->proc_reg);
> > > > > > +     if (ret) {
> > > > > > +             dev_err(dev, "failed to enable proc
> > > > > > regulator\n");
> > > > > > +             goto out_free_resources;
> > > > > > +     }
> > > > > > +
> > > > > > +     drv->sram_reg = regulator_get_optional(dev, "sram");
> > > > > > +     if (IS_ERR(drv->sram_reg))
> > > > > > +             drv->sram_reg = NULL;
> > > > > > +     else {
> > > > > > +             ret = regulator_enable(drv->sram_reg);
> > > > > > +             if (ret) {
> > > > > > +                     dev_err(dev, "failed to enable sram
> > > > > > regulator\n");
> > > > > > +                     goto out_free_resources;
> > > > > > +             }
> > > > > > +     }
> > > > > > +
> > > > > > +     /*
> > > > > > +      * We assume min voltage is 0 and tracking target
> > > > > > voltage using
> > > > > > +      * min_volt_shift for each iteration.
> > > > > > +      * The retry_max is 3 times of expeted iteration count.
> > > > > > +      */
> > > > > > +     drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data-
> > > > > > > sram_max_volt,
> > > > > >
> > > > > > +                                            drv->soc_data-
> > > > > > > proc_max_volt),
> > > > > >
> > > > > > +                                        drv->soc_data-
> > > > > > > min_volt_shift);
> > > > > >
> > > > > > +
> > > > > > +     ret = clk_prepare_enable(drv->cci_clk);
> > > > > > +     if (ret)
> > > > > > +             goto out_free_resources;
> > > > > > +
> > > > > > +     ret = clk_prepare_enable(drv->inter_clk);
> > > > > > +     if (ret)
> > > > > > +             goto out_disable_cci_clk;
> > > > > > +
> > > > > > +     ret = dev_pm_opp_of_add_table(dev);
> > > > > > +     if (ret) {
> > > > > > +             dev_err(dev, "failed to add opp table: %d\n",
> > > > > > ret);
> > > > > > +             goto out_disable_inter_clk;
> > > > > > +     }
> > > > > > +
> > > > > > +     rate = clk_get_rate(drv->inter_clk);
> > > > > > +     opp = dev_pm_opp_find_freq_ceil(dev, &rate);
> > > > > > +     if (IS_ERR(opp)) {
> > > > > > +             ret = PTR_ERR(opp);
> > > > > > +             dev_err(dev, "failed to get intermediate opp:
> > > > > > %d\n",
> > > > > > ret);
> > > > > > +             goto out_remove_opp_table;
> > > > > > +     }
> > > > > > +     drv->inter_voltage = dev_pm_opp_get_voltage(opp);
> > > > > > +     dev_pm_opp_put(opp);
> > > > > > +
> > > > > > +     rate = U32_MAX;
> > > > > > +     opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
> > > > > > +     if (IS_ERR(opp)) {
> > > > > > +             dev_err(dev, "failed to get opp\n");
> > > > > > +             ret = PTR_ERR(opp);
> > > > > > +             goto out_remove_opp_table;
> > > > > > +     }
> > > > > > +
> > > > > > +     opp_volt = dev_pm_opp_get_voltage(opp);
> > > > > > +     dev_pm_opp_put(opp);
> > > > > > +     ret = mtk_ccifreq_set_voltage(drv, opp_volt);
> > > > > > +     if (ret) {
> > > > > > +             dev_err(dev, "failed to scale to highest
> > > > > > voltage %lu in
> > > > > > proc_reg\n",
> > > > > > +                     opp_volt);
> > > > > > +             goto out_remove_opp_table;
> > > > > > +     }
> > > > > > +
> > > > > > +     passive_data = devm_kzalloc(dev, sizeof(struct
> > > > > > devfreq_passive_data),
> > > > > > +                                 GFP_KERNEL);
> > > > > > +     if (!passive_data) {
> > > > > > +             ret = -ENOMEM;
> > > > > > +             goto out_remove_opp_table;
> > > > > > +     }
> > > > > > +
> > > > > > +     passive_data->parent_type = CPUFREQ_PARENT_DEV;
> > > > > > +     drv->devfreq = devm_devfreq_add_device(dev,
> > > > > > &mtk_ccifreq_profile,
> > > > > > +                                            DEVFREQ_GOV_PASS
> > > > > > IVE,
> > > > > > +                                            passive_data);
> > > > > > +     if (IS_ERR(drv->devfreq)) {
> > > > > > +             ret = -EPROBE_DEFER;
> > > > > > +             dev_err(dev, "failed to add devfreq device:
> > > > > > %d\n",
> > > > > > +                     PTR_ERR(drv->devfreq));
> > > > > > +             goto out_remove_opp_table;
> > > > > > +     }
> > > > > > +
> > > > > > +     drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
> > > > > > +     ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
> > > > > > +     if (ret) {
> > > > > > +             dev_err(dev, "failed to register opp notifier:
> > > > > > %d\n",
> > > > > > ret);
> > > > > > +             goto out_remove_devfreq_device;
> > > > > > +     }
> > > > > > +     return 0;
> > > > > > +
> > > > > > +out_remove_devfreq_device:
> > > > > > +     devm_devfreq_remove_device(dev, drv->devfreq);
> > > > > > +
> > > > > > +out_remove_opp_table:
> > > > > > +     dev_pm_opp_of_remove_table(dev);
> > > > > > +
> > > > > > +out_disable_inter_clk:
> > > > > > +     clk_disable_unprepare(drv->inter_clk);
> > > > > > +
> > > > > > +out_disable_cci_clk:
> > > > > > +     clk_disable_unprepare(drv->cci_clk);
> > > > > > +
> > > > > > +out_free_resources:
> > > > > > +     if (regulator_is_enabled(drv->proc_reg))
> > > > > > +             regulator_disable(drv->proc_reg);
> > > > > > +     if (drv->sram_reg && regulator_is_enabled(drv-
> > > > > > >sram_reg))
> > > > > > +             regulator_disable(drv->sram_reg);
> > > > > > +
> > > > > > +     if (!IS_ERR(drv->proc_reg))
> > > > > > +             regulator_put(drv->proc_reg);
> > > > > > +     if (!IS_ERR(drv->sram_reg))
> > > > > > +             regulator_put(drv->sram_reg);
> > > > > > +     if (!IS_ERR(drv->cci_clk))
> > > > > > +             clk_put(drv->cci_clk);
> > > > > > +     if (!IS_ERR(drv->inter_clk))
> > > > > > +             clk_put(drv->inter_clk);
> > > > > > +
> > > > > > +     return ret;
> > > > > > +}
> > > > > > +
> > > > > > +static int mtk_ccifreq_remove(struct platform_device *pdev)
> > > > > > +{
> > > > > > +     struct device *dev = &pdev->dev;
> > > > > > +     struct mtk_ccifreq_drv *drv;
> > > > > > +
> > > > > > +     drv = platform_get_drvdata(pdev);
> > > > > > +
> > > > > > +     dev_pm_opp_unregister_notifier(dev, &drv->opp_nb);
> > > > > > +     dev_pm_opp_of_remove_table(dev);
> > > > > > +     clk_disable_unprepare(drv->inter_clk);
> > > > > > +     clk_disable_unprepare(drv->cci_clk);
> > > > > > +     regulator_disable(drv->proc_reg);
> > > > > > +     if (drv->sram_reg)
> > > > > > +             regulator_disable(drv->sram_reg);
> > > > > > +
> > > > > > +     return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static const struct mtk_ccifreq_platform_data
> > > > > > mt8183_platform_data =
> > > > > > {
> > > > > > +     .min_volt_shift = 100000,
> > > > > > +     .max_volt_shift = 200000,
> > > > > > +     .proc_max_volt = 1150000,
> > > > > > +     .sram_min_volt = 0,
> > > > > > +     .sram_max_volt = 1150000,
> > > > > > +};
> > > > > > +
> > > > > > +static const struct mtk_ccifreq_platform_data
> > > > > > mt8186_platform_data =
> > > > > > {
> > > > > > +     .min_volt_shift = 100000,
> > > > > > +     .max_volt_shift = 250000,
> > > > > > +     .proc_max_volt = 1118750,
> > > > > > +     .sram_min_volt = 850000,
> > > > > > +     .sram_max_volt = 1118750,
> > > > > > +};
> > > > > > +
> > > > > > +static const struct of_device_id mtk_ccifreq_machines[] = {
> > > > > > +     { .compatible = "mediatek,mt8183-cci", .data =
> > > > > > &mt8183_platform_data },
> > > > > > +     { .compatible = "mediatek,mt8186-cci", .data =
> > > > > > &mt8186_platform_data },
> > > > > > +     { },
> > > > > > +};
> > > > > > +MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines);
> > > > > > +
> > > > > > +static struct platform_driver mtk_ccifreq_platdrv = {
> > > > > > +     .probe  = mtk_ccifreq_probe,
> > > > > > +     .remove = mtk_ccifreq_remove,
> > > > > > +     .driver = {
> > > > > > +             .name = "mtk-ccifreq",
> > > > > > +             .of_match_table = mtk_ccifreq_machines,
> > > > > > +     },
> > > > > > +};
> > > > > > +module_platform_driver(mtk_ccifreq_platdrv);
> > > > > > +
> > > > > > +MODULE_DESCRIPTION("MediaTek CCI devfreq driver");
> > > > > > +MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>");
> > > > > > +MODULE_LICENSE("GPL v2");
> > > > >
> > > > > Hi Chanwoo,
> > > > >
> > > > > Just a kindly ping.
> > > > > Could you please give me some suggestion on this patch?
> > > > > Thanks!
> > > > >
> > > > > BRs,
> > > > > Johnson Wang
> > > > >
> > > >
> > > > Hi Johnson,
> > > >
> > > > Sorry for late reply.But I replied it yesterday as following:
> > > > Maybe, this reply[1] has not yet arrrived at your mail box.
> > > > [1]
> > > >
> > >
> > >
> https://lore.kernel.org/lkml/0846a062-2ea2-e6d4-03c8-992c2f2e24a0@gmail.com/T/#m3bc609d805d6e74ec7a105be0511926b4afbbaef
> > > >
> > > > As I described on reply[1], I updated the patches on devfreq-
> > > > testing
> > > > branch. Could you please test your patches based on devfreq-
> > > > testing
> > > > branch?
> > > >
> > >
> > > Hi Chanwoo,
> > >
> > > Thanks for your information.
> > > I've tested this patch based on the latest devfreq-testing branch.
> > > It encounters the same crash as Chen-Yu mentioned[1].
> > >
> > > [1]
> > > https://lore.kernel.org/linux-pm/YniX1w+oI1eOCmCx@google.com/T/#u
> >
> > Hi Johnson,
> >
> > Thanks for the test. I'll drop the last patch caused of crash.
> > And I'll send v3 patchset right now.
> >
> >
>
> Hi Chanwoo,
>
> With your v3 patchset, this CCI devfreq driver works properly on the
> target.
> Thanks!

Hi Johnson,

Thanks for the test.
I'll send v4 with a Tested-by tag and some typo fixup And then I'll merge them.
As I know, you will send the next version of mediatek cci driver.
After that, I'll merge your patches. Thanks.

-- 
Best Regards,
Chanwoo Choi

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  2022-05-09 12:14     ` Johnson Wang
@ 2022-05-11 10:48       ` Chen-Yu Tsai
  2022-05-12 13:04         ` Johnson Wang
  0 siblings, 1 reply; 27+ messages in thread
From: Chen-Yu Tsai @ 2022-05-11 10:48 UTC (permalink / raw)
  To: Johnson Wang
  Cc: krzk+dt, cw00.choi, robh+dt, kyungmin.park, khilman, linux-pm,
	linux-kernel, devicetree, linux-arm-kernel, linux-mediatek,
	jia-wei.chang, Project_Global_Chrome_Upstream_Group

On Mon, May 9, 2022 at 8:14 PM Johnson Wang <johnson.wang@mediatek.com> wrote:
>
> Hi Chen-Yu,
>
> On Tue, 2022-04-26 at 11:18 +0800, Chen-Yu Tsai wrote:
> > On Mon, Apr 25, 2022 at 8:56 PM Johnson Wang <
> > johnson.wang@mediatek.com> wrote:
> > >
> > > Add devicetree binding of MediaTek CCI on MT8183 and MT8186.
> > >
> > > Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> > > Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > > ---
> > >  .../bindings/interconnect/mediatek,cci.yaml   | 139
> > > ++++++++++++++++++
> > >  1 file changed, 139 insertions(+)
> > >  create mode 100644
> > > Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > >
> > > diff --git
> > > a/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > > new file mode 100644
> > > index 000000000000..e5221e17d11b
> > > --- /dev/null
> > > +++
> > > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
> > > @@ -0,0 +1,139 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id:
> > > https://urldefense.com/v3/__http://devicetree.org/schemas/interconnect/mediatek,cci.yaml*__;Iw!!CTRNKA9wMg0ARbw!zuufEcqpKbditY3eqLTHpL8P8humMCyh4D4QWsximmw124tJUPE3ZBUyBqBtDlQ9pSDO$
> > >
> > > +$schema:
> > > https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!zuufEcqpKbditY3eqLTHpL8P8humMCyh4D4QWsximmw124tJUPE3ZBUyBqBtDoE9YHyu$
> > >
> > > +
> > > +title: MediaTek Cache Coherent Interconnect (CCI) frequency and
> > > voltage scaling
> > > +
> > > +maintainers:
> > > +  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > > +
> > > +description: |
> > > +  MediaTek Cache Coherent Interconnect (CCI) is a hardware engine
> > > used by
> > > +  MT8183 and MT8186 SoCs to scale the frequency and adjust the
> > > voltage in
> > > +  hardware. It can also optimize the voltage to reduce the power
> > > consumption.
> > > +
> > > +properties:
> > > +  compatible:
> > > +    enum:
> > > +      - mediatek,mt8183-cci
> > > +      - mediatek,mt8186-cci
> > > +
> > > +  clocks:
> > > +    items:
> > > +      - description:
> > > +          The multiplexer for clock input of CPU cluster.
> >
> > of the bus, not CPU cluster.
>
> Thanks for your suggestion.
> I will correct it in the next version.
>
> >
> > > +      - description:
> > > +          A parent of "cpu" clock which is used as an intermediate
> > > clock source
> > > +          when the original CPU is under transition and not stable
> > > yet.
> >
> > This really should be handled in the clk controller, and not by every
> > device
> > that happens to take a clock from a mux with upstream PLLs that can
> > change
> > in clock rate. The end device hardware only takes one clock input.
> > That's it.
> >
>
> To make this intermediate clock works properly, this driver is also
> responsible for handling the Vproc voltage and ensures the voltage is
> high enough to support intermediate clock rate.
>
> If we move intermediate clock rate control to clock driver, then
> intermediate voltage control may be handled by the clock driver itself
> as well.
>
> We believe that is not reasonable because clock driver shouldn't handle
> voltage control. On the other hand, DVFS driver is more suitable for
> doing this job.

Either way the DVFS driver handles the voltage change.

Right now the driver is doing:

1. Raise voltage if scaling up
2. Mux CCI clock over to stable clock
3. Set rate for CCI PLL
4. Mux CCI clock back to CCI PLL
5. Drop voltage if scaling down

I'm saying that the clock driver should handle 2+4 transparently when any
driver requests a rate change on the CCI clock. So instead the driver would
do:

1. Raise voltage if scaling up
2. Set rate for CCI _clock_
   Here the clock driver would do:
   a. Mux CCI clock over to stable clock
   b. Change clock rate for original parent, i.e. the CCI PLL
   c. Mux CCI clock back to original parent, i.e. the CCI PLL
   and back to the devfreq driver ...
3. Drop voltage if scaling down

Does that make sense?


Regards
ChenYu

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  2022-05-11 10:48       ` Chen-Yu Tsai
@ 2022-05-12 13:04         ` Johnson Wang
  2022-05-13  3:31           ` Chen-Yu Tsai
  0 siblings, 1 reply; 27+ messages in thread
From: Johnson Wang @ 2022-05-12 13:04 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: krzk+dt, cw00.choi, robh+dt, kyungmin.park, khilman, linux-pm,
	linux-kernel, devicetree, linux-arm-kernel, linux-mediatek,
	jia-wei.chang, Project_Global_Chrome_Upstream_Group

On Wed, 2022-05-11 at 18:48 +0800, Chen-Yu Tsai wrote:
> On Mon, May 9, 2022 at 8:14 PM Johnson Wang <
> johnson.wang@mediatek.com> wrote:
> > 
> > Hi Chen-Yu,
> > 
> > On Tue, 2022-04-26 at 11:18 +0800, Chen-Yu Tsai wrote:
> > > On Mon, Apr 25, 2022 at 8:56 PM Johnson Wang <
> > > johnson.wang@mediatek.com> wrote:
> > > > 
> > > > Add devicetree binding of MediaTek CCI on MT8183 and MT8186.
> > > > 
> > > > Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> > > > Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > > > ---
> > > >  .../bindings/interconnect/mediatek,cci.yaml   | 139
> > > > ++++++++++++++++++
> > > >  1 file changed, 139 insertions(+)
> > > >  create mode 100644
> > > > Documentation/devicetree/bindings/interconnect/mediatek,cci.yam
> > > > l
> > > > 
> > > > diff --git
> > > > a/Documentation/devicetree/bindings/interconnect/mediatek,cci.y
> > > > aml
> > > > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.y
> > > > aml
> > > > new file mode 100644
> > > > index 000000000000..e5221e17d11b
> > > > --- /dev/null
> > > > +++
> > > > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.y
> > > > aml
> > > > @@ -0,0 +1,139 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > +%YAML 1.2
> > > > +---
> > > > +$id:
> > > > 
https://urldefense.com/v3/__http://devicetree.org/schemas/interconnect/mediatek,cci.yaml*__;Iw!!CTRNKA9wMg0ARbw!zuufEcqpKbditY3eqLTHpL8P8humMCyh4D4QWsximmw124tJUPE3ZBUyBqBtDlQ9pSDO$
> > > > 
> > > > +$schema:
> > > > 
https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!zuufEcqpKbditY3eqLTHpL8P8humMCyh4D4QWsximmw124tJUPE3ZBUyBqBtDoE9YHyu$
> > > > 
> > > > +
> > > > +title: MediaTek Cache Coherent Interconnect (CCI) frequency
> > > > and
> > > > voltage scaling
> > > > +
> > > > +maintainers:
> > > > +  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > > > +
> > > > +description: |
> > > > +  MediaTek Cache Coherent Interconnect (CCI) is a hardware
> > > > engine
> > > > used by
> > > > +  MT8183 and MT8186 SoCs to scale the frequency and adjust the
> > > > voltage in
> > > > +  hardware. It can also optimize the voltage to reduce the
> > > > power
> > > > consumption.
> > > > +
> > > > +properties:
> > > > +  compatible:
> > > > +    enum:
> > > > +      - mediatek,mt8183-cci
> > > > +      - mediatek,mt8186-cci
> > > > +
> > > > +  clocks:
> > > > +    items:
> > > > +      - description:
> > > > +          The multiplexer for clock input of CPU cluster.
> > > 
> > > of the bus, not CPU cluster.
> > 
> > Thanks for your suggestion.
> > I will correct it in the next version.
> > 
> > > 
> > > > +      - description:
> > > > +          A parent of "cpu" clock which is used as an
> > > > intermediate
> > > > clock source
> > > > +          when the original CPU is under transition and not
> > > > stable
> > > > yet.
> > > 
> > > This really should be handled in the clk controller, and not by
> > > every
> > > device
> > > that happens to take a clock from a mux with upstream PLLs that
> > > can
> > > change
> > > in clock rate. The end device hardware only takes one clock
> > > input.
> > > That's it.
> > > 
> > 
> > To make this intermediate clock works properly, this driver is also
> > responsible for handling the Vproc voltage and ensures the voltage
> > is
> > high enough to support intermediate clock rate.
> > 
> > If we move intermediate clock rate control to clock driver, then
> > intermediate voltage control may be handled by the clock driver
> > itself
> > as well.
> > 
> > We believe that is not reasonable because clock driver shouldn't
> > handle
> > voltage control. On the other hand, DVFS driver is more suitable
> > for
> > doing this job.
> 
> Either way the DVFS driver handles the voltage change.
> 
> Right now the driver is doing:
> 
> 1. Raise voltage if scaling up
> 2. Mux CCI clock over to stable clock
> 3. Set rate for CCI PLL
> 4. Mux CCI clock back to CCI PLL
> 5. Drop voltage if scaling down
> 
> I'm saying that the clock driver should handle 2+4 transparently when
> any
> driver requests a rate change on the CCI clock. So instead the driver
> would
> do:
> 
> 1. Raise voltage if scaling up
> 2. Set rate for CCI _clock_
>    Here the clock driver would do:
>    a. Mux CCI clock over to stable clock
>    b. Change clock rate for original parent, i.e. the CCI PLL
>    c. Mux CCI clock back to original parent, i.e. the CCI PLL
>    and back to the devfreq driver ...
> 3. Drop voltage if scaling down
> 
> Does that make sense?
> 
> 
> Regards
> ChenYu

Hi Chen-Yu,

Before we mux the CCI clock to an intermediate clock(MAINPLL), we must
ensure that regulator voltage is high enough (we call it intermediate
voltage) to support the intermediate clock rate.

Based on this concept, if we move mux control to clock driver, there
will be a dilemma about which driver to adjust the voltage.

1)When DVFS calls clk_set_rate(), clock driver scales up the regulator
voltage to higher than intermediate voltage and then mux the CCI clock.

This option is not reasonable because clock driver shouldn't handle the
regulators.


2)DVFS scales up the regulator voltage, then calls clk_set_rate(). 
Clock driver mux the CCI clock to the intermediate clock.

This option isn't straightforward and makes one confused easily. For a
person who reads this driver, he may not understand why we adjust the
voltage before clk_set_rate().

That's why we put intermediate voltage/freq together in the DVFS.

BRs,
Johnson Wang


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  2022-05-12 13:04         ` Johnson Wang
@ 2022-05-13  3:31           ` Chen-Yu Tsai
  0 siblings, 0 replies; 27+ messages in thread
From: Chen-Yu Tsai @ 2022-05-13  3:31 UTC (permalink / raw)
  To: Johnson Wang
  Cc: krzk+dt, cw00.choi, robh+dt, kyungmin.park, khilman, linux-pm,
	linux-kernel, devicetree, linux-arm-kernel, linux-mediatek,
	jia-wei.chang, Project_Global_Chrome_Upstream_Group

On Thu, May 12, 2022 at 9:05 PM Johnson Wang <johnson.wang@mediatek.com> wrote:
>
> On Wed, 2022-05-11 at 18:48 +0800, Chen-Yu Tsai wrote:
> > On Mon, May 9, 2022 at 8:14 PM Johnson Wang <
> > johnson.wang@mediatek.com> wrote:
> > >
> > > Hi Chen-Yu,
> > >
> > > On Tue, 2022-04-26 at 11:18 +0800, Chen-Yu Tsai wrote:
> > > > On Mon, Apr 25, 2022 at 8:56 PM Johnson Wang <
> > > > johnson.wang@mediatek.com> wrote:
> > > > >
> > > > > Add devicetree binding of MediaTek CCI on MT8183 and MT8186.
> > > > >
> > > > > Signed-off-by: Johnson Wang <johnson.wang@mediatek.com>
> > > > > Signed-off-by: Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > > > > ---
> > > > >  .../bindings/interconnect/mediatek,cci.yaml   | 139
> > > > > ++++++++++++++++++
> > > > >  1 file changed, 139 insertions(+)
> > > > >  create mode 100644
> > > > > Documentation/devicetree/bindings/interconnect/mediatek,cci.yam
> > > > > l
> > > > >
> > > > > diff --git
> > > > > a/Documentation/devicetree/bindings/interconnect/mediatek,cci.y
> > > > > aml
> > > > > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.y
> > > > > aml
> > > > > new file mode 100644
> > > > > index 000000000000..e5221e17d11b
> > > > > --- /dev/null
> > > > > +++
> > > > > b/Documentation/devicetree/bindings/interconnect/mediatek,cci.y
> > > > > aml
> > > > > @@ -0,0 +1,139 @@
> > > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > > +%YAML 1.2
> > > > > +---
> > > > > +$id:
> > > > >
> https://urldefense.com/v3/__http://devicetree.org/schemas/interconnect/mediatek,cci.yaml*__;Iw!!CTRNKA9wMg0ARbw!zuufEcqpKbditY3eqLTHpL8P8humMCyh4D4QWsximmw124tJUPE3ZBUyBqBtDlQ9pSDO$
> > > > >
> > > > > +$schema:
> > > > >
> https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!zuufEcqpKbditY3eqLTHpL8P8humMCyh4D4QWsximmw124tJUPE3ZBUyBqBtDoE9YHyu$
> > > > >
> > > > > +
> > > > > +title: MediaTek Cache Coherent Interconnect (CCI) frequency
> > > > > and
> > > > > voltage scaling
> > > > > +
> > > > > +maintainers:
> > > > > +  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
> > > > > +
> > > > > +description: |
> > > > > +  MediaTek Cache Coherent Interconnect (CCI) is a hardware
> > > > > engine
> > > > > used by
> > > > > +  MT8183 and MT8186 SoCs to scale the frequency and adjust the
> > > > > voltage in
> > > > > +  hardware. It can also optimize the voltage to reduce the
> > > > > power
> > > > > consumption.
> > > > > +
> > > > > +properties:
> > > > > +  compatible:
> > > > > +    enum:
> > > > > +      - mediatek,mt8183-cci
> > > > > +      - mediatek,mt8186-cci
> > > > > +
> > > > > +  clocks:
> > > > > +    items:
> > > > > +      - description:
> > > > > +          The multiplexer for clock input of CPU cluster.
> > > >
> > > > of the bus, not CPU cluster.
> > >
> > > Thanks for your suggestion.
> > > I will correct it in the next version.
> > >
> > > >
> > > > > +      - description:
> > > > > +          A parent of "cpu" clock which is used as an
> > > > > intermediate
> > > > > clock source
> > > > > +          when the original CPU is under transition and not
> > > > > stable
> > > > > yet.
> > > >
> > > > This really should be handled in the clk controller, and not by
> > > > every
> > > > device
> > > > that happens to take a clock from a mux with upstream PLLs that
> > > > can
> > > > change
> > > > in clock rate. The end device hardware only takes one clock
> > > > input.
> > > > That's it.
> > > >
> > >
> > > To make this intermediate clock works properly, this driver is also
> > > responsible for handling the Vproc voltage and ensures the voltage
> > > is
> > > high enough to support intermediate clock rate.
> > >
> > > If we move intermediate clock rate control to clock driver, then
> > > intermediate voltage control may be handled by the clock driver
> > > itself
> > > as well.
> > >
> > > We believe that is not reasonable because clock driver shouldn't
> > > handle
> > > voltage control. On the other hand, DVFS driver is more suitable
> > > for
> > > doing this job.
> >
> > Either way the DVFS driver handles the voltage change.
> >
> > Right now the driver is doing:
> >
> > 1. Raise voltage if scaling up
> > 2. Mux CCI clock over to stable clock
> > 3. Set rate for CCI PLL
> > 4. Mux CCI clock back to CCI PLL
> > 5. Drop voltage if scaling down
> >
> > I'm saying that the clock driver should handle 2+4 transparently when
> > any
> > driver requests a rate change on the CCI clock. So instead the driver
> > would
> > do:
> >
> > 1. Raise voltage if scaling up
> > 2. Set rate for CCI _clock_
> >    Here the clock driver would do:
> >    a. Mux CCI clock over to stable clock
> >    b. Change clock rate for original parent, i.e. the CCI PLL
> >    c. Mux CCI clock back to original parent, i.e. the CCI PLL
> >    and back to the devfreq driver ...
> > 3. Drop voltage if scaling down
> >
> > Does that make sense?
> >
> >
> > Regards
> > ChenYu
>
> Hi Chen-Yu,
>
> Before we mux the CCI clock to an intermediate clock(MAINPLL), we must
> ensure that regulator voltage is high enough (we call it intermediate
> voltage) to support the intermediate clock rate.
>
> Based on this concept, if we move mux control to clock driver, there
> will be a dilemma about which driver to adjust the voltage.
>
> 1)When DVFS calls clk_set_rate(), clock driver scales up the regulator
> voltage to higher than intermediate voltage and then mux the CCI clock.
>
> This option is not reasonable because clock driver shouldn't handle the
> regulators.
>
>
> 2)DVFS scales up the regulator voltage, then calls clk_set_rate().
> Clock driver mux the CCI clock to the intermediate clock.
>
> This option isn't straightforward and makes one confused easily. For a
> person who reads this driver, he may not understand why we adjust the
> voltage before clk_set_rate().
>
> That's why we put intermediate voltage/freq together in the DVFS.

Thanks for the explanation. The intermediate clock's rate being higher
than the lowest OPP is the key I missed.

I can't think of a better way to describe this in DT. The intermediate
clock's rate is stable, but it is set either through hardware reset defaults
or firmware, so we can't just assume a given clock rate and hard code that.
Having a direct reference to the clock seems simpler.


Regards
ChenYu

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2022-05-13  3:31 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-25 12:55 [PATCH v3 0/2] Introduce MediaTek CCI devfreq driver Johnson Wang
2022-04-25 12:55 ` [PATCH v3 1/2] dt-bindings: interconnect: Add MediaTek CCI dt-bindings Johnson Wang
2022-04-25 17:56   ` Krzysztof Kozlowski
2022-04-26  3:18   ` Chen-Yu Tsai
2022-05-09 12:14     ` Johnson Wang
2022-05-11 10:48       ` Chen-Yu Tsai
2022-05-12 13:04         ` Johnson Wang
2022-05-13  3:31           ` Chen-Yu Tsai
2022-05-09 12:09   ` Chanwoo Choi
2022-05-09 12:43     ` Chanwoo Choi
2022-05-10  2:59     ` Johnson Wang
2022-05-10  4:27       ` Chanwoo Choi
2022-04-25 12:55 ` [PATCH v3 2/2] PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver Johnson Wang
2022-04-26 12:45   ` kernel test robot
2022-04-27  7:09   ` kernel test robot
2022-04-27  9:25   ` kernel test robot
2022-04-27 10:11     ` Johnson Wang
2022-04-28 11:39       ` [kbuild-all] " Chen, Rong A
2022-05-06 12:03         ` Chen-Yu Tsai
2022-05-09  2:53           ` Chanwoo Choi
2022-05-06 11:38   ` Johnson Wang
2022-05-07 13:53     ` Chanwoo Choi
2022-05-09  5:57       ` Johnson Wang
2022-05-09 11:51         ` Chanwoo Choi
2022-05-11  5:14           ` Johnson Wang
2022-05-11  7:08             ` Chanwoo Choi
2022-05-06 18:57   ` Chanwoo Choi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).