diff mbox series

[v2,4.4.y-cip,03/11] soc: renesas: Identify SoC and register with the SoC bus

Message ID 20201201083938.32688-4-prabhakar.mahadev-lad.rj@bp.renesas.com (mailing list archive)
State Accepted
Delegated to: Nobuhiro Iwamatsu
Headers show
Series Renesas RZ/G1x add SoC detection support | expand

Commit Message

Lad Prabhakar Dec. 1, 2020, 8:39 a.m. UTC
From: Geert Uytterhoeven <geert+renesas@glider.be>

commit 8d6799a9ba23acd675f3243580ee6f1756fb4381 upstream.

Identify the SoC type and revision, and register this information with
the SoC bus, so it is available under /sys/devices/soc0/, and can be
checked where needed using soc_device_match().

Identification is done using the Product Register or Common Chip Code
Register, as declared in DT (PRR only for now), or using a hardcoded
fallback if missing.

Example:

    Detected Renesas R-Car Gen2 r8a7791 ES1.0
    ...
    # cat /sys/devices/soc0/{machine,family,soc_id,revision}
    Koelsch
    R-Car Gen2
    r8a7791
    ES1.0

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
[PL: Dropped references to other platforms apart from RZ/G1{ME},
dropped SOC_BUS config option from arm64, enabled SOC_BUS config
option for ARCH_R8A7743 and ARCH_R8A7745]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
 arch/arm/mach-shmobile/Kconfig    |   2 +
 drivers/soc/renesas/Makefile      |   2 +
 drivers/soc/renesas/renesas-soc.c | 123 ++++++++++++++++++++++++++++++
 3 files changed, 127 insertions(+)
 create mode 100644 drivers/soc/renesas/renesas-soc.c

Comments

Pavel Machek Dec. 1, 2020, 9:21 a.m. UTC | #1
Hi!

> From: Geert Uytterhoeven <geert+renesas@glider.be>
> 
> commit 8d6799a9ba23acd675f3243580ee6f1756fb4381 upstream.
> 
> Identify the SoC type and revision, and register this information with
> the SoC bus, so it is available under /sys/devices/soc0/, and can be
> checked where needed using soc_device_match().
> 
> Identification is done using the Product Register or Common Chip Code
> Register, as declared in DT (PRR only for now), or using a hardcoded
> fallback if missing.

Just a minor nitpicks; no need to fix them for merge but maybe
consideration for mainline?

> +	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
> +	if (!soc_dev_attr)
> +		return -ENOMEM;
> +
> +	np = of_find_node_by_path("/");
> +	of_property_read_string(np, "model", &soc_dev_attr->machine);
> +	of_node_put(np);
> +
> +	soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL);
> +	soc_dev_attr->soc_id = kstrdup_const(strchr(match->compatible, ',') + 1,
> +					     GFP_KERNEL);
> +	if (chipid)
> +		soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u",
> +						   ((product >> 4) & 0x0f) + 1,
> +						   product & 0xf);

If memory allocations fail here, would it be better to fail the probe?

Would it be better to return error if !strchr(match->compatible, ',')
instead of trying to kstrdup_const((void *) 1) and oopsing?

> +	pr_info("Detected Renesas %s %s %s\n", soc_dev_attr->family,
> +		soc_dev_attr->soc_id, soc_dev_attr->revision ?: "");

Revision is NULL is handled here, but family may well be NULL, too, if
allocation failed. It is not going to cause problems here, but...

Best regards,
								Pavel
diff mbox series

Patch

diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index a51df53f0914..3f1e27b76d59 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -72,6 +72,7 @@  config ARCH_R8A7742
 config ARCH_R8A7743
 	bool "RZ/G1M (R8A77430)"
 	select ARCH_RCAR_GEN2
+	select SOC_BUS
 
 config ARCH_R8A7744
 	bool "RZ/G1N (R8A77440)"
@@ -81,6 +82,7 @@  config ARCH_R8A7744
 config ARCH_R8A7745
 	bool "RZ/G1E (R8A77450)"
 	select ARCH_RCAR_GEN2
+	select SOC_BUS
 
 config ARCH_R8A77470
 	bool "RZ/G1C (R8A77470)"
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index 87517569af13..77e8f953f4c8 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -1 +1,3 @@ 
 obj-$(CONFIG_ARCH_RCAR_GEN2)	+= rcar-rst.o
+
+obj-$(CONFIG_SOC_BUS)		+= renesas-soc.o
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
new file mode 100644
index 000000000000..e36b51a52dfc
--- /dev/null
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -0,0 +1,123 @@ 
+/*
+ * Renesas SoC Identification
+ *
+ * Copyright (C) 2014-2016 Glider bvba
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sys_soc.h>
+
+struct renesas_family {
+	const char name[16];
+	u32 reg;			/* CCCR or PRR, if not in DT */
+};
+
+static const struct renesas_family fam_rzg __initconst __maybe_unused = {
+	.name	= "RZ/G",
+	.reg	= 0xff000044,		/* PRR (Product Register) */
+};
+
+struct renesas_soc {
+	const struct renesas_family *family;
+	u8 id;
+};
+
+static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = {
+	.family	= &fam_rzg,
+	.id	= 0x47,
+};
+
+static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = {
+	.family	= &fam_rzg,
+	.id	= 0x4c,
+};
+
+static const struct of_device_id renesas_socs[] __initconst = {
+#ifdef CONFIG_ARCH_R8A7743
+	{ .compatible = "renesas,r8a7743",	.data = &soc_rz_g1m },
+#endif
+#ifdef CONFIG_ARCH_R8A7745
+	{ .compatible = "renesas,r8a7745",	.data = &soc_rz_g1e },
+#endif
+	{ /* sentinel */ }
+};
+
+static int __init renesas_soc_init(void)
+{
+	struct soc_device_attribute *soc_dev_attr;
+	const struct renesas_family *family;
+	const struct of_device_id *match;
+	const struct renesas_soc *soc;
+	void __iomem *chipid = NULL;
+	struct soc_device *soc_dev;
+	struct device_node *np;
+	unsigned int product;
+
+	match = of_match_node(renesas_socs, of_root);
+	if (!match)
+		return -ENODEV;
+
+	soc = match->data;
+	family = soc->family;
+
+	/* Try PRR first, then hardcoded fallback */
+	np = of_find_compatible_node(NULL, NULL, "renesas,prr");
+	if (np) {
+		chipid = of_iomap(np, 0);
+		of_node_put(np);
+	} else if (soc->id) {
+		chipid = ioremap(family->reg, 4);
+	}
+	if (chipid) {
+		product = readl(chipid);
+		iounmap(chipid);
+		if (soc->id && ((product >> 8) & 0xff) != soc->id) {
+			pr_warn("SoC mismatch (product = 0x%x)\n", product);
+			return -ENODEV;
+		}
+	}
+
+	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+	if (!soc_dev_attr)
+		return -ENOMEM;
+
+	np = of_find_node_by_path("/");
+	of_property_read_string(np, "model", &soc_dev_attr->machine);
+	of_node_put(np);
+
+	soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL);
+	soc_dev_attr->soc_id = kstrdup_const(strchr(match->compatible, ',') + 1,
+					     GFP_KERNEL);
+	if (chipid)
+		soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u",
+						   ((product >> 4) & 0x0f) + 1,
+						   product & 0xf);
+
+	pr_info("Detected Renesas %s %s %s\n", soc_dev_attr->family,
+		soc_dev_attr->soc_id, soc_dev_attr->revision ?: "");
+
+	soc_dev = soc_device_register(soc_dev_attr);
+	if (IS_ERR(soc_dev)) {
+		kfree(soc_dev_attr->revision);
+		kfree_const(soc_dev_attr->soc_id);
+		kfree_const(soc_dev_attr->family);
+		kfree(soc_dev_attr);
+		return PTR_ERR(soc_dev);
+	}
+
+	return 0;
+}
+core_initcall(renesas_soc_init);