diff mbox

[RFC,v2,1/2] mfd: syscon: Support early initialization

Message ID fa3178534fcf4488fc45a9a24e44b2588acb38c6.1392807832.git.michal.simek@xilinx.com (mailing list archive)
State New, archived
Headers show

Commit Message

Michal Simek Feb. 19, 2014, 11:04 a.m. UTC
Some platforms need to get system controller
ready as soon as possible.
The patch provides early_syscon_initialization
which create early mapping for all syscon compatible
devices in early_syscon_probe.
Regmap is get via syscon_early_regmap_lookup_by_phandle()

Regular device probes attach device to regmap
via regmap_attach_dev().

For early syscon initialization is necessary to extend
struct syscon and provide remove function
which unmap all early init structures.

Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---

Changes in v2:
- Fix bad logic in early_syscon_probe
- Fix compilation failure for x86_64 reported by zero day testing system
- Regmap change available here
  git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git tags/nodev

 drivers/mfd/syscon.c       | 128 +++++++++++++++++++++++++++++++++++++++------
 include/linux/mfd/syscon.h |  11 ++++
 2 files changed, 122 insertions(+), 17 deletions(-)

--
1.8.2.3

Comments

Alexander Shiyan Feb. 19, 2014, 11:14 a.m. UTC | #1
?????, 19 ??????? 2014, 12:04 +01:00 ?? Michal Simek <michal.simek@xilinx.com>:
> Some platforms need to get system controller
> ready as soon as possible.
> The patch provides early_syscon_initialization
> which create early mapping for all syscon compatible
> devices in early_syscon_probe.
> Regmap is get via syscon_early_regmap_lookup_by_phandle()
> 
> Regular device probes attach device to regmap
> via regmap_attach_dev().
> 
> For early syscon initialization is necessary to extend
> struct syscon and provide remove function
> which unmap all early init structures.
> 
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> ---
...

> +static struct of_device_id of_syscon_ids[] = {
> +	{ .compatible = "syscon" },
> +	{},
>  };

You should move syscon_ids out of #ifdef CONFIG_OF

---
Alexander Shiyan Feb. 19, 2014, 11:16 a.m. UTC | #2
?????, 19 ??????? 2014, 15:14 +04:00 ?? Alexander Shiyan <shc_work@mail.ru>:
> ?????, 19 ??????? 2014, 12:04 +01:00 ?? Michal Simek <michal.simek@xilinx.com>:
> > Some platforms need to get system controller
> > ready as soon as possible.
> > The patch provides early_syscon_initialization
> > which create early mapping for all syscon compatible
> > devices in early_syscon_probe.
> > Regmap is get via syscon_early_regmap_lookup_by_phandle()
> > 
> > Regular device probes attach device to regmap
> > via regmap_attach_dev().
> > 
> > For early syscon initialization is necessary to extend
> > struct syscon and provide remove function
> > which unmap all early init structures.
> > 
> > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > ---
> ...
> 
> > +static struct of_device_id of_syscon_ids[] = {
> > +	{ .compatible = "syscon" },
> > +	{},
> >  };
> 
> You should move syscon_ids out of #ifdef CONFIG_OF

Oh, confused, sorry for noise.

---
Lee Jones Feb. 19, 2014, 11:41 a.m. UTC | #3
FAO Arnd, Mark,

> Some platforms need to get system controller
> ready as soon as possible.
> The patch provides early_syscon_initialization
> which create early mapping for all syscon compatible
> devices in early_syscon_probe.
> Regmap is get via syscon_early_regmap_lookup_by_phandle()
> 
> Regular device probes attach device to regmap
> via regmap_attach_dev().
> 
> For early syscon initialization is necessary to extend
> struct syscon and provide remove function
> which unmap all early init structures.
> 
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> ---
> 
> Changes in v2:
> - Fix bad logic in early_syscon_probe
> - Fix compilation failure for x86_64 reported by zero day testing system
> - Regmap change available here
>   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git tags/nodev
> 
>  drivers/mfd/syscon.c       | 128 +++++++++++++++++++++++++++++++++++++++------
>  include/linux/mfd/syscon.h |  11 ++++
>  2 files changed, 122 insertions(+), 17 deletions(-)

I have the same reservations as last time:

  http://archive.arm.linux.org.uk/lurker/message/20140212.095424.96cb7281.html

I believe you were waiting for Arnd and/or Mark to comment.
Michal Simek Feb. 19, 2014, 11:44 a.m. UTC | #4
On 02/19/2014 12:41 PM, Lee Jones wrote:
> FAO Arnd, Mark,
> 
>> Some platforms need to get system controller
>> ready as soon as possible.
>> The patch provides early_syscon_initialization
>> which create early mapping for all syscon compatible
>> devices in early_syscon_probe.
>> Regmap is get via syscon_early_regmap_lookup_by_phandle()
>>
>> Regular device probes attach device to regmap
>> via regmap_attach_dev().
>>
>> For early syscon initialization is necessary to extend
>> struct syscon and provide remove function
>> which unmap all early init structures.
>>
>> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
>> ---
>>
>> Changes in v2:
>> - Fix bad logic in early_syscon_probe
>> - Fix compilation failure for x86_64 reported by zero day testing system
>> - Regmap change available here
>>   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git tags/nodev
>>
>>  drivers/mfd/syscon.c       | 128 +++++++++++++++++++++++++++++++++++++++------
>>  include/linux/mfd/syscon.h |  11 ++++
>>  2 files changed, 122 insertions(+), 17 deletions(-)
> 
> I have the same reservations as last time:
> 
>   http://archive.arm.linux.org.uk/lurker/message/20140212.095424.96cb7281.html
> 
> I believe you were waiting for Arnd and/or Mark to comment.

yes on Arnd because Mark already applied that regmap part.
But of course any input how to get this done will be helpful.

Thanks,
Michal
Mark Brown Feb. 19, 2014, 12:17 p.m. UTC | #5
On Wed, Feb 19, 2014 at 12:44:50PM +0100, Michal Simek wrote:
> On 02/19/2014 12:41 PM, Lee Jones wrote:

> > I believe you were waiting for Arnd and/or Mark to comment.

> yes on Arnd because Mark already applied that regmap part.
> But of course any input how to get this done will be helpful.

Like I said I've never seen the user you're adding for the regmap API so
I've no particular opinion on it.
Michal Simek Feb. 19, 2014, 1:51 p.m. UTC | #6
On 02/19/2014 01:17 PM, Mark Brown wrote:
> On Wed, Feb 19, 2014 at 12:44:50PM +0100, Michal Simek wrote:
>> On 02/19/2014 12:41 PM, Lee Jones wrote:
> 
>>> I believe you were waiting for Arnd and/or Mark to comment.
> 
>> yes on Arnd because Mark already applied that regmap part.
>> But of course any input how to get this done will be helpful.
> 
> Like I said I've never seen the user you're adding for the regmap API so
> I've no particular opinion on it.

2/2 is the code where I would like to use this when clk subsystem
start to use better io helper functions then just static inline
clk_readl/clk_writel.

Then my 2/2 driver will be just nicer than current implementation.

Regarding syscon changes. I think the right question is if this driver
should be still in drivers/mfd/ or should be moved to somewhere else
(drivers/base for example).

Thanks,
Michal
Mark Brown Feb. 19, 2014, 1:59 p.m. UTC | #7
On Wed, Feb 19, 2014 at 02:51:36PM +0100, Michal Simek wrote:
> On 02/19/2014 01:17 PM, Mark Brown wrote:

> > Like I said I've never seen the user you're adding for the regmap API so
> > I've no particular opinion on it.

> 2/2 is the code where I would like to use this when clk subsystem
> start to use better io helper functions then just static inline
> clk_readl/clk_writel.

> Then my 2/2 driver will be just nicer than current implementation.

OK, but I still haven't seen the code (or Lee's concerns for that
matter).
Tushar Behera May 9, 2014, 12:13 p.m. UTC | #8
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 02/19/2014 04:34 PM, Michal Simek wrote:
> Some platforms need to get system controller ready as soon as
> possible. The patch provides early_syscon_initialization which
> create early mapping for all syscon compatible devices in
> early_syscon_probe. Regmap is get via
> syscon_early_regmap_lookup_by_phandle()
> 
> Regular device probes attach device to regmap via
> regmap_attach_dev().
> 
> For early syscon initialization is necessary to extend struct
> syscon and provide remove function which unmap all early init
> structures.
> 
> Signed-off-by: Michal Simek <michal.simek@xilinx.com> ---
> 

I don't have V3 in my mailbox, hence replying to this thread. The
content is applicable to V3.

[...]
> @@ -95,6 +98,24 @@ struct regmap
> *syscon_regmap_lookup_by_pdevname(const char *s) } 
> EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname);
> 
> +struct regmap *syscon_early_regmap_lookup_by_phandle(struct
> device_node *np, +						     const char *property) +{ +	struct
> device_node *syscon_np; +	struct syscon *syscon; + +	syscon_np =
> of_parse_phandle(np, property, 0); +	if (!syscon_np) +		return
> ERR_PTR(-ENODEV); + +	syscon = syscon_np->data; + +
> of_node_put(syscon_np); + +	return syscon->regmap;

This fails while derefencing syscon if if early_syscon_init() has not
yet been not yet been called. Something like this would be helpful.

struct regmap *regmap = ERR_PTR(-ENODEV);

syscon = syscon_np->data;
if (syscon)
	regmap = syscon->regmap;

return regmap;


- -- 
Tushar Behera
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQEcBAEBAgAGBQJTbMZMAAoJELqclMPPkq4NoZEH/j/vTBLu0VmKm01jZqJUUC59
siD+DvRclRcdRGCzsf7iN9Zjw2g+abDtEBynBNdC6swTJJUwDyMtkcguiHn/ytPN
B/5bli3rKpRkDlg9i/Cfgqd2KmYh1U6Q2LJ3+pyRAQqe0zm+bI5+fp/cn1PGLBIW
1R2rexJO98GhGO/Yhh62FD366rB15bgApC2+XjYb2Wcka3f8VY47gqkxnAwxZzvU
ovG/rqXEuGW7H3o/+BLDtmQREEjKg20ggRo2FEj0WozhTo6Sn2YUJg70DKioguu0
eteP+X4DsShluJfxq9/51bfFutlXPPYZIbLIZxwyiFSJiAIR8hjLO/Ed/GicybQ=
=HCI5
-----END PGP SIGNATURE-----
diff mbox

Patch

diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index 71841f9..8e6c611 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -20,12 +20,15 @@ 
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <linux/slab.h>
 #include <linux/mfd/syscon.h>

 static struct platform_driver syscon_driver;

 struct syscon {
+	void __iomem *base;
 	struct regmap *regmap;
+	struct resource res;
 };

 static int syscon_match_node(struct device *dev, void *data)
@@ -95,6 +98,24 @@  struct regmap *syscon_regmap_lookup_by_pdevname(const char *s)
 }
 EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname);

+struct regmap *syscon_early_regmap_lookup_by_phandle(struct device_node *np,
+						     const char *property)
+{
+	struct device_node *syscon_np;
+	struct syscon *syscon;
+
+	syscon_np = of_parse_phandle(np, property, 0);
+	if (!syscon_np)
+		return ERR_PTR(-ENODEV);
+
+	syscon = syscon_np->data;
+
+	of_node_put(syscon_np);
+
+	return syscon->regmap;
+}
+EXPORT_SYMBOL_GPL(syscon_early_regmap_lookup_by_phandle);
+
 struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
 					const char *property)
 {
@@ -128,40 +149,112 @@  static int syscon_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct syscon *syscon;
 	struct resource *res;
-	void __iomem *base;

-	syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL);
+	/* Early syscon init */
+	if (pdev->dev.of_node && pdev->dev.of_node->data) {
+		syscon = pdev->dev.of_node->data;
+		res = &syscon->res;
+		regmap_attach_dev(dev, syscon->regmap, &syscon_regmap_config);
+	} else {
+
+		syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL);
+		if (!syscon)
+			return -ENOMEM;
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!res)
+			return -ENOENT;
+
+		syscon->base = devm_ioremap(dev, res->start,
+					    resource_size(res));
+		if (!syscon->base)
+			return -ENOMEM;
+
+		syscon_regmap_config.max_register = res->end - res->start - 3;
+		syscon->regmap = devm_regmap_init_mmio(dev, syscon->base,
+						&syscon_regmap_config);
+		if (IS_ERR(syscon->regmap)) {
+			dev_err(dev, "regmap init failed\n");
+			return PTR_ERR(syscon->regmap);
+		}
+	}
+
+	platform_set_drvdata(pdev, syscon);
+
+	dev_info(dev, "regmap %pR registered\n", res);
+
+	return 0;
+}
+
+static const struct platform_device_id syscon_ids[] = {
+	{ "syscon", },
+	{ }
+};
+
+static int syscon_remove(struct platform_device *pdev)
+{
+	struct syscon *syscon = platform_get_drvdata(pdev);
+
+	if (pdev->dev.of_node && pdev->dev.of_node->data) {
+		iounmap(syscon->base);
+		kfree(syscon);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int early_syscon_probe(struct device_node *np)
+{
+	struct syscon *syscon;
+
+	syscon = kzalloc(sizeof(*syscon), GFP_KERNEL);
 	if (!syscon)
 		return -ENOMEM;

-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENOENT;
+	if (of_address_to_resource(np, 0, &syscon->res))
+		return -EINVAL;

-	base = devm_ioremap(dev, res->start, resource_size(res));
-	if (!base)
-		return -ENOMEM;
+	syscon->base = ioremap(syscon->res.start, resource_size(&syscon->res));
+	if (!syscon->base) {
+		pr_err("%s: Unable to map I/O memory\n", __func__);
+		return PTR_ERR(syscon->base);
+	}

-	syscon_regmap_config.max_register = res->end - res->start - 3;
-	syscon->regmap = devm_regmap_init_mmio(dev, base,
-					&syscon_regmap_config);
+	syscon_regmap_config.max_register = syscon->res.end -
+					    syscon->res.start - 3;
+	syscon->regmap = regmap_init_mmio(NULL, syscon->base,
+					  &syscon_regmap_config);
 	if (IS_ERR(syscon->regmap)) {
-		dev_err(dev, "regmap init failed\n");
+		pr_err("regmap init failed\n");
 		return PTR_ERR(syscon->regmap);
 	}

-	platform_set_drvdata(pdev, syscon);
+	np->data = syscon;

-	dev_info(dev, "regmap %pR registered\n", res);
+	of_node_put(np);
+
+	pr_info("%s: regmap %pR registered\n", np->full_name, &syscon->res);

 	return 0;
 }

-static const struct platform_device_id syscon_ids[] = {
-	{ "syscon", },
-	{ }
+static struct of_device_id of_syscon_ids[] = {
+	{ .compatible = "syscon" },
+	{},
 };

+void __init early_syscon_init(void)
+{
+	struct device_node *np;
+
+	for_each_matching_node_and_match(np, of_syscon_ids, NULL) {
+		if (early_syscon_probe(np))
+			BUG();
+	}
+}
+#endif
+
 static struct platform_driver syscon_driver = {
 	.driver = {
 		.name = "syscon",
@@ -169,6 +262,7 @@  static struct platform_driver syscon_driver = {
 		.of_match_table = of_syscon_match,
 	},
 	.probe		= syscon_probe,
+	.remove		= syscon_remove,
 	.id_table	= syscon_ids,
 };

diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h
index 8789fa3..465c092 100644
--- a/include/linux/mfd/syscon.h
+++ b/include/linux/mfd/syscon.h
@@ -24,6 +24,10 @@  extern struct regmap *syscon_regmap_lookup_by_pdevname(const char *s);
 extern struct regmap *syscon_regmap_lookup_by_phandle(
 					struct device_node *np,
 					const char *property);
+extern struct regmap *syscon_early_regmap_lookup_by_phandle(
+					struct device_node *np,
+					const char *property);
+extern void early_syscon_init(void);
 #else
 static inline struct regmap *syscon_node_to_regmap(struct device_node *np)
 {
@@ -46,6 +50,13 @@  static inline struct regmap *syscon_regmap_lookup_by_phandle(
 {
 	return ERR_PTR(-ENOSYS);
 }
+
+static struct regmap *syscon_early_regmap_lookup_by_phandle(
+					struct device_node *np,
+					const char *property)
+{
+	return ERR_PTR(-ENOSYS);
+}
 #endif

 #endif /* __LINUX_MFD_SYSCON_H__ */