Skip to contentSkip to conversation

Syscon early initialization

RFC PATCH Applied Michal Simek 4 participants 8 messages Feb 10, 2014 – Feb 16, 2014

Subsystems (9)

v1 of 3 Applied Latest is v3 →

lore
Share & tools
lore
#0 lore raw

cover Syscon early initialization

Hi,

this series come from my discussion with Arnd at KS and then on some other threads/IRCs(Arnd and Mark) that SoC vendors are more and more try to add misc functionality to
one memory region. For this purpose syscon driver is in the kernel. But regular syscon driver is initialized too late
and platforms are trying to create specific code to handle it.

For this purpose the series have been created to provide early syscon initialization and regmap creation first and then attaching device.

The last patch is zynq specific patch to clear slcr driver and clock driver can profit from it too when clk regmap is ready.

Also moving syscon driver from mfs should be consider.

Thanks for your comments,
Michal

Michal Simek (3):
regmap: Separate regmap dev initialization
mfd: syscon: Support early initialization
ARM: zynq: Use early syscon initialization

 arch/arm/boot/dts/zynq-7000.dtsi |   1 +
 arch/arm/mach-zynq/common.c      |   6 +-
 arch/arm/mach-zynq/slcr.c        |  42 +------------
 drivers/base/regmap/regmap.c     |  41 +++++++++----
 drivers/clk/zynq/clkc.c          |  57 ++++++------------
 drivers/mfd/syscon.c             | 126 +++++++++++++++++++++++++++++++++------
 include/linux/mfd/syscon.h       |  11 ++++
 include/linux/regmap.h           |   2 +
 8 files changed, 173 insertions(+), 113 deletions(-)

--
1.8.2.3

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140210/69ed2e02/attachment.sig>

#1 lore raw

RFC PATCH 1/3 regmap: Separate regmap dev initialization

Create special function regmap_attach_dev which can be called separately out of regmap_init.

---

 drivers/base/regmap/regmap.c | 41 ++++++++++++++++++++++++++++-------------
 include/linux/regmap.h       |  2 ++
 2 files changed, 30 insertions(+), 13 deletions(-)
drivers/base/regmap/regmap.c +28 -13
index b897c1a..c766f5f 100644
@@ -380,6 +380,28 @@ static void regmap_range_exit(struct regmap *map)
 	kfree(map->selector_work_buf);
 }
 
+int regmap_attach_dev(struct device *dev, struct regmap *map,
+		      const struct regmap_config *config)
+{
+	struct regmap **m;
+
+	map->dev = dev;
+
+	regmap_debugfs_init(map, config->name);
+
+	/* Add a devres resource for dev_get_regmap() */
+	m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
+	if (!m) {
+		regmap_debugfs_exit(map);
+		return -ENOMEM;
+	}
+	*m = map;
+	devres_add(dev, m);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(regmap_attach_dev);
+
 /**
  * regmap_init(): Initialise register map
  *
@@ -397,7 +419,7 @@ struct regmap *regmap_init(struct device *dev,
 			   void *bus_context,
 			   const struct regmap_config *config)
 {
-	struct regmap *map, **m;
+	struct regmap *map;
 	int ret = -EINVAL;
 	enum regmap_endian reg_endian, val_endian;
 	int i, j;
@@ -734,25 +756,18 @@ skip_format_initialization:
 		}
 	}
 
-	regmap_debugfs_init(map, config->name);
-
 	ret = regcache_init(map, config);
 	if (ret != 0)
 		goto err_range;
 
-	/* Add a devres resource for dev_get_regmap() */
-	m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
-	if (!m) {
-		ret = -ENOMEM;
-		goto err_debugfs;
-	}
-	*m = map;
-	devres_add(dev, m);
+	if (dev)
+		ret = regmap_attach_dev(dev, map, config);
+		if (ret != 0)
+			goto err_regcache;
 
 	return map;
 
-err_debugfs:
-	regmap_debugfs_exit(map);
+err_regcache:
 	regcache_exit(map);
 err_range:
 	regmap_range_exit(map);
include/linux/regmap.h +2 -0
index 4149f1a..fa4d079 100644
@@ -317,6 +317,8 @@ struct regmap *regmap_init(struct device *dev,
 			   const struct regmap_bus *bus,
 			   void *bus_context,
 			   const struct regmap_config *config);
+int regmap_attach_dev(struct device *dev, struct regmap *map,
+				 const struct regmap_config *config);
 struct regmap *regmap_init_i2c(struct i2c_client *i2c,
 			       const struct regmap_config *config);
 struct regmap *regmap_init_spi(struct spi_device *dev,

--
1.8.2.3

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140210/2f6b4e20/attachment.sig>

maintainer Applied
#2 lore raw

Re: [RFC PATCH 1/3] regmap: Separate regmap dev initialization

Quoted 2 lines · Michal Simek

Create special function regmap_attach_dev which can be called separately out of regmap_init.

Applied, thanks. I've pushed a signed tag too so dependencies can pull this in:

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git tags/nodev

When sending things like this that add new functionality it's often
helpful to send the patches adding users to review along with the core
patch since this helps to review if the usage is actually sane and
sensible. From a purely regmap point of view this seems OK but...
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140216/0d9e2231/attachment.sig>

#3 lore raw

RFC PATCH 2/3 mfd: syscon: Support early initialization

In reply to Michal Simek

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.

---

 drivers/mfd/syscon.c       | 126 +++++++++++++++++++++++++++++++++++++++------
 include/linux/mfd/syscon.h |  11 ++++
 2 files changed, 120 insertions(+), 17 deletions(-)
drivers/mfd/syscon.c +109 -17
index 71841f9..5935f02 100644
@@ -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,110 @@ 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;
+}
+
+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();
+	}
+}
+
 static struct platform_driver syscon_driver = {
 	.driver = {
 		.name = "syscon",
@@ -169,6 +260,7 @@ static struct platform_driver syscon_driver = {
 		.of_match_table = of_syscon_match,
 	},
 	.probe		= syscon_probe,
+	.remove		= syscon_remove,
 	.id_table	= syscon_ids,
 };
 
include/linux/mfd/syscon.h +11 -0
index 8789fa3..465c092 100644
@@ -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__ */

--
1.8.2.3

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140210/b29e2420/attachment-0001.sig>

#4 lore raw

Re: [RFC PATCH 2/3] mfd: syscon: Support early initialization

Quoted 177 lines · Michal Simek

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.

---

 drivers/mfd/syscon.c       | 126 +++++++++++++++++++++++++++++++++++++++------
 include/linux/mfd/syscon.h |  11 ++++
 2 files changed, 120 insertions(+), 17 deletions(-)
drivers/mfd/syscon.c +96 -17
index 71841f9..5935f02 100644
@@ -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,110 @@ 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;
+}
+
+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[] = {

drivers/mfd/syscon.c static int syscon_probe(struct platform_device *pdev) · line 251

Quoted 10 lines
drivers/mfd/syscon.c +8 -0
+	{ .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))

just
if (early_syscon_probe(np))

	BUG();

here.

Thanks,
Michal

Signature · 14 lines
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 263 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140210/2a67d56a/attachment-0001.sig>
#5 lore raw

Re: [RFC PATCH 2/3] mfd: syscon: Support early initialization

In reply to Michal Simek
Quoted 22 lines · Michal Simek

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.

---

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

<snip>

Quoted 5 lines

struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,

drivers/mfd/syscon.c +0 -0
 					const char *property)
 {
@@ -128,40 +149,110 @@ static int syscon_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;

drivers/mfd/syscon.c static int syscon_probe(struct platform_device *pdev) · line 157

Quoted 10 lines
drivers/mfd/syscon.c +5 -2
 	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);

Instead of duplicating all of the init code with early and late versions of each, is there any reason why we can't always do the early stuff early and then connect it to the dev infrastructure when it becomes available?

Quoted 152 lines
drivers/mfd/syscon.c +82 -15
+	} 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;
+}
+
+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();
+	}
+}
+
 static struct platform_driver syscon_driver = {
 	.driver = {
 		.name = "syscon",
@@ -169,6 +260,7 @@ static struct platform_driver syscon_driver = {
 		.of_match_table = of_syscon_match,
 	},
 	.probe		= syscon_probe,
+	.remove		= syscon_remove,
 	.id_table	= syscon_ids,
 };
 
include/linux/mfd/syscon.h +11 -0
index 8789fa3..465c092 100644
@@ -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__ */
Signature · 4 lines
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
#6 lore raw

Re: [RFC PATCH 2/3] mfd: syscon: Support early initialization

Quoted 36 lines · Lee Jones
Quoted 22 lines · Michal Simek

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.

---

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

<snip>

Quoted 9 lines

struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,

drivers/mfd/syscon.c +0 -1
 					const char *property)
 {
@@ -128,40 +149,110 @@ static int syscon_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct syscon *syscon;
 	struct resource *res;
-	void __iomem *base;
 
Quoted 11 lines

drivers/mfd/syscon.c static int syscon_probe(struct platform_device *pdev) · line 157

Quoted 6 lines
drivers/mfd/syscon.c +5 -1
-	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);

Instead of duplicating all of the init code with early and late versions of each, is there any reason why we can't always do the early stuff early and then connect it to the dev infrastructure when it becomes available?

I am waiting for Arnd and Mark opinions regarding this. That's why it was just RFC.
There the next question is if this should still stay in mfd or moved to base.

I wanted to keep this to be driver compatible
that's why I have done it in this way.

We will see.

Thanks,
Michal

Signature · 14 lines
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 263 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140212/3f71a6b5/attachment.sig>
#7 lore raw

RFC PATCH 3/3 ARM: zynq: Use early syscon initialization

In reply to Michal Simek

Use early syscon initialization to simplify slcr code.
- Remove two slcr inits (zynq_slcr_init, zynq_early_slcr_init)
- Directly use regmap accesses in zynq_slcr_read/write
- Remove zynq_clock_init() and use addresses from syscon (This is the most problematic part now because clock doesn't support regmap accesses that's why reading slcr base is ugly. There are some attempts to get clk regmap to work - for example:
https://lkml.org/lkml/2013/10/16/112)

---

Especially look at slcr.c which is much simpler than was before. clkc.c will be simpler when regmap support is added because then syscon_early_regmap_lookup_by_phandle() will be called without zynq_slcr_base search.

---
 arch/arm/boot/dts/zynq-7000.dtsi |  1 +
 arch/arm/mach-zynq/common.c      |  6 ++---
 arch/arm/mach-zynq/slcr.c        | 42 ++---------------------------
 drivers/clk/zynq/clkc.c          | 57 ++++++++++++----------------------------
 4 files changed, 23 insertions(+), 83 deletions(-)
arch/arm/boot/dts/zynq-7000.dtsi +1 -0
index 7284499..e414489 100644
@@ -135,6 +135,7 @@
 			compatible = "xlnx,zynq-slcr", "syscon";
 			reg = <0xF8000000 0x1000>;
 			ranges;
+			syscon = <&slcr>;
 			clkc: clkc at 100 {
 				#clock-cells = <1>;
 				compatible = "xlnx,ps7-clkc";
arch/arm/mach-zynq/common.c +3 -3
index 9d3c88e..78589e3 100644
@@ -28,6 +28,7 @@
 #include <linux/of.h>
 #include <linux/irqchip.h>
 #include <linux/irqchip/arm-gic.h>
+#include <linux/mfd/syscon.h>
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
 
@@ -130,15 +131,14 @@ out:
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
 
 	platform_device_register(&zynq_cpuidle_device);
-
-	zynq_slcr_init();
 }
 
 static void __init zynq_timer_init(void)
 {
+	early_syscon_init();
+
 	zynq_early_slcr_init();
 
-	zynq_clock_init();
 	of_clk_init(NULL);
 	clocksource_of_init();
 }
arch/arm/mach-zynq/slcr.c +2 -40

76 lines not on this page · raw message

drivers/clk/zynq/clkc.c +17 -40

72 lines not on this page · raw message

--
1.8.2.3

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140210/2103137c/attachment.sig>