From: Geert Uytterhoeven 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 Signed-off-by: Simon Horman [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 --- 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 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 +#include +#include +#include +#include +#include + +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); -- 2.17.1