linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig
@ 2018-02-23 21:00 Tony Lindgren
  2018-02-23 21:00 ` [PATCH 01/12] bus: ti-sysc: Add fck clock alias for children with notifier_block Tony Lindgren
                   ` (12 more replies)
  0 siblings, 13 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel

Hi all,

This series of changes makes ti-sysc driver to use device tree data for
configuring the interconnect target module registers. We already have
smartreflex dts data configured according to the binding for ti-sysc,
so that will be the first user.

I've added code to check the dts data against the existing platform
data to make sure we're not causing regressions. And I've verified
that PM still works.

Regards,

Tony


Tony Lindgren (12):
  bus: ti-sysc: Add fck clock alias for children with notifier_block
  bus: ti-sysc: Add suspend and resume handling
  bus: ti-sysc: Handle stdout-path for debug console
  bus: ti-sysc: Improve handling for no-reset-on-init and
    no-idle-on-init
  bus: ti-sysc: Remove unnecessary debugging statements
  bus: ti-sysc: Add support for platform data callbacks
  bus: ti-sysc: Handle some devices in omap_device compatible way
  ARM: OMAP2+: Add functions to allocate module data from device tree
  ARM: OMAP2+: Add checks for device tree based sysconfig data
  ARM: OMAP2+: Try to parse earlycon from parent too
  PM / AVS: SmartReflex: Prepare to use device tree based probing
  ARM: OMAP2+: Enable ti-sysc to use device tree data for smartreflex

 arch/arm/mach-omap2/board-n8x0.c      |   4 +-
 arch/arm/mach-omap2/omap_device.c     |   5 +
 arch/arm/mach-omap2/omap_hwmod.c      | 418 ++++++++++++++++++++++++++-
 arch/arm/mach-omap2/omap_hwmod.h      |   7 +
 arch/arm/mach-omap2/pdata-quirks.c    |  41 ++-
 arch/arm/mach-omap2/sr_device.c       |  25 +-
 drivers/bus/ti-sysc.c                 | 527 +++++++++++++++++++++++++++++++---
 drivers/power/avs/smartreflex.c       |  41 ++-
 include/linux/platform_data/ti-sysc.h |  50 ++++
 9 files changed, 1063 insertions(+), 55 deletions(-)

-- 
2.16.2

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

* [PATCH 01/12] bus: ti-sysc: Add fck clock alias for children with notifier_block
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
@ 2018-02-23 21:00 ` Tony Lindgren
  2018-02-23 21:00 ` [PATCH 02/12] bus: ti-sysc: Add suspend and resume handling Tony Lindgren
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel

The functional clock is used by several child device drivers to query
the rate for the child device internal configuration. The functional
clock is really for the whole interconnect target module, and not just
for the child device, and can also be shared across multiple children.
At least the timers, i2c and mmc driver query the fck for rate.

So let's just create a clock alias for the child fck if it does not
yet exits. We can do this with the BUS_NOTIFY_ADD_DEVICE before the
child is probed.

Note that we need to now also remove the legacy mode check for getting
the dts clocks in ti-sysc driver.

Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/bus/ti-sysc.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 87 insertions(+), 4 deletions(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -13,11 +13,14 @@
 
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/clkdev.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
+#include <linux/slab.h>
+
 #include <linux/platform_data/ti-sysc.h>
 
 #include <dt-bindings/bus/ti-sysc.h>
@@ -136,9 +139,6 @@ static int sysc_get_clocks(struct sysc *ddata)
 {
 	int i, error;
 
-	if (ddata->legacy_mode)
-		return 0;
-
 	for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
 		error = sysc_get_one_clock(ddata, i);
 		if (error && error != -ENOENT)
@@ -605,6 +605,74 @@ static int sysc_init_syss_mask(struct sysc *ddata)
 	return 0;
 }
 
+/*
+ * Many child device drivers need to have fck available to get the clock
+ * rate for device internal configuration.
+ */
+static int sysc_child_add_fck(struct sysc *ddata,
+			      struct device *child)
+{
+	struct clk *fck;
+	struct clk_lookup *l;
+	const char *name = clock_names[SYSC_FCK];
+
+	if (IS_ERR_OR_NULL(ddata->clocks[SYSC_FCK]))
+		return 0;
+
+	fck = clk_get(child, name);
+	if (!IS_ERR(fck)) {
+		clk_put(fck);
+
+		return -EEXIST;
+	}
+
+	l = clkdev_create(ddata->clocks[SYSC_FCK], name, dev_name(child));
+
+	return l ? 0 : -ENODEV;
+}
+
+static struct device_type sysc_device_type = {
+};
+
+static struct sysc *sysc_child_to_parent(struct device *dev)
+{
+	struct device *parent = dev->parent;
+
+	if (!parent || parent->type != &sysc_device_type)
+		return NULL;
+
+	return dev_get_drvdata(parent);
+}
+
+static int sysc_notifier_call(struct notifier_block *nb,
+			      unsigned long event, void *device)
+{
+	struct device *dev = device;
+	struct sysc *ddata;
+	int error;
+
+	ddata = sysc_child_to_parent(dev);
+	if (!ddata)
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		error = sysc_child_add_fck(ddata, dev);
+		if (error && error != -EEXIST)
+			dev_warn(ddata->dev, "could not add %s fck: %i\n",
+				 dev_name(dev), error);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block sysc_nb = {
+	.notifier_call = sysc_notifier_call,
+};
+
 /* Device tree configured quirks */
 struct sysc_dts_quirk {
 	const char *name;
@@ -937,6 +1005,7 @@ static int sysc_probe(struct platform_device *pdev)
 
 	sysc_show_registers(ddata);
 
+	ddata->dev->type = &sysc_device_type;
 	error = of_platform_populate(ddata->dev->of_node,
 				     NULL, NULL, ddata->dev);
 	if (error)
@@ -1008,7 +1077,21 @@ static struct platform_driver sysc_driver = {
 		.pm = &sysc_pm_ops,
 	},
 };
-module_platform_driver(sysc_driver);
+
+static int __init sysc_init(void)
+{
+	bus_register_notifier(&platform_bus_type, &sysc_nb);
+
+	return platform_driver_register(&sysc_driver);
+}
+module_init(sysc_init);
+
+static void __exit sysc_exit(void)
+{
+	bus_unregister_notifier(&platform_bus_type, &sysc_nb);
+	platform_driver_unregister(&sysc_driver);
+}
+module_exit(sysc_exit);
 
 MODULE_DESCRIPTION("TI sysc interconnect target driver");
 MODULE_LICENSE("GPL v2");
-- 
2.16.2

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

* [PATCH 02/12] bus: ti-sysc: Add suspend and resume handling
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
  2018-02-23 21:00 ` [PATCH 01/12] bus: ti-sysc: Add fck clock alias for children with notifier_block Tony Lindgren
@ 2018-02-23 21:00 ` Tony Lindgren
  2018-02-23 21:00 ` [PATCH 03/12] bus: ti-sysc: Handle stdout-path for debug console Tony Lindgren
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel

This allows us to idle the module on suspend after the children
are suspended.

Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/bus/ti-sysc.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -58,6 +58,7 @@ static const char * const clock_names[] = { "fck", "ick", };
  * @cfg: interconnect target module configuration
  * @name: name if available
  * @revision: interconnect target module revision
+ * @needs_resume: runtime resume needed on resume from suspend
  */
 struct sysc {
 	struct device *dev;
@@ -71,6 +72,8 @@ struct sysc {
 	struct sysc_config cfg;
 	const char *name;
 	u32 revision;
+	bool enabled;
+	bool needs_resume;
 };
 
 static u32 sysc_read(struct sysc *ddata, int offset)
@@ -497,7 +500,38 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int sysc_suspend(struct device *dev)
+{
+	struct sysc *ddata;
+
+	ddata = dev_get_drvdata(dev);
+
+	if (!ddata->enabled)
+		return 0;
+
+	ddata->needs_resume = true;
+
+	return sysc_runtime_suspend(dev);
+}
+
+static int sysc_resume(struct device *dev)
+{
+	struct sysc *ddata;
+
+	ddata = dev_get_drvdata(dev);
+	if (ddata->needs_resume) {
+		ddata->needs_resume = false;
+
+		return sysc_runtime_resume(dev);
+	}
+
+	return 0;
+}
+#endif
+
 static const struct dev_pm_ops sysc_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(sysc_suspend, sysc_resume)
 	SET_RUNTIME_PM_OPS(sysc_runtime_suspend,
 			   sysc_runtime_resume,
 			   NULL)
-- 
2.16.2

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

* [PATCH 03/12] bus: ti-sysc: Handle stdout-path for debug console
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
  2018-02-23 21:00 ` [PATCH 01/12] bus: ti-sysc: Add fck clock alias for children with notifier_block Tony Lindgren
  2018-02-23 21:00 ` [PATCH 02/12] bus: ti-sysc: Add suspend and resume handling Tony Lindgren
@ 2018-02-23 21:00 ` Tony Lindgren
  2018-02-23 21:00 ` [PATCH 04/12] bus: ti-sysc: Improve handling for no-reset-on-init and no-idle-on-init Tony Lindgren
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel

If we have stdout-path specified for earlycon, we must prevent
the debug console from idling until runtime PM kicks in.

Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/bus/ti-sysc.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -206,6 +206,50 @@ static int sysc_parse_and_check_child_range(struct sysc *ddata)
 	return 0;
 }
 
+static struct device_node *stdout_path;
+
+static void sysc_init_stdout_path(struct sysc *ddata)
+{
+	struct device_node *np = NULL;
+	const char *uart;
+
+	if (IS_ERR(stdout_path))
+		return;
+
+	if (stdout_path)
+		return;
+
+	np = of_find_node_by_path("/chosen");
+	if (!np)
+		goto err;
+
+	uart = of_get_property(np, "stdout-path", NULL);
+	if (!uart)
+		goto err;
+
+	np = of_find_node_by_path(uart);
+	if (!np)
+		goto err;
+
+	stdout_path = np;
+
+	return;
+
+err:
+	stdout_path = ERR_PTR(-ENODEV);
+}
+
+static void sysc_check_quirk_stdout(struct sysc *ddata,
+				    struct device_node *np)
+{
+	sysc_init_stdout_path(ddata);
+	if (np != stdout_path)
+		return;
+
+	ddata->cfg.quirks |= SYSC_QUIRK_NO_IDLE_ON_INIT |
+				SYSC_QUIRK_NO_RESET_ON_INIT;
+}
+
 /**
  * sysc_check_one_child - check child configuration
  * @ddata: device driver data
@@ -224,6 +268,8 @@ static int sysc_check_one_child(struct sysc *ddata,
 	if (name)
 		dev_warn(ddata->dev, "really a child ti,hwmods property?");
 
+	sysc_check_quirk_stdout(ddata, np);
+
 	return 0;
 }
 
-- 
2.16.2

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

* [PATCH 04/12] bus: ti-sysc: Improve handling for no-reset-on-init and no-idle-on-init
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
                   ` (2 preceding siblings ...)
  2018-02-23 21:00 ` [PATCH 03/12] bus: ti-sysc: Handle stdout-path for debug console Tony Lindgren
@ 2018-02-23 21:00 ` Tony Lindgren
  2018-02-23 21:00 ` [PATCH 05/12] bus: ti-sysc: Remove unnecessary debugging statements Tony Lindgren
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel

At least earlycon needs a delayed idle before the 8250 driver probes
to avoid glitches in the console output. Let's handle the delayed idle
for devices tagged with ti,no-reset-on-init and ti,no-idle-on-init with
delayed_work. Others don't need it, and there should be no need to use
runtime PM autosuspend for the interconnect target driver as it's the
child device drivers that should configure it.

Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/bus/ti-sysc.c | 28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -74,6 +74,7 @@ struct sysc {
 	u32 revision;
 	bool enabled;
 	bool needs_resume;
+	struct delayed_work idle_work;
 };
 
 static u32 sysc_read(struct sysc *ddata, int offset)
@@ -1028,6 +1029,16 @@ static int sysc_init_match(struct sysc *ddata)
 	return 0;
 }
 
+static void ti_sysc_idle(struct work_struct *work)
+{
+	struct sysc *ddata;
+
+	ddata = container_of(work, struct sysc, idle_work.work);
+
+	if (pm_runtime_active(ddata->dev))
+		pm_runtime_put_sync(ddata->dev);
+}
+
 static int sysc_probe(struct platform_device *pdev)
 {
 	struct sysc *ddata;
@@ -1081,8 +1092,6 @@ static int sysc_probe(struct platform_device *pdev)
 		goto unprepare;
 	}
 
-	pm_runtime_use_autosuspend(ddata->dev);
-
 	sysc_show_registers(ddata);
 
 	ddata->dev->type = &sysc_device_type;
@@ -1091,13 +1100,19 @@ static int sysc_probe(struct platform_device *pdev)
 	if (error)
 		goto err;
 
-	pm_runtime_mark_last_busy(ddata->dev);
-	pm_runtime_put_autosuspend(ddata->dev);
+	INIT_DELAYED_WORK(&ddata->idle_work, ti_sysc_idle);
+
+	/* At least earlycon won't survive without deferred idle */
+	if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE_ON_INIT |
+				 SYSC_QUIRK_NO_RESET_ON_INIT)) {
+		schedule_delayed_work(&ddata->idle_work, 3000);
+	} else {
+		pm_runtime_put(&pdev->dev);
+	}
 
 	return 0;
 
 err:
-	pm_runtime_dont_use_autosuspend(&pdev->dev);
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 unprepare:
@@ -1111,6 +1126,8 @@ static int sysc_remove(struct platform_device *pdev)
 	struct sysc *ddata = platform_get_drvdata(pdev);
 	int error;
 
+	cancel_delayed_work_sync(&ddata->idle_work);
+
 	error = pm_runtime_get_sync(ddata->dev);
 	if (error < 0) {
 		pm_runtime_put_noidle(ddata->dev);
@@ -1120,7 +1137,6 @@ static int sysc_remove(struct platform_device *pdev)
 
 	of_platform_depopulate(&pdev->dev);
 
-	pm_runtime_dont_use_autosuspend(&pdev->dev);
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
-- 
2.16.2

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

* [PATCH 05/12] bus: ti-sysc: Remove unnecessary debugging statements
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
                   ` (3 preceding siblings ...)
  2018-02-23 21:00 ` [PATCH 04/12] bus: ti-sysc: Improve handling for no-reset-on-init and no-idle-on-init Tony Lindgren
@ 2018-02-23 21:00 ` Tony Lindgren
  2018-02-23 21:00 ` [PATCH 06/12] bus: ti-sysc: Add support for platform data callbacks Tony Lindgren
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel, Tony Lindgren

We already show the status for the interconnect target module
when debugging is enabled, there's no need to be more verbose
about that. So let's just cut down the noise and remove the
extra debug statements.

Signed-off-by: Tony Lindgren <tony@atomide.coM>
---
 drivers/bus/ti-sysc.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -201,9 +201,6 @@ static int sysc_parse_and_check_child_range(struct sysc *ddata)
 	ddata->module_pa = of_translate_address(np, ranges++);
 	ddata->module_size = be32_to_cpup(ranges);
 
-	dev_dbg(ddata->dev, "interconnect target 0x%llx size 0x%x for %pOF\n",
-		ddata->module_pa, ddata->module_size, np);
-
 	return 0;
 }
 
@@ -296,11 +293,8 @@ static int sysc_check_children(struct sysc *ddata)
  */
 static void sysc_check_quirk_16bit(struct sysc *ddata, struct resource *res)
 {
-	if (resource_size(res) == 8) {
-		dev_dbg(ddata->dev,
-			"enabling 16-bit and clockactivity quirks\n");
+	if (resource_size(res) == 8)
 		ddata->cfg.quirks |= SYSC_QUIRK_16BIT | SYSC_QUIRK_USE_CLOCKACT;
-	}
 }
 
 /**
@@ -326,7 +320,6 @@ static int sysc_parse_one(struct sysc *ddata, enum sysc_registers reg)
 	res = platform_get_resource_byname(to_platform_device(ddata->dev),
 					   IORESOURCE_MEM, name);
 	if (!res) {
-		dev_dbg(ddata->dev, "has no %s register\n", name);
 		ddata->offsets[reg] = -ENODEV;
 
 		return 0;
-- 
2.16.2

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

* [PATCH 06/12] bus: ti-sysc: Add support for platform data callbacks
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
                   ` (4 preceding siblings ...)
  2018-02-23 21:00 ` [PATCH 05/12] bus: ti-sysc: Remove unnecessary debugging statements Tony Lindgren
@ 2018-02-23 21:00 ` Tony Lindgren
  2018-02-23 21:00 ` [PATCH 07/12] bus: ti-sysc: Handle some devices in omap_device compatible way Tony Lindgren
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel

We want to pass the device tree configuration for interconnect target
modules from ti-sysc driver to the existing platform hwmod code.

This allows us to first validate the dts data against the existing
platform data before we start dropping the platform data in favor of
device tree data.

To do this, let's add platform data callbacks for PM runtime functions
to call for the interconnect target modules if platform data is
available.

Note that as ti-sysc driver can rebind, omap_auxdata_lookup and related
functions can no longer be __init.

Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 arch/arm/mach-omap2/board-n8x0.c      |  4 +-
 arch/arm/mach-omap2/pdata-quirks.c    | 40 ++++++++++++++-
 drivers/bus/ti-sysc.c                 | 96 ++++++++++++++++++++++++++++++-----
 include/linux/platform_data/ti-sysc.h | 49 ++++++++++++++++++
 4 files changed, 172 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -566,11 +566,11 @@ static int n8x0_menelaus_late_init(struct device *dev)
 }
 #endif
 
-struct menelaus_platform_data n8x0_menelaus_platform_data __initdata = {
+struct menelaus_platform_data n8x0_menelaus_platform_data = {
 	.late_init = n8x0_menelaus_late_init,
 };
 
-struct aic3x_pdata n810_aic33_data __initdata = {
+struct aic3x_pdata n810_aic33_data = {
 	.gpio_reset = 118,
 };
 
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -24,6 +24,7 @@
 #include <linux/platform_data/pinctrl-single.h>
 #include <linux/platform_data/hsmmc-omap.h>
 #include <linux/platform_data/iommu-omap.h>
+#include <linux/platform_data/ti-sysc.h>
 #include <linux/platform_data/wkup_m3.h>
 #include <linux/platform_data/pwm_omap_dmtimer.h>
 #include <linux/platform_data/media/ir-rx51.h>
@@ -455,6 +456,42 @@ static void __init dra7x_evm_mmc_quirk(void)
 }
 #endif
 
+static int ti_sysc_enable_module(struct device *dev,
+				 const struct ti_sysc_cookie *cookie)
+{
+	if (!cookie->data)
+		return -EINVAL;
+
+	return omap_hwmod_enable(cookie->data);
+}
+
+static int ti_sysc_idle_module(struct device *dev,
+			       const struct ti_sysc_cookie *cookie)
+{
+	if (!cookie->data)
+		return -EINVAL;
+
+	return omap_hwmod_idle(cookie->data);
+}
+
+static int ti_sysc_shutdown_module(struct device *dev,
+				   const struct ti_sysc_cookie *cookie)
+{
+	if (!cookie->data)
+		return -EINVAL;
+
+	return omap_hwmod_shutdown(cookie->data);
+}
+
+static struct of_dev_auxdata omap_auxdata_lookup[];
+
+static struct ti_sysc_platform_data ti_sysc_pdata = {
+	.auxdata = omap_auxdata_lookup,
+	.enable_module = ti_sysc_enable_module,
+	.idle_module = ti_sysc_idle_module,
+	.shutdown_module = ti_sysc_shutdown_module,
+};
+
 static struct pcs_pdata pcs_pdata;
 
 void omap_pcs_legacy_init(int irq, void (*rearm)(void))
@@ -545,7 +582,7 @@ static struct pdata_init auxdata_quirks[] __initdata = {
 
 struct omap_sr_data __maybe_unused omap_sr_pdata[OMAP_SR_NR];
 
-static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
+static struct of_dev_auxdata omap_auxdata_lookup[] = {
 #ifdef CONFIG_MACH_NOKIA_N8X0
 	OF_DEV_AUXDATA("ti,omap2420-mmc", 0x4809c000, "mmci-omap.0", NULL),
 	OF_DEV_AUXDATA("menelaus", 0x72, "1-0072", &n8x0_menelaus_platform_data),
@@ -603,6 +640,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 		       &dra7_hsmmc_data_mmc3),
 #endif
 	/* Common auxdata */
+	OF_DEV_AUXDATA("ti,sysc", 0, NULL, &ti_sysc_pdata),
 	OF_DEV_AUXDATA("pinctrl-single", 0, NULL, &pcs_pdata),
 	{ /* sentinel */ },
 };
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -25,13 +25,6 @@
 
 #include <dt-bindings/bus/ti-sysc.h>
 
-enum sysc_registers {
-	SYSC_REVISION,
-	SYSC_SYSCONFIG,
-	SYSC_SYSSTATUS,
-	SYSC_MAX_REGS,
-};
-
 static const char * const reg_names[] = { "rev", "sysc", "syss", };
 
 enum sysc_clocks {
@@ -70,6 +63,7 @@ struct sysc {
 	const char *legacy_mode;
 	const struct sysc_capabilities *cap;
 	struct sysc_config cfg;
+	struct ti_sysc_cookie cookie;
 	const char *name;
 	u32 revision;
 	bool enabled;
@@ -494,6 +488,7 @@ static void sysc_show_registers(struct sysc *ddata)
 		bufp += sysc_show_reg(ddata, bufp, i);
 
 	bufp += sysc_show_rev(bufp, ddata);
+	bufp += sysc_show_rev(bufp, ddata);
 
 	dev_dbg(ddata->dev, "%llx:%x%s\n",
 		ddata->module_pa, ddata->module_size,
@@ -502,33 +497,70 @@ static void sysc_show_registers(struct sysc *ddata)
 
 static int __maybe_unused sysc_runtime_suspend(struct device *dev)
 {
+	struct ti_sysc_platform_data *pdata;
 	struct sysc *ddata;
-	int i;
+	int error = 0, i;
 
 	ddata = dev_get_drvdata(dev);
 
-	if (ddata->legacy_mode)
+	if (!ddata->enabled)
 		return 0;
 
+	if (ddata->legacy_mode) {
+		pdata = dev_get_platdata(ddata->dev);
+		if (!pdata)
+			return 0;
+
+		if (!pdata->idle_module)
+			return -ENODEV;
+
+		error = pdata->idle_module(dev, &ddata->cookie);
+		if (error)
+			dev_err(dev, "%s: could not idle: %i\n",
+				__func__, error);
+
+		goto idled;
+	}
+
 	for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
 		if (IS_ERR_OR_NULL(ddata->clocks[i]))
 			continue;
 		clk_disable(ddata->clocks[i]);
 	}
 
-	return 0;
+idled:
+	ddata->enabled = false;
+
+	return error;
 }
 
 static int __maybe_unused sysc_runtime_resume(struct device *dev)
 {
+	struct ti_sysc_platform_data *pdata;
 	struct sysc *ddata;
-	int i, error;
+	int error = 0, i;
 
 	ddata = dev_get_drvdata(dev);
 
-	if (ddata->legacy_mode)
+	if (ddata->enabled)
 		return 0;
 
+	if (ddata->legacy_mode) {
+		pdata = dev_get_platdata(ddata->dev);
+		if (!pdata)
+			return 0;
+
+		if (!pdata->enable_module)
+			return -ENODEV;
+
+		error = pdata->enable_module(dev, &ddata->cookie);
+		if (error)
+			dev_err(dev, "%s: could not enable: %i\n",
+				__func__, error);
+
+		goto awake;
+	}
+
 	for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
 		if (IS_ERR_OR_NULL(ddata->clocks[i]))
 			continue;
@@ -537,7 +569,10 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev)
 			return error;
 	}
 
-	return 0;
+awake:
+	ddata->enabled = true;
+
+	return error;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -1007,6 +1042,33 @@ static const struct sysc_capabilities sysc_omap4_usb_host_fs = {
 	.regbits = &sysc_regbits_omap4_usb_host_fs,
 };
 
+static int sysc_init_pdata(struct sysc *ddata)
+{
+	struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
+	struct ti_sysc_module_data mdata;
+	int error = 0;
+
+	if (!pdata || !ddata->legacy_mode)
+		return 0;
+
+	mdata.name = ddata->legacy_mode;
+	mdata.module_pa = ddata->module_pa;
+	mdata.module_size = ddata->module_size;
+	mdata.offsets = ddata->offsets;
+	mdata.nr_offsets = SYSC_MAX_REGS;
+	mdata.cap = ddata->cap;
+	mdata.cfg = &ddata->cfg;
+
+	if (!pdata->init_module)
+		return -ENODEV;
+
+	error = pdata->init_module(ddata->dev, &mdata, &ddata->cookie);
+	if (error == -EEXIST)
+		error = 0;
+
+	return error;
+}
+
 static int sysc_init_match(struct sysc *ddata)
 {
 	const struct sysc_capabilities *cap;
@@ -1034,6 +1096,7 @@ static void ti_sysc_idle(struct work_struct *work)
 
 static int sysc_probe(struct platform_device *pdev)
 {
+	struct ti_sysc_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct sysc *ddata;
 	int error;
 
@@ -1072,6 +1135,10 @@ static int sysc_probe(struct platform_device *pdev)
 	if (error)
 		goto unprepare;
 
+	error = sysc_init_pdata(ddata);
+	if (error)
+		goto unprepare;
+
 	pm_runtime_enable(ddata->dev);
 
 	error = sysc_init_module(ddata);
@@ -1089,7 +1156,8 @@ static int sysc_probe(struct platform_device *pdev)
 
 	ddata->dev->type = &sysc_device_type;
 	error = of_platform_populate(ddata->dev->of_node,
-				     NULL, NULL, ddata->dev);
+				     NULL, pdata ? pdata->auxdata : NULL,
+				     ddata->dev);
 	if (error)
 		goto err;
 
diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
--- a/include/linux/platform_data/ti-sysc.h
+++ b/include/linux/platform_data/ti-sysc.h
@@ -16,6 +16,10 @@ enum ti_sysc_module_type {
 	TI_SYSC_OMAP4_USB_HOST_FS,
 };
 
+struct ti_sysc_cookie {
+	void *data;
+};
+
 /**
  * struct sysc_regbits - TI OCP_SYSCONFIG register field offsets
  * @midle_shift: Offset of the midle bit
@@ -83,4 +87,49 @@ struct sysc_config {
 	u32 quirks;
 };
 
+enum sysc_registers {
+	SYSC_REVISION,
+	SYSC_SYSCONFIG,
+	SYSC_SYSSTATUS,
+	SYSC_MAX_REGS,
+};
+
+/**
+ * struct ti_sysc_module_data - ti-sysc to hwmod translation data for a module
+ * @name: legacy "ti,hwmods" module name
+ * @module_pa: physical address of the interconnect target module
+ * @module_size: size of the interconnect target module
+ * @offsets: array of register offsets as listed in enum sysc_registers
+ * @nr_offsets: number of registers
+ * @cap: interconnect target module capabilities
+ * @cfg: interconnect target module configuration
+ *
+ * This data is enough to allocate a new struct omap_hwmod_class_sysconfig
+ * based on device tree data parsed by ti-sysc driver.
+ */
+struct ti_sysc_module_data {
+	const char *name;
+	u64 module_pa;
+	u32 module_size;
+	int *offsets;
+	int nr_offsets;
+	const struct sysc_capabilities *cap;
+	struct sysc_config *cfg;
+};
+
+struct device;
+
+struct ti_sysc_platform_data {
+	struct of_dev_auxdata *auxdata;
+	int (*init_module)(struct device *dev,
+			   const struct ti_sysc_module_data *data,
+			   struct ti_sysc_cookie *cookie);
+	int (*enable_module)(struct device *dev,
+			     const struct ti_sysc_cookie *cookie);
+	int (*idle_module)(struct device *dev,
+			   const struct ti_sysc_cookie *cookie);
+	int (*shutdown_module)(struct device *dev,
+			       const struct ti_sysc_cookie *cookie);
+};
+
 #endif	/* __TI_SYSC_DATA_H__ */
-- 
2.16.2

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

* [PATCH 07/12] bus: ti-sysc: Handle some devices in omap_device compatible way
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
                   ` (5 preceding siblings ...)
  2018-02-23 21:00 ` [PATCH 06/12] bus: ti-sysc: Add support for platform data callbacks Tony Lindgren
@ 2018-02-23 21:00 ` Tony Lindgren
  2018-03-01  0:37   ` Tony Lindgren
  2018-02-23 21:00 ` [PATCH 08/12] ARM: OMAP2+: Add functions to allocate module data from device tree Tony Lindgren
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel

Now that ti-sysc can manage child devices, we must also be backwards
compatible with the current omap_device code. With omap_device, we
assume that the child device manages the interconnect target module
directly.

The drivers needing special handling are the ones that still set
pm_runtime_irq_safe(). In the long run we want to update those drivers
as otherwise they will cause problems with genpd as a permanent PM
runtime usage count is set on the parent device.

We can handle omap_device these devices by improving the ti-sysc quirk
handling to detect the devices needing special handling based on
register map and revision register if usable. We also need to implement
dev_pm_domain for these child devices just like omap_device does.

Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/bus/ti-sysc.c                 | 227 +++++++++++++++++++++++++++++++++-
 include/linux/platform_data/ti-sysc.h |   1 +
 2 files changed, 225 insertions(+), 3 deletions(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -14,8 +14,10 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
@@ -68,6 +70,7 @@ struct sysc {
 	u32 revision;
 	bool enabled;
 	bool needs_resume;
+	bool child_needs_resume;
 	struct delayed_work idle_work;
 };
 
@@ -474,6 +477,14 @@ static int sysc_show_reg(struct sysc *ddata,
 	return sprintf(bufp, ":%x", ddata->offsets[reg]);
 }
 
+static int sysc_show_name(char *bufp, struct sysc *ddata)
+{
+	if (!ddata->name)
+		return 0;
+
+	return sprintf(bufp, ":%s", ddata->name);
+}
+
 /**
  * sysc_show_registers - show information about interconnect target module
  * @ddata: device driver data
@@ -488,7 +499,7 @@ static void sysc_show_registers(struct sysc *ddata)
 		bufp += sysc_show_reg(ddata, bufp, i);
 
 	bufp += sysc_show_rev(bufp, ddata);
-	bufp += sysc_show_rev(bufp, ddata);
+	bufp += sysc_show_name(bufp, ddata);
 
 	dev_dbg(ddata->dev, "%llx:%x%s\n",
 		ddata->module_pa, ddata->module_size,
@@ -612,11 +623,94 @@ static const struct dev_pm_ops sysc_pm_ops = {
 			   NULL)
 };
 
+/* Module revision register based quirks */
+struct sysc_revision_quirk {
+	const char *name;
+	u32 base;
+	int rev_offset;
+	int sysc_offset;
+	int syss_offset;
+	u32 revision;
+	u32 revision_mask;
+	u32 quirks;
+};
+
+#define SYSC_QUIRK(optname, optbase, optrev, optsysc, optsyss,		\
+		   optrev_val, optrevmask, optquirkmask)		\
+	{								\
+		.name = (optname),					\
+		.base = (optbase),					\
+		.rev_offset = (optrev),					\
+		.sysc_offset = (optsysc),				\
+		.syss_offset = (optsyss),				\
+		.revision = (optrev_val),				\
+		.revision_mask = (optrevmask),				\
+		.quirks = (optquirkmask),				\
+	}
+
+static const struct sysc_revision_quirk sysc_revision_quirks[] = {
+	/* These drivers need to be fixed to not use pm_runtime_irq_safe() */
+	SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000020, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000030, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("smartreflex", 0, -1, 0x24, -1, 0x00000000, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("smartreflex", 0, -1, 0x38, -1, 0x00000000, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+};
+
+static void sysc_init_revision_quirks(struct sysc *ddata)
+{
+	const struct sysc_revision_quirk *q;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sysc_revision_quirks); i++) {
+		q = &sysc_revision_quirks[i];
+
+		if (q->base && q->base != ddata->module_pa)
+			continue;
+
+		if (q->rev_offset >= 0 &&
+		    q->rev_offset != ddata->offsets[SYSC_REVISION])
+			continue;
+
+		if (q->sysc_offset >= 0 &&
+		    q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
+			continue;
+
+		if (q->syss_offset >= 0 &&
+		    q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
+			continue;
+
+		if (q->revision == ddata->revision ||
+		    (q->revision & q->revision_mask) ==
+		    (ddata->revision & q->revision_mask)) {
+			ddata->name = q->name;
+			ddata->cfg.quirks |= q->quirks;
+		}
+	}
+}
+
 /* At this point the module is configured enough to read the revision */
 static int sysc_init_module(struct sysc *ddata)
 {
 	int error;
 
+	if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE_ON_INIT |
+				 SYSC_QUIRK_NO_RESET_ON_INIT)) {
+		ddata->revision = sysc_read_revision(ddata);
+		goto rev_quirks;
+	}
+
 	error = pm_runtime_get_sync(ddata->dev);
 	if (error < 0) {
 		pm_runtime_put_noidle(ddata->dev);
@@ -626,6 +720,9 @@ static int sysc_init_module(struct sysc *ddata)
 	ddata->revision = sysc_read_revision(ddata);
 	pm_runtime_put_sync(ddata->dev);
 
+rev_quirks:
+	sysc_init_revision_quirks(ddata);
+
 	return 0;
 }
 
@@ -753,6 +850,127 @@ static struct sysc *sysc_child_to_parent(struct device *dev)
 	return dev_get_drvdata(parent);
 }
 
+static int __maybe_unused sysc_child_runtime_suspend(struct device *dev)
+{
+	struct sysc *ddata;
+	int error;
+
+	ddata = sysc_child_to_parent(dev);
+
+	error = pm_generic_runtime_suspend(dev);
+	if (error)
+		return error;
+
+	if (!ddata->enabled)
+		return 0;
+
+	return sysc_runtime_suspend(ddata->dev);
+}
+
+static int __maybe_unused sysc_child_runtime_resume(struct device *dev)
+{
+	struct sysc *ddata;
+	int error;
+
+	ddata = sysc_child_to_parent(dev);
+
+	if (!ddata->enabled) {
+		error = sysc_runtime_resume(ddata->dev);
+		if (error < 0)
+			dev_err(ddata->dev,
+				"%s error: %i\n", __func__, error);
+	}
+
+	return pm_generic_runtime_resume(dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sysc_child_suspend_noirq(struct device *dev)
+{
+	struct sysc *ddata;
+	int error;
+
+	ddata = sysc_child_to_parent(dev);
+
+	error = pm_generic_suspend_noirq(dev);
+	if (error)
+		return error;
+
+	if (!pm_runtime_status_suspended(dev)) {
+		error = pm_generic_runtime_suspend(dev);
+		if (error)
+			return error;
+
+		error = sysc_runtime_suspend(ddata->dev);
+		if (error)
+			return error;
+
+		ddata->child_needs_resume = true;
+	}
+
+	return 0;
+}
+
+static int sysc_child_resume_noirq(struct device *dev)
+{
+	struct sysc *ddata;
+	int error;
+
+	ddata = sysc_child_to_parent(dev);
+
+	if (ddata->child_needs_resume) {
+		ddata->child_needs_resume = false;
+
+		error = sysc_runtime_resume(ddata->dev);
+		if (error)
+			dev_err(ddata->dev,
+				"%s runtime resume error: %i\n",
+				__func__, error);
+
+		error = pm_generic_runtime_resume(dev);
+		if (error)
+			dev_err(ddata->dev,
+				"%s generic runtime resume: %i\n",
+				__func__, error);
+	}
+
+	return pm_generic_resume_noirq(dev);
+}
+#endif
+
+struct dev_pm_domain sysc_child_pm_domain = {
+	.ops = {
+		SET_RUNTIME_PM_OPS(sysc_child_runtime_suspend,
+				   sysc_child_runtime_resume,
+				   NULL)
+		USE_PLATFORM_PM_SLEEP_OPS
+		SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_child_suspend_noirq,
+					      sysc_child_resume_noirq)
+	}
+};
+
+/**
+ * sysc_legacy_idle_quirk - handle children in omap_device compatible way
+ * @ddata: device driver data
+ * @child: child device driver
+ *
+ * Allow idle for child devices as done with _od_runtime_suspend().
+ * Otherwise many child devices will not idle because of the permanent
+ * parent usecount set in pm_runtime_irq_safe().
+ *
+ * Note that the long term solution is to just modify the child device
+ * drivers to not set pm_runtime_irq_safe() and then this can be just
+ * dropped.
+ */
+static void sysc_legacy_idle_quirk(struct sysc *ddata, struct device *child)
+{
+	if (!ddata->legacy_mode)
+		return;
+
+	if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
+		dev_pm_domain_set(child, &sysc_child_pm_domain);
+}
+
 static int sysc_notifier_call(struct notifier_block *nb,
 			      unsigned long event, void *device)
 {
@@ -770,6 +988,7 @@ static int sysc_notifier_call(struct notifier_block *nb,
 		if (error && error != -EEXIST)
 			dev_warn(ddata->dev, "could not add %s fck: %i\n",
 				 dev_name(dev), error);
+		sysc_legacy_idle_quirk(ddata, dev);
 		break;
 	default:
 		break;
@@ -974,7 +1193,8 @@ static const struct sysc_capabilities sysc_34xx_sr = {
 	.type = TI_SYSC_OMAP34XX_SR,
 	.sysc_mask = SYSC_OMAP2_CLOCKACTIVITY,
 	.regbits = &sysc_regbits_omap34xx_sr,
-	.mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED,
+	.mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED |
+		      SYSC_QUIRK_LEGACY_IDLE,
 };
 
 /*
@@ -995,12 +1215,13 @@ static const struct sysc_capabilities sysc_36xx_sr = {
 	.type = TI_SYSC_OMAP36XX_SR,
 	.sysc_mask = SYSC_OMAP3_SR_ENAWAKEUP,
 	.regbits = &sysc_regbits_omap36xx_sr,
-	.mod_quirks = SYSC_QUIRK_UNCACHED,
+	.mod_quirks = SYSC_QUIRK_UNCACHED | SYSC_QUIRK_LEGACY_IDLE,
 };
 
 static const struct sysc_capabilities sysc_omap4_sr = {
 	.type = TI_SYSC_OMAP4_SR,
 	.regbits = &sysc_regbits_omap36xx_sr,
+	.mod_quirks = SYSC_QUIRK_LEGACY_IDLE,
 };
 
 /*
diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
--- a/include/linux/platform_data/ti-sysc.h
+++ b/include/linux/platform_data/ti-sysc.h
@@ -45,6 +45,7 @@ struct sysc_regbits {
 	s8 emufree_shift;
 };
 
+#define SYSC_QUIRK_LEGACY_IDLE		BIT(8)
 #define SYSC_QUIRK_RESET_STATUS		BIT(7)
 #define SYSC_QUIRK_NO_IDLE_ON_INIT	BIT(6)
 #define SYSC_QUIRK_NO_RESET_ON_INIT	BIT(5)
-- 
2.16.2

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

* [PATCH 08/12] ARM: OMAP2+: Add functions to allocate module data from device tree
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
                   ` (6 preceding siblings ...)
  2018-02-23 21:00 ` [PATCH 07/12] bus: ti-sysc: Handle some devices in omap_device compatible way Tony Lindgren
@ 2018-02-23 21:00 ` Tony Lindgren
  2018-02-23 21:00 ` [PATCH 09/12] ARM: OMAP2+: Add checks for device tree based sysconfig data Tony Lindgren
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel, Paul Walmsley

We can have ti-sysc driver manage the interconnect target module via
platform data callback functions to hwmod code. This allows initializing
and idling the devices using dts data instead of the legacy static data
for interconnect target modules.

Let's add functions to configure the module sysconfig data with platform
callbacks from ti-sysc driver.

Cc: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 arch/arm/mach-omap2/omap_hwmod.c | 309 ++++++++++++++++++++++++++++++++++++++-
 arch/arm/mach-omap2/omap_hwmod.h |   7 +
 2 files changed, 315 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -145,6 +145,8 @@
 
 #include <linux/platform_data/ti-sysc.h>
 
+#include <dt-bindings/bus/ti-sysc.h>
+
 #include <asm/system_misc.h>
 
 #include "clock.h"
@@ -2498,7 +2500,7 @@ static void __init _setup_postsetup(struct omap_hwmod *oh)
  * affects the IP block hardware, or system integration hardware
  * associated with the IP block.  Returns 0.
  */
-static int __init _setup(struct omap_hwmod *oh, void *data)
+static int _setup(struct omap_hwmod *oh, void *data)
 {
 	if (oh->_state != _HWMOD_STATE_INITIALIZED)
 		return 0;
@@ -3060,6 +3062,311 @@ int __init omap_hwmod_setup_one(const char *oh_name)
 	return 0;
 }
 
+/**
+ * omap_hwmod_init_regbits - init sysconfig specific register bits
+ * @dev: struct device
+ * @data: module data
+ * @sysc_fields: new sysc configuration
+ */
+static int omap_hwmod_init_regbits(struct device *dev,
+				   const struct ti_sysc_module_data *data,
+				   struct sysc_regbits **sysc_fields)
+{
+	*sysc_fields = NULL;
+
+	switch (data->cap->type) {
+	case TI_SYSC_OMAP2:
+	case TI_SYSC_OMAP2_TIMER:
+		*sysc_fields = &omap_hwmod_sysc_type1;
+		break;
+	case TI_SYSC_OMAP3_SHAM:
+		*sysc_fields = &omap3_sham_sysc_fields;
+		break;
+	case TI_SYSC_OMAP3_AES:
+		*sysc_fields = &omap3xxx_aes_sysc_fields;
+		break;
+	case TI_SYSC_OMAP4:
+	case TI_SYSC_OMAP4_TIMER:
+		*sysc_fields = &omap_hwmod_sysc_type2;
+		break;
+	case TI_SYSC_OMAP4_SIMPLE:
+		*sysc_fields = &omap_hwmod_sysc_type3;
+		break;
+	case TI_SYSC_OMAP34XX_SR:
+		*sysc_fields = &omap34xx_sr_sysc_fields;
+		break;
+	case TI_SYSC_OMAP36XX_SR:
+		*sysc_fields = &omap36xx_sr_sysc_fields;
+		break;
+	case TI_SYSC_OMAP4_SR:
+		*sysc_fields = &omap36xx_sr_sysc_fields;
+		break;
+	case TI_SYSC_OMAP4_MCASP:
+		*sysc_fields = &omap_hwmod_sysc_type_mcasp;
+		break;
+	case TI_SYSC_OMAP4_USB_HOST_FS:
+		*sysc_fields = &omap_hwmod_sysc_type_usb_host_fs;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * omap_hwmod_init_reg_offs - initialize sysconfig register offsets
+ * @dev: struct device
+ * @data: module data
+ * @rev_offs: revision register offset
+ * @sysc_offs: sysc register offset
+ * @syss_offs: syss register offset
+ */
+int omap_hwmod_init_reg_offs(struct device *dev,
+			     const struct ti_sysc_module_data *data,
+			     u32 *rev_offs, u32 *sysc_offs, u32 *syss_offs)
+{
+	*rev_offs = 0;
+	*sysc_offs = 0;
+	*syss_offs = 0;
+
+	if (data->offsets[SYSC_REVISION] > 0)
+		*rev_offs = data->offsets[SYSC_REVISION];
+
+	if (data->offsets[SYSC_SYSCONFIG] > 0)
+		*sysc_offs = data->offsets[SYSC_SYSCONFIG];
+
+	if (data->offsets[SYSC_SYSSTATUS] > 0)
+		*syss_offs = data->offsets[SYSC_SYSSTATUS];
+
+	return 0;
+}
+
+/**
+ * omap_hwmod_init_sysc_flags - initialize sysconfig features
+ * @dev: struct device
+ * @data: module data
+ * @sysc_flags: module configuration
+ */
+int omap_hwmod_init_sysc_flags(struct device *dev,
+			       const struct ti_sysc_module_data *data,
+			       u32 *sysc_flags)
+{
+	*sysc_flags = 0;
+
+	switch (data->cap->type) {
+	case TI_SYSC_OMAP2:
+	case TI_SYSC_OMAP2_TIMER:
+		/* See SYSC_OMAP2_* in include/dt-bindings/bus/ti-sysc.h */
+		if (data->cfg->sysc_val & SYSC_OMAP2_CLOCKACTIVITY)
+			*sysc_flags |= SYSC_HAS_CLOCKACTIVITY;
+		if (data->cfg->sysc_val & SYSC_OMAP2_EMUFREE)
+			*sysc_flags |= SYSC_HAS_EMUFREE;
+		if (data->cfg->sysc_val & SYSC_OMAP2_ENAWAKEUP)
+			*sysc_flags |= SYSC_HAS_ENAWAKEUP;
+		if (data->cfg->sysc_val & SYSC_OMAP2_SOFTRESET)
+			*sysc_flags |= SYSC_HAS_SOFTRESET;
+		if (data->cfg->sysc_val & SYSC_OMAP2_AUTOIDLE)
+			*sysc_flags |= SYSC_HAS_AUTOIDLE;
+		break;
+	case TI_SYSC_OMAP4:
+	case TI_SYSC_OMAP4_TIMER:
+		/* See SYSC_OMAP4_* in include/dt-bindings/bus/ti-sysc.h */
+		if (data->cfg->sysc_val & SYSC_OMAP4_DMADISABLE)
+			*sysc_flags |= SYSC_HAS_DMADISABLE;
+		if (data->cfg->sysc_val & SYSC_OMAP4_FREEEMU)
+			*sysc_flags |= SYSC_HAS_EMUFREE;
+		if (data->cfg->sysc_val & SYSC_OMAP4_SOFTRESET)
+			*sysc_flags |= SYSC_HAS_SOFTRESET;
+		break;
+	case TI_SYSC_OMAP34XX_SR:
+	case TI_SYSC_OMAP36XX_SR:
+		/* See SYSC_OMAP3_SR_* in include/dt-bindings/bus/ti-sysc.h */
+		if (data->cfg->sysc_val & SYSC_OMAP3_SR_ENAWAKEUP)
+			*sysc_flags |= SYSC_HAS_ENAWAKEUP;
+		break;
+	default:
+		if (data->cap->regbits->emufree_shift >= 0)
+			*sysc_flags |= SYSC_HAS_EMUFREE;
+		if (data->cap->regbits->enwkup_shift >= 0)
+			*sysc_flags |= SYSC_HAS_ENAWAKEUP;
+		if (data->cap->regbits->srst_shift >= 0)
+			*sysc_flags |= SYSC_HAS_SOFTRESET;
+		if (data->cap->regbits->autoidle_shift >= 0)
+			*sysc_flags |= SYSC_HAS_AUTOIDLE;
+		break;
+	}
+
+	if (data->cap->regbits->midle_shift >= 0 &&
+	    data->cfg->midlemodes)
+		*sysc_flags |= SYSC_HAS_MIDLEMODE;
+
+	if (data->cap->regbits->sidle_shift >= 0 &&
+	    data->cfg->sidlemodes)
+		*sysc_flags |= SYSC_HAS_SIDLEMODE;
+
+	if (data->cfg->quirks & SYSC_QUIRK_UNCACHED)
+		*sysc_flags |= SYSC_NO_CACHE;
+	if (data->cfg->quirks & SYSC_QUIRK_RESET_STATUS)
+		*sysc_flags |= SYSC_HAS_RESET_STATUS;
+
+	if (data->cfg->syss_mask & 1)
+		*sysc_flags |= SYSS_HAS_RESET_STATUS;
+
+	return 0;
+}
+
+/**
+ * omap_hwmod_init_idlemodes - initialize module idle modes
+ * @dev: struct device
+ * @data: module data
+ * @idlemodes: module supported idle modes
+ */
+int omap_hwmod_init_idlemodes(struct device *dev,
+			      const struct ti_sysc_module_data *data,
+			      u32 *idlemodes)
+{
+	*idlemodes = 0;
+
+	if (data->cfg->midlemodes & BIT(SYSC_IDLE_FORCE))
+		*idlemodes |= MSTANDBY_FORCE;
+	if (data->cfg->midlemodes & BIT(SYSC_IDLE_NO))
+		*idlemodes |= MSTANDBY_NO;
+	if (data->cfg->midlemodes & BIT(SYSC_IDLE_SMART))
+		*idlemodes |= MSTANDBY_SMART;
+	if (data->cfg->midlemodes & BIT(SYSC_IDLE_SMART_WKUP))
+		*idlemodes |= MSTANDBY_SMART_WKUP;
+
+	if (data->cfg->sidlemodes & BIT(SYSC_IDLE_FORCE))
+		*idlemodes |= SIDLE_FORCE;
+	if (data->cfg->sidlemodes & BIT(SYSC_IDLE_NO))
+		*idlemodes |= SIDLE_NO;
+	if (data->cfg->sidlemodes & BIT(SYSC_IDLE_SMART))
+		*idlemodes |= SIDLE_SMART;
+	if (data->cfg->sidlemodes & BIT(SYSC_IDLE_SMART_WKUP))
+		*idlemodes |= SIDLE_SMART_WKUP;
+
+	return 0;
+}
+
+/**
+ * omap_hwmod_allocate_module - allocate new module
+ * @dev: struct device
+ * @oh: module
+ * @sysc_fields: sysc register bits
+ * @rev_offs: revision register offset
+ * @sysc_offs: sysconfig register offset
+ * @syss_offs: sysstatus register offset
+ * @sysc_flags: sysc specific flags
+ * @idlemodes: sysc supported idlemodes
+ *
+ * Note that the allocations here cannot use devm as ti-sysc can rebind.
+ */
+int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
+			       const struct ti_sysc_module_data *data,
+			       struct sysc_regbits *sysc_fields,
+			       u32 rev_offs, u32 sysc_offs, u32 syss_offs,
+			       u32 sysc_flags, u32 idlemodes)
+{
+	struct omap_hwmod_class_sysconfig *sysc;
+	struct omap_hwmod_class *class;
+	void __iomem *regs = NULL;
+	unsigned long flags;
+
+	sysc = kzalloc(sizeof(*sysc), GFP_KERNEL);
+	if (!sysc)
+		return -ENOMEM;
+
+	sysc->sysc_fields = sysc_fields;
+	sysc->rev_offs = rev_offs;
+	sysc->sysc_offs = sysc_offs;
+	sysc->syss_offs = syss_offs;
+	sysc->sysc_flags = sysc_flags;
+	sysc->idlemodes = idlemodes;
+	sysc->srst_udelay = data->cfg->srst_udelay;
+
+	if (!oh->_mpu_rt_va) {
+		regs = ioremap(data->module_pa,
+			       data->module_size);
+		if (!regs)
+			return -ENOMEM;
+	}
+
+	/*
+	 * We need new oh->class as the other devices in the same class
+	 * may not yet have ioremapped their registers.
+	 */
+	class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL);
+	if (!class)
+		return -ENOMEM;
+
+	class->sysc = sysc;
+
+	spin_lock_irqsave(&oh->_lock, flags);
+	if (regs)
+		oh->_mpu_rt_va = regs;
+	oh->class = class;
+	oh->_state = _HWMOD_STATE_INITIALIZED;
+	_setup(oh, NULL);
+	spin_unlock_irqrestore(&oh->_lock, flags);
+
+	return 0;
+}
+
+/**
+ * omap_hwmod_init_module - initialize new module
+ * @dev: struct device
+ * @data: module data
+ * @cookie: cookie for the caller to use for later calls
+ */
+int omap_hwmod_init_module(struct device *dev,
+			   const struct ti_sysc_module_data *data,
+			   struct ti_sysc_cookie *cookie)
+{
+	struct omap_hwmod *oh;
+	struct sysc_regbits *sysc_fields;
+	u32 rev_offs, sysc_offs, syss_offs, sysc_flags, idlemodes;
+	int error;
+
+	if (!dev || !data)
+		return -EINVAL;
+
+	oh = _lookup(data->name);
+	if (!oh)
+		return -ENODEV;
+
+	cookie->data = oh;
+
+	error = omap_hwmod_init_regbits(dev, data, &sysc_fields);
+	if (error)
+		return error;
+
+	error = omap_hwmod_init_reg_offs(dev, data, &rev_offs,
+					 &sysc_offs, &syss_offs);
+	if (error)
+		return error;
+
+	error = omap_hwmod_init_sysc_flags(dev, data, &sysc_flags);
+	if (error)
+		return error;
+
+	error = omap_hwmod_init_idlemodes(dev, data, &idlemodes);
+	if (error)
+		return error;
+
+	if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE_ON_INIT)
+		oh->flags |= HWMOD_INIT_NO_IDLE;
+	if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
+		oh->flags |= HWMOD_INIT_NO_RESET;
+
+	if (oh->class->sysc)
+		return 0;
+
+	return omap_hwmod_allocate_module(dev, oh, data, sysc_fields,
+					  rev_offs, sysc_offs, syss_offs,
+					  sysc_flags, idlemodes);
+}
+
 /**
  * omap_hwmod_setup_earlycon_flags - set up flags for early console
  *
diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
--- a/arch/arm/mach-omap2/omap_hwmod.h
+++ b/arch/arm/mach-omap2/omap_hwmod.h
@@ -620,6 +620,13 @@ int omap_hwmod_parse_module_range(struct omap_hwmod *oh,
 				  struct device_node *np,
 				  struct resource *res);
 
+struct ti_sysc_module_data;
+struct ti_sysc_cookie;
+
+int omap_hwmod_init_module(struct device *dev,
+			   const struct ti_sysc_module_data *data,
+			   struct ti_sysc_cookie *cookie);
+
 int omap_hwmod_enable(struct omap_hwmod *oh);
 int omap_hwmod_idle(struct omap_hwmod *oh);
 int omap_hwmod_shutdown(struct omap_hwmod *oh);
-- 
2.16.2

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

* [PATCH 09/12] ARM: OMAP2+: Add checks for device tree based sysconfig data
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
                   ` (7 preceding siblings ...)
  2018-02-23 21:00 ` [PATCH 08/12] ARM: OMAP2+: Add functions to allocate module data from device tree Tony Lindgren
@ 2018-02-23 21:00 ` Tony Lindgren
  2018-02-23 21:00 ` [PATCH 10/12] ARM: OMAP2+: Try to parse earlycon from parent too Tony Lindgren
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel, Paul Walmsley

We can check the device tree based sysconfig data against the existing
platform data to make sure we're not introducing regressions. Then at
some point after the sysconfig data comes from device tree, we can just
drop the related platform data.

Cc: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 arch/arm/mach-omap2/omap_hwmod.c | 109 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 106 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -3062,6 +3062,53 @@ int __init omap_hwmod_setup_one(const char *oh_name)
 	return 0;
 }
 
+static void omap_hwmod_check_one(struct device *dev,
+				 const char *name, s8 v1, u8 v2)
+{
+	if (v1 < 0)
+		return;
+
+	if (v1 != v2)
+		dev_warn(dev, "%s %d != %d\n", name, v1, v2);
+}
+
+/**
+ * omap_hwmod_check_sysc - check sysc against platform sysc
+ * @dev: struct device
+ * @data: module data
+ * @sysc_fields: new sysc configuration
+ */
+static int omap_hwmod_check_sysc(struct device *dev,
+				 const struct ti_sysc_module_data *data,
+				 struct sysc_regbits *sysc_fields)
+{
+	const struct sysc_regbits *regbits = data->cap->regbits;
+
+	omap_hwmod_check_one(dev, "dmadisable_shift",
+			     regbits->dmadisable_shift,
+			     sysc_fields->dmadisable_shift);
+	omap_hwmod_check_one(dev, "midle_shift",
+			     regbits->midle_shift,
+			     sysc_fields->midle_shift);
+	omap_hwmod_check_one(dev, "sidle_shift",
+			     regbits->sidle_shift,
+			     sysc_fields->sidle_shift);
+	omap_hwmod_check_one(dev, "clkact_shift",
+			     regbits->clkact_shift,
+			     sysc_fields->clkact_shift);
+	omap_hwmod_check_one(dev, "enwkup_shift",
+			     regbits->enwkup_shift,
+			     sysc_fields->enwkup_shift);
+	omap_hwmod_check_one(dev, "srst_shift",
+			     regbits->srst_shift,
+			     sysc_fields->srst_shift);
+	omap_hwmod_check_one(dev, "autoidle_shift",
+			     regbits->autoidle_shift,
+			     sysc_fields->autoidle_shift);
+
+	return 0;
+}
+
 /**
  * omap_hwmod_init_regbits - init sysconfig specific register bits
  * @dev: struct device
@@ -3111,7 +3158,7 @@ static int omap_hwmod_init_regbits(struct device *dev,
 		return -EINVAL;
 	}
 
-	return 0;
+	return omap_hwmod_check_sysc(dev, data, *sysc_fields);
 }
 
 /**
@@ -3249,6 +3296,59 @@ int omap_hwmod_init_idlemodes(struct device *dev,
 	return 0;
 }
 
+/**
+ * omap_hwmod_check_module - check new module against platform data
+ * @dev: struct device
+ * @oh: module
+ * @data: new module data
+ * @sysc_fields: sysc register bits
+ * @rev_offs: revision register offset
+ * @sysc_offs: sysconfig register offset
+ * @syss_offs: sysstatus register offset
+ * @sysc_flags: sysc specific flags
+ * @idlemodes: sysc supported idlemodes
+ */
+static int omap_hwmod_check_module(struct device *dev,
+				   struct omap_hwmod *oh,
+				   const struct ti_sysc_module_data *data,
+				   struct sysc_regbits *sysc_fields,
+				   u32 rev_offs, u32 sysc_offs,
+				   u32 syss_offs, u32 sysc_flags,
+				   u32 idlemodes)
+{
+	if (!oh->class->sysc)
+		return -ENODEV;
+
+	if (sysc_fields != oh->class->sysc->sysc_fields)
+		dev_warn(dev, "sysc_fields %p != %p\n", sysc_fields,
+			 oh->class->sysc->sysc_fields);
+
+	if (rev_offs != oh->class->sysc->rev_offs)
+		dev_warn(dev, "rev_offs %08x != %08x\n", rev_offs,
+			 oh->class->sysc->rev_offs);
+	if (sysc_offs != oh->class->sysc->sysc_offs)
+		dev_warn(dev, "sysc_offs %08x != %08x\n", sysc_offs,
+			 oh->class->sysc->sysc_offs);
+	if (syss_offs != oh->class->sysc->syss_offs)
+		dev_warn(dev, "syss_offs %08x != %08x\n", syss_offs,
+			 oh->class->sysc->syss_offs);
+
+	if (sysc_flags != oh->class->sysc->sysc_flags)
+		dev_warn(dev, "sysc_flags %08x != %08x\n", sysc_flags,
+			 oh->class->sysc->sysc_flags);
+
+	if (idlemodes != oh->class->sysc->idlemodes)
+		dev_warn(dev, "idlemodes %08x != %08x\n", idlemodes,
+			 oh->class->sysc->idlemodes);
+
+	if (data->cfg->srst_udelay != oh->class->sysc->srst_udelay)
+		dev_warn(dev, "srst_udelay %i != %i\n",
+			 data->cfg->srst_udelay,
+			 oh->class->sysc->srst_udelay);
+
+	return 0;
+}
+
 /**
  * omap_hwmod_allocate_module - allocate new module
  * @dev: struct device
@@ -3359,8 +3459,11 @@ int omap_hwmod_init_module(struct device *dev,
 	if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
 		oh->flags |= HWMOD_INIT_NO_RESET;
 
-	if (oh->class->sysc)
-		return 0;
+	error = omap_hwmod_check_module(dev, oh, data, sysc_fields,
+					rev_offs, sysc_offs, syss_offs,
+					sysc_flags, idlemodes);
+	if (!error)
+		return error;
 
 	return omap_hwmod_allocate_module(dev, oh, data, sysc_fields,
 					  rev_offs, sysc_offs, syss_offs,
-- 
2.16.2

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

* [PATCH 10/12] ARM: OMAP2+: Try to parse earlycon from parent too
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
                   ` (8 preceding siblings ...)
  2018-02-23 21:00 ` [PATCH 09/12] ARM: OMAP2+: Add checks for device tree based sysconfig data Tony Lindgren
@ 2018-02-23 21:00 ` Tony Lindgren
  2018-02-23 21:00 ` [PATCH 11/12] PM / AVS: SmartReflex: Prepare to use device tree based probing Tony Lindgren
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel, Paul Walmsley

With ti-sysc driver the "ti,hwmods" property will be moved to the
interconnect target module instead of the child device. To keep
earlycon working, we need to match against the interconnect target
module in the ti-sysc case.

Cc: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 arch/arm/mach-omap2/omap_hwmod.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -3492,6 +3492,12 @@ static void __init omap_hwmod_setup_earlycon_flags(void)
 			if (np) {
 				uart = of_get_property(np, "ti,hwmods", NULL);
 				oh = omap_hwmod_lookup(uart);
+				if (!oh) {
+					uart = of_get_property(np->parent,
+							       "ti,hwmods",
+							       NULL);
+					oh = omap_hwmod_lookup(uart);
+				}
 				if (oh)
 					oh->flags |= DEBUG_OMAPUART_FLAGS;
 			}
-- 
2.16.2

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

* [PATCH 11/12] PM / AVS: SmartReflex: Prepare to use device tree based probing
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
                   ` (9 preceding siblings ...)
  2018-02-23 21:00 ` [PATCH 10/12] ARM: OMAP2+: Try to parse earlycon from parent too Tony Lindgren
@ 2018-02-23 21:00 ` Tony Lindgren
  2018-02-26 10:37   ` Rafael J. Wysocki
  2018-03-01  3:07   ` Kevin Hilman
  2018-02-23 21:01 ` [PATCH 12/12] ARM: OMAP2+: Enable ti-sysc to use device tree data for smartreflex Tony Lindgren
  2018-02-23 21:41 ` [PATCH 0.5/12] ARM: OMAP2+: Prepare to pass auxdata " Tony Lindgren
  12 siblings, 2 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:00 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel, linux-pm, Rafael J . Wysocki

We are currently probing smartreflex with omap_device while we are
already probing smartreflex related interconnect target module with
ti-sysc driver and dts data.

Before we can flip things on for ti-sysc, we need to prepare the
smartreflex driver a bit:

1. The smartreflex clock is really for the whole interconnect target
   module. So it may be configured at the parent device level with
   ti-sysc

2. With ti-sysc, we have the child device manage interconnect target
   module directly if pm_runtime_irq_safe() is set and there is only
   one child. In that case nobody else is going to call pm_runtime_get
   and put, so we need to add these calls to idle smartreflex properly
   after probe if not fully configured

3. With ti-sysc, the parent driver may rebind. So we want to use
   platform_driver_register() and don't want probe to be __init

Note that this patch depends on the related changes to ti-sysc driver
and omap_device probing to prevent both ti-sysc and omap_device to
try to probe smartreflex.

Cc: linux-pm@vger.kernel.org
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/power/avs/smartreflex.c | 41 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 34 insertions(+), 7 deletions(-)

diff --git a/drivers/power/avs/smartreflex.c b/drivers/power/avs/smartreflex.c
--- a/drivers/power/avs/smartreflex.c
+++ b/drivers/power/avs/smartreflex.c
@@ -132,12 +132,16 @@ static void sr_set_clk_length(struct omap_sr *sr)
 	struct clk *fck;
 	u32 fclk_speed;
 
-	fck = clk_get(&sr->pdev->dev, "fck");
-
+	/* Try interconnect target module fck first if it already exists */
+	fck = clk_get(sr->pdev->dev.parent, "fck");
 	if (IS_ERR(fck)) {
-		dev_err(&sr->pdev->dev, "%s: unable to get fck for device %s\n",
-			__func__, dev_name(&sr->pdev->dev));
-		return;
+		fck = clk_get(&sr->pdev->dev, "fck");
+		if (IS_ERR(fck)) {
+			dev_err(&sr->pdev->dev,
+				"%s: unable to get fck for device %s\n",
+				__func__, dev_name(&sr->pdev->dev));
+			return;
+		}
 	}
 
 	fclk_speed = clk_get_rate(fck);
@@ -838,7 +842,7 @@ static int omap_sr_autocomp_store(void *data, u64 val)
 DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
 			omap_sr_autocomp_store, "%llu\n");
 
-static int __init omap_sr_probe(struct platform_device *pdev)
+static int omap_sr_probe(struct platform_device *pdev)
 {
 	struct omap_sr *sr_info;
 	struct omap_sr_data *pdata = pdev->dev.platform_data;
@@ -898,6 +902,12 @@ static int __init omap_sr_probe(struct platform_device *pdev)
 
 	list_add(&sr_info->node, &sr_list);
 
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(&pdev->dev);
+		goto err_list_del;
+	}
+
 	/*
 	 * Call into late init to do initializations that require
 	 * both sr driver and sr class driver to be initiallized.
@@ -966,12 +976,17 @@ static int __init omap_sr_probe(struct platform_device *pdev)
 
 	}
 
+	pm_runtime_put_sync(&pdev->dev);
+
 	return ret;
 
 err_debugfs:
 	debugfs_remove_recursive(sr_info->dbg_dir);
 err_list_del:
 	list_del(&sr_info->node);
+
+	pm_runtime_put_sync(&pdev->dev);
+
 	return ret;
 }
 
@@ -1025,11 +1040,23 @@ static void omap_sr_shutdown(struct platform_device *pdev)
 	return;
 }
 
+static const struct of_device_id omap_sr_match[] = {
+	{ .compatible = "ti,omap3-smartreflex-core", },
+	{ .compatible = "ti,omap3-smartreflex-mpu-iva", },
+	{ .compatible = "ti,omap4-smartreflex-core", },
+	{ .compatible = "ti,omap4-smartreflex-mpu", },
+	{ .compatible = "ti,omap4-smartreflex-iva", },
+	{  },
+};
+MODULE_DEVICE_TABLE(of, omap_sr_match);
+
 static struct platform_driver smartreflex_driver = {
+	.probe		= omap_sr_probe,
 	.remove         = omap_sr_remove,
 	.shutdown	= omap_sr_shutdown,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.of_match_table	= omap_sr_match,
 	},
 };
 
@@ -1048,7 +1075,7 @@ static int __init sr_init(void)
 	else
 		pr_warn("%s: No PMIC hook to init smartreflex\n", __func__);
 
-	ret = platform_driver_probe(&smartreflex_driver, omap_sr_probe);
+	ret = platform_driver_register(&smartreflex_driver);
 	if (ret) {
 		pr_err("%s: platform driver register failed for SR\n",
 		       __func__);
-- 
2.16.2

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

* [PATCH 12/12] ARM: OMAP2+: Enable ti-sysc to use device tree data for smartreflex
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
                   ` (10 preceding siblings ...)
  2018-02-23 21:00 ` [PATCH 11/12] PM / AVS: SmartReflex: Prepare to use device tree based probing Tony Lindgren
@ 2018-02-23 21:01 ` Tony Lindgren
  2018-02-23 21:41 ` [PATCH 0.5/12] ARM: OMAP2+: Prepare to pass auxdata " Tony Lindgren
  12 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:01 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel

Let's enable ti-sysc probing of child devices. So far we have only used
ti-sysc to probe interconnect target modules to idle them for cases where
the SoC does not have any child devices configured for the module, such
as smartreflex on dra7.

As we have smartreflex driver configured in the device tree for some SoCs,
we need to flip things on with a single patch to prevent both omap_device
and ti-sysc to probe smartreflex. So let's stop probing smartreflex with
omap_device and probe it with ti-sysc by enabling passing the auxdata.

Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 arch/arm/mach-omap2/omap_device.c  |  5 +++++
 arch/arm/mach-omap2/pdata-quirks.c |  1 +
 arch/arm/mach-omap2/sr_device.c    | 25 ++++++++++++++-----------
 3 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
--- a/arch/arm/mach-omap2/omap_device.c
+++ b/arch/arm/mach-omap2/omap_device.c
@@ -140,6 +140,7 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
 	struct omap_device *od;
 	struct omap_hwmod *oh;
 	struct device_node *node = pdev->dev.of_node;
+	struct resource res;
 	const char *oh_name;
 	int oh_cnt, i, ret = 0;
 	bool device_active = false;
@@ -150,6 +151,10 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
+	/* Use ti-sysc driver instead of omap_device? */
+	if (!omap_hwmod_parse_module_range(NULL, node, &res))
+		return -ENODEV;
+
 	hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
 	if (!hwmods) {
 		ret = -ENOMEM;
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -487,6 +487,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[];
 
 static struct ti_sysc_platform_data ti_sysc_pdata = {
 	.auxdata = omap_auxdata_lookup,
+	.init_module = omap_hwmod_init_module,
 	.enable_module = ti_sysc_enable_module,
 	.idle_module = ti_sysc_idle_module,
 	.shutdown_module = ti_sysc_shutdown_module,
diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c
--- a/arch/arm/mach-omap2/sr_device.c
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -93,16 +93,23 @@ extern struct omap_sr_data omap_sr_pdata[];
 
 static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
 {
-	struct omap_sr_data *sr_data;
-	struct platform_device *pdev;
+	struct omap_sr_data *sr_data = NULL;
 	struct omap_volt_data *volt_data;
 	struct omap_smartreflex_dev_attr *sr_dev_attr;
-	char *name = "smartreflex";
 	static int i;
 
-	sr_data = kzalloc(sizeof(*sr_data), GFP_KERNEL);
-	if (!sr_data)
-		return -ENOMEM;
+	if (!strncmp(oh->name, "smartreflex_mpu_iva", 20) ||
+	    !strncmp(oh->name, "smartreflex_mpu", 16))
+		sr_data = &omap_sr_pdata[OMAP_SR_MPU];
+	else if (!strncmp(oh->name, "smartreflex_core", 17))
+		sr_data = &omap_sr_pdata[OMAP_SR_CORE];
+	else if (!strncmp(oh->name, "smartreflex_iva", 16))
+		sr_data = &omap_sr_pdata[OMAP_SR_IVA];
+
+	if (!sr_data) {
+		pr_err("%s: Unknown instance %s\n", __func__, oh->name);
+		return -EINVAL;
+	}
 
 	sr_dev_attr = (struct omap_smartreflex_dev_attr *)oh->dev_attr;
 	if (!sr_dev_attr || !sr_dev_attr->sensor_voltdm_name) {
@@ -147,13 +154,9 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
 
 	sr_data->enable_on_init = sr_enable_on_init;
 
-	pdev = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data));
-	if (IS_ERR(pdev))
-		pr_warn("%s: Could not build omap_device for %s: %s\n",
-			__func__, name, oh->name);
 exit:
 	i++;
-	kfree(sr_data);
+
 	return 0;
 }
 
-- 
2.16.2

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

* [PATCH 0.5/12] ARM: OMAP2+: Prepare to pass auxdata for smartreflex
  2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
                   ` (11 preceding siblings ...)
  2018-02-23 21:01 ` [PATCH 12/12] ARM: OMAP2+: Enable ti-sysc to use device tree data for smartreflex Tony Lindgren
@ 2018-02-23 21:41 ` Tony Lindgren
  2018-02-26  8:37   ` kbuild test robot
  12 siblings, 1 reply; 21+ messages in thread
From: Tony Lindgren @ 2018-02-23 21:41 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel

We are still initializing smartreflex with platform data using
omap_device_build(). We can instead pass the platform data in
with auxdata in pdata-quirks.c and make the driver use that
in later patches.

Note that we cannot enable the auxdata use yet, this is done
in the last patch of the series.

Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 arch/arm/mach-omap2/pdata-quirks.c | 13 +++++++++++++
 arch/arm/mach-omap2/sr_device.c    |  2 ++
 include/linux/power/smartreflex.h  |  7 +++++++
 3 files changed, 22 insertions(+)

diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -17,6 +17,7 @@
 #include <linux/wl12xx.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
+#include <linux/power/smartreflex.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
 
@@ -542,6 +543,8 @@ static struct pdata_init auxdata_quirks[] __initdata = {
 	{ /* sentinel */ },
 };
 
+struct omap_sr_data __maybe_unused omap_sr_pdata[OMAP_SR_NR];
+
 static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 #ifdef CONFIG_MACH_NOKIA_N8X0
 	OF_DEV_AUXDATA("ti,omap2420-mmc", 0x4809c000, "mmci-omap.0", NULL),
@@ -551,6 +554,10 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 #ifdef CONFIG_ARCH_OMAP3
 	OF_DEV_AUXDATA("ti,omap2-iommu", 0x5d000000, "5d000000.mmu",
 		       &omap3_iommu_pdata),
+	OF_DEV_AUXDATA("ti,omap3-smartreflex-core", 0x480cb000,
+		       "480cb000.smartreflex", &omap_sr_pdata[OMAP_SR_CORE]),
+	OF_DEV_AUXDATA("ti,omap3-smartreflex-mpu-iva", 0x480c9000,
+		       "480c9000.smartreflex", &omap_sr_pdata[OMAP_SR_MPU]),
 	OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x4809c000, "4809c000.mmc", &mmc_pdata[0]),
 	OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x480b4000, "480b4000.mmc", &mmc_pdata[1]),
 	OF_DEV_AUXDATA("nokia,n900-ir", 0, "n900-ir", &rx51_ir_data),
@@ -580,6 +587,12 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 		       &omap4_iommu_pdata),
 	OF_DEV_AUXDATA("ti,omap4-iommu", 0x55082000, "55082000.mmu",
 		       &omap4_iommu_pdata),
+	OF_DEV_AUXDATA("ti,omap4-smartreflex-iva", 0x4a0db000,
+		       "4a0db000.smartreflex", &omap_sr_pdata[OMAP_SR_IVA]),
+	OF_DEV_AUXDATA("ti,omap4-smartreflex-core", 0x4a0dd000,
+		       "4a0dd000.smartreflex", &omap_sr_pdata[OMAP_SR_CORE]),
+	OF_DEV_AUXDATA("ti,omap4-smartreflex-mpu", 0x4a0d9000,
+		       "4a0d9000.smartreflex", &omap_sr_pdata[OMAP_SR_MPU]),
 #endif
 #ifdef CONFIG_SOC_DRA7XX
 	OF_DEV_AUXDATA("ti,dra7-hsmmc", 0x4809c000, "4809c000.mmc",
diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c
--- a/arch/arm/mach-omap2/sr_device.c
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -89,6 +89,8 @@ static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
 	sr_data->nvalue_count = j;
 }
 
+extern struct omap_sr_data omap_sr_pdata[];
+
 static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
 {
 	struct omap_sr_data *sr_data;
diff --git a/include/linux/power/smartreflex.h b/include/linux/power/smartreflex.h
--- a/include/linux/power/smartreflex.h
+++ b/include/linux/power/smartreflex.h
@@ -143,6 +143,13 @@
 #define OMAP3430_SR_ERRWEIGHT		0x04
 #define OMAP3430_SR_ERRMAXLIMIT		0x02
 
+enum sr_instance {
+	OMAP_SR_MPU,			/* shared with iva on omap3 */
+	OMAP_SR_CORE,
+	OMAP_SR_IVA,
+	OMAP_SR_NR,
+};
+
 struct omap_sr {
 	char				*name;
 	struct list_head		node;
-- 
2.16.2

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

* Re: [PATCH 0.5/12] ARM: OMAP2+: Prepare to pass auxdata for smartreflex
  2018-02-23 21:41 ` [PATCH 0.5/12] ARM: OMAP2+: Prepare to pass auxdata " Tony Lindgren
@ 2018-02-26  8:37   ` kbuild test robot
  2018-02-26 22:23     ` Tony Lindgren
  0 siblings, 1 reply; 21+ messages in thread
From: kbuild test robot @ 2018-02-26  8:37 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: kbuild-all, linux-omap, Dave Gerlach, Nishanth Menon, Suman Anna,
	Tero Kristo, linux-kernel, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 1374 bytes --]

Hi Tony,

I love your patch! Yet something to improve:

[auto build test ERROR on omap/for-next]
[also build test ERROR on v4.16-rc3 next-20180226]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Tony-Lindgren/ARM-OMAP2-Prepare-to-pass-auxdata-for-smartreflex/20180226-132741
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git for-next
config: arm-multi_v7_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All errors (new ones prefixed by >>):

>> arch/arm/mach-omap2/pdata-quirks.c:517:36: error: array type has incomplete element type 'struct omap_sr_data'
    struct omap_sr_data __maybe_unused omap_sr_pdata[OMAP_SR_NR];
                                       ^~~~~~~~~~~~~

vim +517 arch/arm/mach-omap2/pdata-quirks.c

   516	
 > 517	struct omap_sr_data __maybe_unused omap_sr_pdata[OMAP_SR_NR];
   518	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 43115 bytes --]

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

* Re: [PATCH 11/12] PM / AVS: SmartReflex: Prepare to use device tree based probing
  2018-02-23 21:00 ` [PATCH 11/12] PM / AVS: SmartReflex: Prepare to use device tree based probing Tony Lindgren
@ 2018-02-26 10:37   ` Rafael J. Wysocki
  2018-02-26 21:34     ` Tony Lindgren
  2018-03-01  3:07   ` Kevin Hilman
  1 sibling, 1 reply; 21+ messages in thread
From: Rafael J. Wysocki @ 2018-02-26 10:37 UTC (permalink / raw)
  To: Tony Lindgren, linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel, linux-pm, Kevin Hilman

On 2/23/2018 10:00 PM, Tony Lindgren wrote:
> We are currently probing smartreflex with omap_device while we are
> already probing smartreflex related interconnect target module with
> ti-sysc driver and dts data.
>
> Before we can flip things on for ti-sysc, we need to prepare the
> smartreflex driver a bit:
>
> 1. The smartreflex clock is really for the whole interconnect target
>     module. So it may be configured at the parent device level with
>     ti-sysc
>
> 2. With ti-sysc, we have the child device manage interconnect target
>     module directly if pm_runtime_irq_safe() is set and there is only
>     one child. In that case nobody else is going to call pm_runtime_get
>     and put, so we need to add these calls to idle smartreflex properly
>     after probe if not fully configured
>
> 3. With ti-sysc, the parent driver may rebind. So we want to use
>     platform_driver_register() and don't want probe to be __init
>
> Note that this patch depends on the related changes to ti-sysc driver
> and omap_device probing to prevent both ti-sysc and omap_device to
> try to probe smartreflex.
>
> Cc: linux-pm@vger.kernel.org
> Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Signed-off-by: Tony Lindgren <tony@atomide.com>

You need an ACK from Kevin Hilman on this anyway and if you receive one, 
please feel free to route it whatever way is convenient for you.

> ---
>   drivers/power/avs/smartreflex.c | 41 ++++++++++++++++++++++++++++++++++-------
>   1 file changed, 34 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/power/avs/smartreflex.c b/drivers/power/avs/smartreflex.c
> --- a/drivers/power/avs/smartreflex.c
> +++ b/drivers/power/avs/smartreflex.c
> @@ -132,12 +132,16 @@ static void sr_set_clk_length(struct omap_sr *sr)
>   	struct clk *fck;
>   	u32 fclk_speed;
>   
> -	fck = clk_get(&sr->pdev->dev, "fck");
> -
> +	/* Try interconnect target module fck first if it already exists */
> +	fck = clk_get(sr->pdev->dev.parent, "fck");
>   	if (IS_ERR(fck)) {
> -		dev_err(&sr->pdev->dev, "%s: unable to get fck for device %s\n",
> -			__func__, dev_name(&sr->pdev->dev));
> -		return;
> +		fck = clk_get(&sr->pdev->dev, "fck");
> +		if (IS_ERR(fck)) {
> +			dev_err(&sr->pdev->dev,
> +				"%s: unable to get fck for device %s\n",
> +				__func__, dev_name(&sr->pdev->dev));
> +			return;
> +		}
>   	}
>   
>   	fclk_speed = clk_get_rate(fck);
> @@ -838,7 +842,7 @@ static int omap_sr_autocomp_store(void *data, u64 val)
>   DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
>   			omap_sr_autocomp_store, "%llu\n");
>   
> -static int __init omap_sr_probe(struct platform_device *pdev)
> +static int omap_sr_probe(struct platform_device *pdev)
>   {
>   	struct omap_sr *sr_info;
>   	struct omap_sr_data *pdata = pdev->dev.platform_data;
> @@ -898,6 +902,12 @@ static int __init omap_sr_probe(struct platform_device *pdev)
>   
>   	list_add(&sr_info->node, &sr_list);
>   
> +	ret = pm_runtime_get_sync(&pdev->dev);
> +	if (ret < 0) {
> +		pm_runtime_put_noidle(&pdev->dev);
> +		goto err_list_del;
> +	}
> +
>   	/*
>   	 * Call into late init to do initializations that require
>   	 * both sr driver and sr class driver to be initiallized.
> @@ -966,12 +976,17 @@ static int __init omap_sr_probe(struct platform_device *pdev)
>   
>   	}
>   
> +	pm_runtime_put_sync(&pdev->dev);
> +
>   	return ret;
>   
>   err_debugfs:
>   	debugfs_remove_recursive(sr_info->dbg_dir);
>   err_list_del:
>   	list_del(&sr_info->node);
> +
> +	pm_runtime_put_sync(&pdev->dev);
> +
>   	return ret;
>   }
>   
> @@ -1025,11 +1040,23 @@ static void omap_sr_shutdown(struct platform_device *pdev)
>   	return;
>   }
>   
> +static const struct of_device_id omap_sr_match[] = {
> +	{ .compatible = "ti,omap3-smartreflex-core", },
> +	{ .compatible = "ti,omap3-smartreflex-mpu-iva", },
> +	{ .compatible = "ti,omap4-smartreflex-core", },
> +	{ .compatible = "ti,omap4-smartreflex-mpu", },
> +	{ .compatible = "ti,omap4-smartreflex-iva", },
> +	{  },
> +};
> +MODULE_DEVICE_TABLE(of, omap_sr_match);
> +
>   static struct platform_driver smartreflex_driver = {
> +	.probe		= omap_sr_probe,
>   	.remove         = omap_sr_remove,
>   	.shutdown	= omap_sr_shutdown,
>   	.driver		= {
>   		.name	= DRIVER_NAME,
> +		.of_match_table	= omap_sr_match,
>   	},
>   };
>   
> @@ -1048,7 +1075,7 @@ static int __init sr_init(void)
>   	else
>   		pr_warn("%s: No PMIC hook to init smartreflex\n", __func__);
>   
> -	ret = platform_driver_probe(&smartreflex_driver, omap_sr_probe);
> +	ret = platform_driver_register(&smartreflex_driver);
>   	if (ret) {
>   		pr_err("%s: platform driver register failed for SR\n",
>   		       __func__);

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

* Re: [PATCH 11/12] PM / AVS: SmartReflex: Prepare to use device tree based probing
  2018-02-26 10:37   ` Rafael J. Wysocki
@ 2018-02-26 21:34     ` Tony Lindgren
  0 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-26 21:34 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-omap, Dave Gerlach, Nishanth Menon, Suman Anna,
	Tero Kristo, linux-kernel, linux-arm-kernel, linux-pm,
	Kevin Hilman

* Rafael J. Wysocki <rafael.j.wysocki@intel.com> [180226 10:38]:
> On 2/23/2018 10:00 PM, Tony Lindgren wrote:
> > We are currently probing smartreflex with omap_device while we are
> > already probing smartreflex related interconnect target module with
> > ti-sysc driver and dts data.
...
> You need an ACK from Kevin Hilman on this anyway and if you receive one,
> please feel free to route it whatever way is convenient for you.

Oops sorry about that Kevin. I did the Cc list from memory and
totally forgot about the MAINTAINERS entry for AVS drivers. I'll
also bounce the original email to Kevin for easier reading.

Regards,

Tony

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

* Re: [PATCH 0.5/12] ARM: OMAP2+: Prepare to pass auxdata for smartreflex
  2018-02-26  8:37   ` kbuild test robot
@ 2018-02-26 22:23     ` Tony Lindgren
  0 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-02-26 22:23 UTC (permalink / raw)
  To: kbuild test robot
  Cc: kbuild-all, linux-omap, Dave Gerlach, Nishanth Menon, Suman Anna,
	Tero Kristo, linux-kernel, linux-arm-kernel

* kbuild test robot <lkp@intel.com> [180226 08:39]:
> >> arch/arm/mach-omap2/pdata-quirks.c:517:36: error: array type has incomplete element type 'struct omap_sr_data'
>     struct omap_sr_data __maybe_unused omap_sr_pdata[OMAP_SR_NR];
>                                        ^~~~~~~~~~~~~
> 
> vim +517 arch/arm/mach-omap2/pdata-quirks.c
> 
>    516	
>  > 517	struct omap_sr_data __maybe_unused omap_sr_pdata[OMAP_SR_NR];
>    518	

Thanks kbt. Looks like it needs to be out of the ifdef
CONFIG_POWER_AVS_OMAP in include/linux/power/smartreflex.h.

Updated patch below.

Regards,

Tony

8< ---------------------
>From tony Mon Sep 17 00:00:00 2001
From: Tony Lindgren <tony@atomide.com>
Date: Thu, 22 Feb 2018 13:57:30 -0800
Subject: [PATCH] ARM: OMAP2+: Prepare to pass auxdata for smartreflex

We are still initializing smartreflex with platform data using
omap_device_build(). We can instead pass the platform data in
with auxdata in pdata-quirks.c and make the driver use that
in later patches.

Note that we cannot enable the auxdata use yet, this is done
in the last patch of the series.

Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 arch/arm/mach-omap2/pdata-quirks.c | 13 +++++++++++++
 arch/arm/mach-omap2/sr_device.c    |  2 ++
 include/linux/power/smartreflex.h  | 10 +++++++++-
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -17,6 +17,7 @@
 #include <linux/wl12xx.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
+#include <linux/power/smartreflex.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
 
@@ -542,6 +543,8 @@ static struct pdata_init auxdata_quirks[] __initdata = {
 	{ /* sentinel */ },
 };
 
+struct omap_sr_data __maybe_unused omap_sr_pdata[OMAP_SR_NR];
+
 static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 #ifdef CONFIG_MACH_NOKIA_N8X0
 	OF_DEV_AUXDATA("ti,omap2420-mmc", 0x4809c000, "mmci-omap.0", NULL),
@@ -551,6 +554,10 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 #ifdef CONFIG_ARCH_OMAP3
 	OF_DEV_AUXDATA("ti,omap2-iommu", 0x5d000000, "5d000000.mmu",
 		       &omap3_iommu_pdata),
+	OF_DEV_AUXDATA("ti,omap3-smartreflex-core", 0x480cb000,
+		       "480cb000.smartreflex", &omap_sr_pdata[OMAP_SR_CORE]),
+	OF_DEV_AUXDATA("ti,omap3-smartreflex-mpu-iva", 0x480c9000,
+		       "480c9000.smartreflex", &omap_sr_pdata[OMAP_SR_MPU]),
 	OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x4809c000, "4809c000.mmc", &mmc_pdata[0]),
 	OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x480b4000, "480b4000.mmc", &mmc_pdata[1]),
 	OF_DEV_AUXDATA("nokia,n900-ir", 0, "n900-ir", &rx51_ir_data),
@@ -580,6 +587,12 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 		       &omap4_iommu_pdata),
 	OF_DEV_AUXDATA("ti,omap4-iommu", 0x55082000, "55082000.mmu",
 		       &omap4_iommu_pdata),
+	OF_DEV_AUXDATA("ti,omap4-smartreflex-iva", 0x4a0db000,
+		       "4a0db000.smartreflex", &omap_sr_pdata[OMAP_SR_IVA]),
+	OF_DEV_AUXDATA("ti,omap4-smartreflex-core", 0x4a0dd000,
+		       "4a0dd000.smartreflex", &omap_sr_pdata[OMAP_SR_CORE]),
+	OF_DEV_AUXDATA("ti,omap4-smartreflex-mpu", 0x4a0d9000,
+		       "4a0d9000.smartreflex", &omap_sr_pdata[OMAP_SR_MPU]),
 #endif
 #ifdef CONFIG_SOC_DRA7XX
 	OF_DEV_AUXDATA("ti,dra7-hsmmc", 0x4809c000, "4809c000.mmc",
diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c
--- a/arch/arm/mach-omap2/sr_device.c
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -89,6 +89,8 @@ static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
 	sr_data->nvalue_count = j;
 }
 
+extern struct omap_sr_data omap_sr_pdata[];
+
 static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
 {
 	struct omap_sr_data *sr_data;
diff --git a/include/linux/power/smartreflex.h b/include/linux/power/smartreflex.h
--- a/include/linux/power/smartreflex.h
+++ b/include/linux/power/smartreflex.h
@@ -143,6 +143,13 @@
 #define OMAP3430_SR_ERRWEIGHT		0x04
 #define OMAP3430_SR_ERRMAXLIMIT		0x02
 
+enum sr_instance {
+	OMAP_SR_MPU,			/* shared with iva on omap3 */
+	OMAP_SR_CORE,
+	OMAP_SR_IVA,
+	OMAP_SR_NR,
+};
+
 struct omap_sr {
 	char				*name;
 	struct list_head		node;
@@ -207,7 +214,6 @@ struct omap_smartreflex_dev_attr {
 	const char      *sensor_voltdm_name;
 };
 
-#ifdef CONFIG_POWER_AVS_OMAP
 /*
  * The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR.
  * The smartreflex class driver should pass the class type.
@@ -290,6 +296,8 @@ struct omap_sr_data {
 	struct voltagedomain		*voltdm;
 };
 
+#ifdef CONFIG_POWER_AVS_OMAP
+
 /* Smartreflex module enable/disable interface */
 void omap_sr_enable(struct voltagedomain *voltdm);
 void omap_sr_disable(struct voltagedomain *voltdm);
-- 
2.16.2

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

* Re: [PATCH 07/12] bus: ti-sysc: Handle some devices in omap_device compatible way
  2018-02-23 21:00 ` [PATCH 07/12] bus: ti-sysc: Handle some devices in omap_device compatible way Tony Lindgren
@ 2018-03-01  0:37   ` Tony Lindgren
  0 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-03-01  0:37 UTC (permalink / raw)
  To: linux-omap
  Cc: Dave Gerlach, Nishanth Menon, Suman Anna, Tero Kristo,
	linux-kernel, linux-arm-kernel

* Tony Lindgren <tony@atomide.com> [180223 21:03]:
> Now that ti-sysc can manage child devices, we must also be backwards
> compatible with the current omap_device code. With omap_device, we
> assume that the child device manages the interconnect target module
> directly.
...
>  /* At this point the module is configured enough to read the revision */
>  static int sysc_init_module(struct sysc *ddata)
>  {
>  	int error;
>  
> +	if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE_ON_INIT |
> +				 SYSC_QUIRK_NO_RESET_ON_INIT)) {
> +		ddata->revision = sysc_read_revision(ddata);
> +		goto rev_quirks;
> +	}
> +
>  	error = pm_runtime_get_sync(ddata->dev);
>  	if (error < 0) {
>  		pm_runtime_put_noidle(ddata->dev);

This needs to use only SYSC_QUIRK_NO_IDLE_ON_INIT to skip PM
runtime. Otherwise the module may not be enabled when it is
being accessed.

Updated patch below.

Regards,

Tony

8< -------------------
>From tony Mon Sep 17 00:00:00 2001
From: Tony Lindgren <tony@atomide.com>
Date: Thu, 22 Feb 2018 14:03:48 -0800
Subject: [PATCH] bus: ti-sysc: Handle some devices in omap_device
 compatible way

Now that ti-sysc can manage child devices, we must also be backwards
compatible with the current omap_device code. With omap_device, we
assume that the child device manages the interconnect target module
directly.

The drivers needing special handling are the ones that still set
pm_runtime_irq_safe(). In the long run we want to update those drivers
as otherwise they will cause problems with genpd as a permanent PM
runtime usage count is set on the parent device.

We can handle omap_device these devices by improving the ti-sysc quirk
handling to detect the devices needing special handling based on
register map and revision register if usable. We also need to implement
dev_pm_domain for these child devices just like omap_device does.

Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/bus/ti-sysc.c                 | 226 +++++++++++++++++++++++++++++++++-
 include/linux/platform_data/ti-sysc.h |   1 +
 2 files changed, 224 insertions(+), 3 deletions(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -14,8 +14,10 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
@@ -68,6 +70,7 @@ struct sysc {
 	u32 revision;
 	bool enabled;
 	bool needs_resume;
+	bool child_needs_resume;
 	struct delayed_work idle_work;
 };
 
@@ -474,6 +477,14 @@ static int sysc_show_reg(struct sysc *ddata,
 	return sprintf(bufp, ":%x", ddata->offsets[reg]);
 }
 
+static int sysc_show_name(char *bufp, struct sysc *ddata)
+{
+	if (!ddata->name)
+		return 0;
+
+	return sprintf(bufp, ":%s", ddata->name);
+}
+
 /**
  * sysc_show_registers - show information about interconnect target module
  * @ddata: device driver data
@@ -488,7 +499,7 @@ static void sysc_show_registers(struct sysc *ddata)
 		bufp += sysc_show_reg(ddata, bufp, i);
 
 	bufp += sysc_show_rev(bufp, ddata);
-	bufp += sysc_show_rev(bufp, ddata);
+	bufp += sysc_show_name(bufp, ddata);
 
 	dev_dbg(ddata->dev, "%llx:%x%s\n",
 		ddata->module_pa, ddata->module_size,
@@ -612,11 +623,93 @@ static const struct dev_pm_ops sysc_pm_ops = {
 			   NULL)
 };
 
+/* Module revision register based quirks */
+struct sysc_revision_quirk {
+	const char *name;
+	u32 base;
+	int rev_offset;
+	int sysc_offset;
+	int syss_offset;
+	u32 revision;
+	u32 revision_mask;
+	u32 quirks;
+};
+
+#define SYSC_QUIRK(optname, optbase, optrev, optsysc, optsyss,		\
+		   optrev_val, optrevmask, optquirkmask)		\
+	{								\
+		.name = (optname),					\
+		.base = (optbase),					\
+		.rev_offset = (optrev),					\
+		.sysc_offset = (optsysc),				\
+		.syss_offset = (optsyss),				\
+		.revision = (optrev_val),				\
+		.revision_mask = (optrevmask),				\
+		.quirks = (optquirkmask),				\
+	}
+
+static const struct sysc_revision_quirk sysc_revision_quirks[] = {
+	/* These drivers need to be fixed to not use pm_runtime_irq_safe() */
+	SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000020, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000030, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("smartreflex", 0, -1, 0x24, -1, 0x00000000, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("smartreflex", 0, -1, 0x38, -1, 0x00000000, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+	SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
+		   SYSC_QUIRK_LEGACY_IDLE),
+};
+
+static void sysc_init_revision_quirks(struct sysc *ddata)
+{
+	const struct sysc_revision_quirk *q;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sysc_revision_quirks); i++) {
+		q = &sysc_revision_quirks[i];
+
+		if (q->base && q->base != ddata->module_pa)
+			continue;
+
+		if (q->rev_offset >= 0 &&
+		    q->rev_offset != ddata->offsets[SYSC_REVISION])
+			continue;
+
+		if (q->sysc_offset >= 0 &&
+		    q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
+			continue;
+
+		if (q->syss_offset >= 0 &&
+		    q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
+			continue;
+
+		if (q->revision == ddata->revision ||
+		    (q->revision & q->revision_mask) ==
+		    (ddata->revision & q->revision_mask)) {
+			ddata->name = q->name;
+			ddata->cfg.quirks |= q->quirks;
+		}
+	}
+}
+
 /* At this point the module is configured enough to read the revision */
 static int sysc_init_module(struct sysc *ddata)
 {
 	int error;
 
+	if (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE_ON_INIT) {
+		ddata->revision = sysc_read_revision(ddata);
+		goto rev_quirks;
+	}
+
 	error = pm_runtime_get_sync(ddata->dev);
 	if (error < 0) {
 		pm_runtime_put_noidle(ddata->dev);
@@ -626,6 +719,9 @@ static int sysc_init_module(struct sysc *ddata)
 	ddata->revision = sysc_read_revision(ddata);
 	pm_runtime_put_sync(ddata->dev);
 
+rev_quirks:
+	sysc_init_revision_quirks(ddata);
+
 	return 0;
 }
 
@@ -753,6 +849,127 @@ static struct sysc *sysc_child_to_parent(struct device *dev)
 	return dev_get_drvdata(parent);
 }
 
+static int __maybe_unused sysc_child_runtime_suspend(struct device *dev)
+{
+	struct sysc *ddata;
+	int error;
+
+	ddata = sysc_child_to_parent(dev);
+
+	error = pm_generic_runtime_suspend(dev);
+	if (error)
+		return error;
+
+	if (!ddata->enabled)
+		return 0;
+
+	return sysc_runtime_suspend(ddata->dev);
+}
+
+static int __maybe_unused sysc_child_runtime_resume(struct device *dev)
+{
+	struct sysc *ddata;
+	int error;
+
+	ddata = sysc_child_to_parent(dev);
+
+	if (!ddata->enabled) {
+		error = sysc_runtime_resume(ddata->dev);
+		if (error < 0)
+			dev_err(ddata->dev,
+				"%s error: %i\n", __func__, error);
+	}
+
+	return pm_generic_runtime_resume(dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sysc_child_suspend_noirq(struct device *dev)
+{
+	struct sysc *ddata;
+	int error;
+
+	ddata = sysc_child_to_parent(dev);
+
+	error = pm_generic_suspend_noirq(dev);
+	if (error)
+		return error;
+
+	if (!pm_runtime_status_suspended(dev)) {
+		error = pm_generic_runtime_suspend(dev);
+		if (error)
+			return error;
+
+		error = sysc_runtime_suspend(ddata->dev);
+		if (error)
+			return error;
+
+		ddata->child_needs_resume = true;
+	}
+
+	return 0;
+}
+
+static int sysc_child_resume_noirq(struct device *dev)
+{
+	struct sysc *ddata;
+	int error;
+
+	ddata = sysc_child_to_parent(dev);
+
+	if (ddata->child_needs_resume) {
+		ddata->child_needs_resume = false;
+
+		error = sysc_runtime_resume(ddata->dev);
+		if (error)
+			dev_err(ddata->dev,
+				"%s runtime resume error: %i\n",
+				__func__, error);
+
+		error = pm_generic_runtime_resume(dev);
+		if (error)
+			dev_err(ddata->dev,
+				"%s generic runtime resume: %i\n",
+				__func__, error);
+	}
+
+	return pm_generic_resume_noirq(dev);
+}
+#endif
+
+struct dev_pm_domain sysc_child_pm_domain = {
+	.ops = {
+		SET_RUNTIME_PM_OPS(sysc_child_runtime_suspend,
+				   sysc_child_runtime_resume,
+				   NULL)
+		USE_PLATFORM_PM_SLEEP_OPS
+		SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_child_suspend_noirq,
+					      sysc_child_resume_noirq)
+	}
+};
+
+/**
+ * sysc_legacy_idle_quirk - handle children in omap_device compatible way
+ * @ddata: device driver data
+ * @child: child device driver
+ *
+ * Allow idle for child devices as done with _od_runtime_suspend().
+ * Otherwise many child devices will not idle because of the permanent
+ * parent usecount set in pm_runtime_irq_safe().
+ *
+ * Note that the long term solution is to just modify the child device
+ * drivers to not set pm_runtime_irq_safe() and then this can be just
+ * dropped.
+ */
+static void sysc_legacy_idle_quirk(struct sysc *ddata, struct device *child)
+{
+	if (!ddata->legacy_mode)
+		return;
+
+	if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
+		dev_pm_domain_set(child, &sysc_child_pm_domain);
+}
+
 static int sysc_notifier_call(struct notifier_block *nb,
 			      unsigned long event, void *device)
 {
@@ -770,6 +987,7 @@ static int sysc_notifier_call(struct notifier_block *nb,
 		if (error && error != -EEXIST)
 			dev_warn(ddata->dev, "could not add %s fck: %i\n",
 				 dev_name(dev), error);
+		sysc_legacy_idle_quirk(ddata, dev);
 		break;
 	default:
 		break;
@@ -974,7 +1192,8 @@ static const struct sysc_capabilities sysc_34xx_sr = {
 	.type = TI_SYSC_OMAP34XX_SR,
 	.sysc_mask = SYSC_OMAP2_CLOCKACTIVITY,
 	.regbits = &sysc_regbits_omap34xx_sr,
-	.mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED,
+	.mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED |
+		      SYSC_QUIRK_LEGACY_IDLE,
 };
 
 /*
@@ -995,12 +1214,13 @@ static const struct sysc_capabilities sysc_36xx_sr = {
 	.type = TI_SYSC_OMAP36XX_SR,
 	.sysc_mask = SYSC_OMAP3_SR_ENAWAKEUP,
 	.regbits = &sysc_regbits_omap36xx_sr,
-	.mod_quirks = SYSC_QUIRK_UNCACHED,
+	.mod_quirks = SYSC_QUIRK_UNCACHED | SYSC_QUIRK_LEGACY_IDLE,
 };
 
 static const struct sysc_capabilities sysc_omap4_sr = {
 	.type = TI_SYSC_OMAP4_SR,
 	.regbits = &sysc_regbits_omap36xx_sr,
+	.mod_quirks = SYSC_QUIRK_LEGACY_IDLE,
 };
 
 /*
diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
--- a/include/linux/platform_data/ti-sysc.h
+++ b/include/linux/platform_data/ti-sysc.h
@@ -45,6 +45,7 @@ struct sysc_regbits {
 	s8 emufree_shift;
 };
 
+#define SYSC_QUIRK_LEGACY_IDLE		BIT(8)
 #define SYSC_QUIRK_RESET_STATUS		BIT(7)
 #define SYSC_QUIRK_NO_IDLE_ON_INIT	BIT(6)
 #define SYSC_QUIRK_NO_RESET_ON_INIT	BIT(5)
-- 
2.16.2

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

* Re: [PATCH 11/12] PM / AVS: SmartReflex: Prepare to use device tree based probing
  2018-02-23 21:00 ` [PATCH 11/12] PM / AVS: SmartReflex: Prepare to use device tree based probing Tony Lindgren
  2018-02-26 10:37   ` Rafael J. Wysocki
@ 2018-03-01  3:07   ` Kevin Hilman
  2018-03-01  3:49     ` Tony Lindgren
  1 sibling, 1 reply; 21+ messages in thread
From: Kevin Hilman @ 2018-03-01  3:07 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: linux-omap, Dave Gerlach, Nishanth Menon, Suman Anna,
	Tero Kristo, linux-kernel, linux-arm-kernel, linux-pm,
	Rafael J . Wysocki

Tony Lindgren <tony@atomide.com> writes:

> We are currently probing smartreflex with omap_device while we are
> already probing smartreflex related interconnect target module with
> ti-sysc driver and dts data.
>
> Before we can flip things on for ti-sysc, we need to prepare the
> smartreflex driver a bit:
>
> 1. The smartreflex clock is really for the whole interconnect target
>    module. So it may be configured at the parent device level with
>    ti-sysc
>
> 2. With ti-sysc, we have the child device manage interconnect target
>    module directly if pm_runtime_irq_safe() is set and there is only
>    one child. In that case nobody else is going to call pm_runtime_get
>    and put, so we need to add these calls to idle smartreflex properly
>    after probe if not fully configured
>
> 3. With ti-sysc, the parent driver may rebind. So we want to use
>    platform_driver_register() and don't want probe to be __init
>
> Note that this patch depends on the related changes to ti-sysc driver
> and omap_device probing to prevent both ti-sysc and omap_device to
> try to probe smartreflex.
>
> Cc: linux-pm@vger.kernel.org
> Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Signed-off-by: Tony Lindgren <tony@atomide.com>

Acked-by: Kevin Hilman <khilman@baylibre.com>

I don't have anything else queued for this driver, so feel free to take
it along with the rest of the series.

Kevin

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

* Re: [PATCH 11/12] PM / AVS: SmartReflex: Prepare to use device tree based probing
  2018-03-01  3:07   ` Kevin Hilman
@ 2018-03-01  3:49     ` Tony Lindgren
  0 siblings, 0 replies; 21+ messages in thread
From: Tony Lindgren @ 2018-03-01  3:49 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: linux-omap, Dave Gerlach, Nishanth Menon, Suman Anna,
	Tero Kristo, linux-kernel, linux-arm-kernel, linux-pm,
	Rafael J . Wysocki

* Kevin Hilman <khilman@baylibre.com> [180301 03:08]:
> Tony Lindgren <tony@atomide.com> writes:
> > We are currently probing smartreflex with omap_device while we are
> > already probing smartreflex related interconnect target module with
> > ti-sysc driver and dts data.
...

> Acked-by: Kevin Hilman <khilman@baylibre.com>
> 
> I don't have anything else queued for this driver, so feel free to take
> it along with the rest of the series.

Thanks for looking, will do.

Tony

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

end of thread, other threads:[~2018-03-01  3:49 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-23 21:00 [PATCH 00/12] Use dts data for ti-sysc to configure sysconfig Tony Lindgren
2018-02-23 21:00 ` [PATCH 01/12] bus: ti-sysc: Add fck clock alias for children with notifier_block Tony Lindgren
2018-02-23 21:00 ` [PATCH 02/12] bus: ti-sysc: Add suspend and resume handling Tony Lindgren
2018-02-23 21:00 ` [PATCH 03/12] bus: ti-sysc: Handle stdout-path for debug console Tony Lindgren
2018-02-23 21:00 ` [PATCH 04/12] bus: ti-sysc: Improve handling for no-reset-on-init and no-idle-on-init Tony Lindgren
2018-02-23 21:00 ` [PATCH 05/12] bus: ti-sysc: Remove unnecessary debugging statements Tony Lindgren
2018-02-23 21:00 ` [PATCH 06/12] bus: ti-sysc: Add support for platform data callbacks Tony Lindgren
2018-02-23 21:00 ` [PATCH 07/12] bus: ti-sysc: Handle some devices in omap_device compatible way Tony Lindgren
2018-03-01  0:37   ` Tony Lindgren
2018-02-23 21:00 ` [PATCH 08/12] ARM: OMAP2+: Add functions to allocate module data from device tree Tony Lindgren
2018-02-23 21:00 ` [PATCH 09/12] ARM: OMAP2+: Add checks for device tree based sysconfig data Tony Lindgren
2018-02-23 21:00 ` [PATCH 10/12] ARM: OMAP2+: Try to parse earlycon from parent too Tony Lindgren
2018-02-23 21:00 ` [PATCH 11/12] PM / AVS: SmartReflex: Prepare to use device tree based probing Tony Lindgren
2018-02-26 10:37   ` Rafael J. Wysocki
2018-02-26 21:34     ` Tony Lindgren
2018-03-01  3:07   ` Kevin Hilman
2018-03-01  3:49     ` Tony Lindgren
2018-02-23 21:01 ` [PATCH 12/12] ARM: OMAP2+: Enable ti-sysc to use device tree data for smartreflex Tony Lindgren
2018-02-23 21:41 ` [PATCH 0.5/12] ARM: OMAP2+: Prepare to pass auxdata " Tony Lindgren
2018-02-26  8:37   ` kbuild test robot
2018-02-26 22:23     ` Tony Lindgren

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).